BIP: 1
Title: BIP Purpose and Guidelines
Authors: Amir Taaki
Status: Closed
Type: Process
Assigned: 2011-09-19
Proposed-Replacement: 2
==What is a BIP?==
BIP stands for Bitcoin Improvement Proposal. A BIP is a design document providing information to the Bitcoin community, or describing a new feature for Bitcoin or its processes or environment. The BIP should provide a concise technical specification of the feature and a rationale for the feature.
We intend BIPs to be the primary mechanisms for proposing new features, for collecting community input on an issue, and for documenting the design decisions that have gone into Bitcoin. The BIP author is responsible for building consensus within the community and documenting dissenting opinions.
Because the BIPs are maintained as text files in a versioned repository, their revision history is the historical record of the feature proposal.
==BIP Types==
There are three kinds of BIP:
* A Standards Track BIP describes any change that affects most or all Bitcoin implementations, such as a change to the network protocol, a change in block or transaction validity rules, or any change or addition that affects the interoperability of applications using Bitcoin.
* An Informational BIP describes a Bitcoin design issue, or provides general guidelines or information to the Bitcoin community, but does not propose a new feature. Informational BIPs do not necessarily represent a Bitcoin community consensus or recommendation, so users and implementers are free to ignore Informational BIPs or follow their advice.
* A Process BIP describes a process surrounding Bitcoin, or proposes a change to (or an event in) a process. Process BIPs are like Standards Track BIPs but apply to areas other than the Bitcoin protocol itself. They may propose an implementation, but not to Bitcoin's codebase; they often require community consensus; unlike Informational BIPs, they are more than recommendations, and users are typically not free to ignore them. Examples include procedures, guidelines, changes to the decision-making process, and changes to the tools or environment used in Bitcoin development. Any meta-BIP is also considered a Process BIP.
==BIP Work Flow==
The BIP process begins with a new idea for Bitcoin. Each potential BIP must have a champion -- someone who writes the BIP using the style and format described below, shepherds the discussions in the appropriate forums, and attempts to build community consensus around the idea. The BIP champion (a.k.a. Author) should first attempt to ascertain whether the idea is BIP-able. Posting to the [https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev bitcoin-dev@lists.linuxfoundation.org] mailing list (and maybe the [https://bitcointalk.org/index.php?board=6.0 Development & Technical Discussion] forum) is the best way to go about this.
Vetting an idea publicly before going as far as writing a BIP is meant to save both the potential author and the wider community time. Many ideas have been brought forward for changing Bitcoin that have been rejected for various reasons. Asking the Bitcoin community first if an idea is original helps prevent too much time being spent on something that is guaranteed to be rejected based on prior discussions (searching the internet does not always do the trick). It also helps to make sure the idea is applicable to the entire community and not just the author. Just because an idea sounds good to the author does not mean it will work for most people in most areas where Bitcoin is used. Small enhancements or patches often don't need standardisation between multiple projects; these don't need a BIP and should be injected into the relevant Bitcoin development work flow with a patch submission to the applicable Bitcoin issue tracker.
Once the champion has asked the Bitcoin community as to whether an idea has any chance of acceptance, a draft BIP should be presented to the [https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev bitcoin-dev] mailing list. This gives the author a chance to flesh out the draft BIP to make it properly formatted, of high quality, and to address additional concerns about the proposal. Following a discussion, the proposal should be sent to the bitcoin-dev list and the BIP editor with the draft BIP. This draft must be written in BIP style as described below, else it will be sent back without further regard until proper formatting rules are followed.
BIP authors are responsible for collecting community feedback on both the initial idea and the BIP before submitting it for review. However, wherever possible, long open-ended discussions on public mailing lists should be avoided. Strategies to keep the discussions efficient include: setting up a separate SIG mailing list for the topic, having the BIP author accept private comments in the early design phases, setting up a wiki page or git repository, etc. BIP authors should use their discretion here.
It is highly recommended that a single BIP contain a single key proposal or new idea. The more focused the BIP, the more successful it tends to be. If in doubt, split your BIP into several well-focused ones.
The BIP editors assign BIP numbers and change their status. Please send all BIP-related email to the BIP editor, which is listed under [[#BIP_Editors|BIP Editors]] below. Also see [[#BIP_Editor_Responsibilities__Workflow|BIP Editor Responsibilities & Workflow]]. The BIP editor reserves the right to reject BIP proposals if they appear too unfocused or too broad.
Authors MUST NOT self assign BIP numbers, but should use an alias such as "bip-johndoe-infinitebitcoins" which includes the author's name/nick and the BIP subject.
If the BIP editor approves, he will assign the BIP a number, label it as Standards Track, Informational, or Process, give it status "Draft", and add it to the BIPs git repository. The BIP editor will not unreasonably deny a BIP. Reasons for denying BIP status include duplication of effort, disregard for formatting rules, being too unfocused or too broad, being technically unsound, not providing proper motivation or addressing backwards compatibility, or not in keeping with the Bitcoin philosophy. For a BIP to be accepted it must meet certain minimum criteria. It must be a clear and complete description of the proposed enhancement. The enhancement must represent a net improvement. The proposed implementation, if applicable, must be solid and must not complicate the protocol unduly.
The BIP author may update the Draft as necessary in the git repository. Updates to drafts may also be submitted by the author as pull requests.
Standards Track BIPs consist of two parts, a design document and a reference implementation. The BIP should be reviewed and accepted before a reference implementation is begun, unless a reference implementation will aid people in studying the BIP. Standards Track BIPs must include an implementation -- in the form of code, a patch, or a URL to same -- before it can be considered Final.
Once a BIP has been accepted, the reference implementation must be completed. When the reference implementation is complete and accepted by the community, the status will be changed to "Final".
A BIP can also be assigned status "Deferred". The BIP author or editor can assign the BIP this status when no progress is being made on the BIP. Once a BIP is deferred, the BIP editor can re-assign it to draft status.
A BIP can also be "Rejected". Perhaps after all is said and done it was not a good idea. It is still important to have a record of this fact.
BIPs can also be superseded by a different BIP, rendering the original obsolete. This is intended for Informational BIPs, where version 2 of an API can replace version 1.
The possible paths of the status of BIPs are as follows:
Some Informational and Process BIPs may also have a status of "Active" if they are never meant to be completed. E.g. BIP 1 (this BIP).
==What belongs in a successful BIP?==
Each BIP should have the following parts:
* Preamble -- RFC 822 style headers containing meta-data about the BIP, including the BIP number, a short descriptive title (limited to a maximum of 44 characters), the names, and optionally the contact info for each author, etc.
* Abstract -- a short (~200 word) description of the technical issue being addressed.
* Copyright/public domain -- Each BIP must either be explicitly labelled as placed in the public domain (see this BIP as an example) or licensed under the Open Publication License.
* Specification -- The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Bitcoin platforms (Satoshi, BitcoinJ, bitcoin-js, libbitcoin).
* Motivation -- The motivation is critical for BIPs that want to change the Bitcoin protocol. It should clearly explain why the existing protocol specification is inadequate to address the problem that the BIP solves. BIP submissions without sufficient motivation may be rejected outright.
* Rationale -- The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages.
* The rationale should provide evidence of consensus within the community and discuss important objections or concerns raised during discussion.
* Backwards Compatibility -- All BIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The BIP must explain how the author proposes to deal with these incompatibilities. BIP submissions without a sufficient backwards compatibility treatise may be rejected outright.
* Reference Implementation -- The reference implementation must be completed before any BIP is given status "Final", but it need not be completed before the BIP is accepted. It is better to finish the specification and rationale first and reach consensus on it before writing code.
* The final implementation must include test code and documentation appropriate for the Bitcoin protocol.
==BIP Formats and Templates==
BIPs should be written in mediawiki or markdown format.
===BIP Header Preamble===
Each BIP must begin with an RFC 822 style header preamble. The headers must appear in the following order. Headers marked with "*" are optional and are described below. All other headers are required.
The Author header lists the names, and optionally the email addresses of all the authors/owners of the BIP. The format of the Author header value must be
Random J. User
if the email address is included, and just
Random J. User
if the address is not given.
If there are multiple authors, each should be on a separate line following RFC 2822 continuation line conventions.
Note: The Resolution header is required for Standards Track BIPs only. It contains a URL that should point to an email message or other web resource where the pronouncement about the BIP is made.
While a BIP is in private discussions (usually during the initial Draft phase), a Discussions-To header will indicate the mailing list or URL where the BIP is being discussed. No Discussions-To header is necessary if the BIP is being discussed privately with the author, or on the bitcoin email mailing lists.
The Type header specifies the type of BIP: Standards Track, Informational, or Process.
The Created header records the date that the BIP was assigned a number, while Post-History is used to record the dates of when new versions of the BIP are posted to bitcoin mailing lists. Both headers should be in yyyy-mm-dd format, e.g. 2001-08-14.
BIPs may have a Requires header, indicating the BIP numbers that this BIP depends on.
BIPs may also have a Superseded-By header indicating that a BIP has been rendered obsolete by a later document; the value is the number of the BIP that replaces the current document. The newer BIP must have a Replaces header containing the number of the BIP that it rendered obsolete.
===Auxiliary Files===
BIPs may include auxiliary files such as diagrams. Image files should be included in a subdirectory for that BIP. Auxiliary files must be named BIP-XXXX-Y.ext, where "XXXX" is the BIP number, "Y" is a serial number (starting at 1), and "ext" is replaced by the actual file extension (e.g. "png").
==Transferring BIP Ownership==
It occasionally becomes necessary to transfer ownership of BIPs to a new champion. In general, we'd like to retain the original author as a co-author of the transferred BIP, but that's really up to the original author. A good reason to transfer ownership is because the original author no longer has the time or interest in updating it or following through with the BIP process, or has fallen off the face of the 'net (i.e. is unreachable or not responding to email). A bad reason to transfer ownership is because you don't agree with the direction of the BIP. We try to build consensus around a BIP, but if that's not possible, you can always submit a competing BIP.
If you are interested in assuming ownership of a BIP, send a message asking to take over, addressed to both the original author and the BIP editor. If the original author doesn't respond to email in a timely manner, the BIP editor will make a unilateral decision (it's not like such decisions can't be reversed :).
==BIP Editors==
The current BIP editor is Luke Dashjr who can be contacted at [[mailto:luke_bipeditor@dashjr.org|luke_bipeditor@dashjr.org]].
==BIP Editor Responsibilities & Workflow==
The BIP editor subscribes to the Bitcoin development mailing list. All BIP-related correspondence should be sent (or CC'd) to luke_bipeditor@dashjr.org.
For each new BIP that comes in an editor does the following:
* Read the BIP to check if it is ready: sound and complete. The ideas must make technical sense, even if they don't seem likely to be accepted.
* The title should accurately describe the content.
* Edit the BIP for language (spelling, grammar, sentence structure, etc.), markup (for reST BIPs), code style (examples should match BIP 8 & 7).
If the BIP isn't ready, the editor will send it back to the author for revision, with specific instructions.
Once the BIP is ready for the repository it should be submitted as a "pull request" to the [https://github.com/bitcoin/bips bitcoin/bips] repository on GitHub where it may get further feedback.
The BIP editor will:
* Assign a BIP number (almost always just the next available number, but sometimes it's a special/joke number, like 666 or 3141) in the pull request comments.
* Merge the pull request when the author is ready (allowing some time for further peer review).
* List the BIP in [[README.mediawiki]]
* Send email back to the BIP author with next steps (post to bitcoin-dev mailing list).
The BIP editors are intended to fulfill administrative and editorial responsibilities. The BIP editors monitor BIP changes, and correct any structure, grammar, spelling, or markup mistakes we see.
==History==
This document was derived heavily from Python's PEP-0001. In many places text was simply copied and modified. Although the PEP-0001 text was written by Barry Warsaw, Jeremy Hylton, and David Goodger, they are not responsible for its use in the Bitcoin Improvement Process, and should not be bothered with technical questions specific to Bitcoin or the BIP process. Please direct all comments to the BIP editors or the Bitcoin development mailing list.
==Changelog==
10 Oct 2015 - Added clarifications about submission process and BIP number assignment.
01 Jan 2016 - Clarified early stages of BIP idea championing, collecting community feedback, etc.
================================================
FILE: bip-0002.mediawiki
================================================
BIP: 2
Title: BIP process, revised
Authors: Luke Dashjr
Status: Closed
Type: Process
Assigned: 2016-02-03
License: BSD-2-Clause OR OPUBL-1.0
Replaces: 1
Proposed-Replacement: 3
==Abstract==
A Bitcoin Improvement Proposal (BIP) is a design document providing information to the Bitcoin community, or describing a new feature for Bitcoin or its processes or environment. The BIP should provide a concise technical specification of the feature and a rationale for the feature.
We intend BIPs to be the primary mechanisms for proposing new features, for collecting community input on an issue, and for documenting the design decisions that have gone into Bitcoin. The BIP author is responsible for building consensus within the community and documenting dissenting opinions.
Because the BIPs are maintained as text files in a versioned repository, their revision history is the historical record of the feature proposal.
This particular BIP replaces BIP 1 with a more well-defined and clear process.
==Copyright==
This BIP is dual-licensed under the Open Publication License and BSD 2-clause license.
==BIP workflow==
The BIP process begins with a new idea for Bitcoin. Each potential BIP must have a champion -- someone who writes the BIP using the style and format described below, shepherds the discussions in the appropriate forums, and attempts to build community consensus around the idea. The BIP champion (a.k.a. Author) should first attempt to ascertain whether the idea is BIP-able.
Small enhancements or patches to a particular piece of software often don't require standardisation between multiple projects; these don't need a BIP and should be injected into the relevant project-specific development workflow with a patch submission to the applicable issue tracker.
Additionally, many ideas have been brought forward for changing Bitcoin that have been rejected for various reasons.
The first step should be to search past discussions to see if an idea has been considered before, and if so, what issues arose in its progression.
After investigating past work, the best way to proceed is by posting about the new idea to the [https://groups.google.com/g/bitcoindev Bitcoin development mailing list].
Vetting an idea publicly before going as far as writing a BIP is meant to save both the potential author and the wider community time.
Asking the Bitcoin community first if an idea is original helps prevent too much time being spent on something that is guaranteed to be rejected based on prior discussions (searching the internet does not always do the trick).
It also helps to make sure the idea is applicable to the entire community and not just the author. Just because an idea sounds good to the author does not mean it will work for most people in most areas where Bitcoin is used.
Once the champion has asked the Bitcoin community as to whether an idea has any chance of acceptance, a draft BIP should be presented to the [https://groups.google.com/g/bitcoindev Bitcoin development mailing list].
This gives the author a chance to flesh out the draft BIP to make it properly formatted, of high quality, and to address additional concerns about the proposal.
Following a discussion, the proposal should be submitted to the [https://github.com/bitcoin/bips BIPs git repository] as a pull request.
This draft must be written in BIP style as described below, and named with an alias such as "bip-johndoe-infinitebitcoins" until an editor has assigned it a BIP number (authors MUST NOT self-assign BIP numbers).
BIP authors are responsible for collecting community feedback on both the initial idea and the BIP before submitting it for review. However, wherever possible, long open-ended discussions on public mailing lists should be avoided. Strategies to keep the discussions efficient include: setting up a separate SIG mailing list for the topic, having the BIP author accept private comments in the early design phases, setting up a wiki page or git repository, etc. BIP authors should use their discretion here.
It is highly recommended that a single BIP contain a single key proposal or new idea. The more focused the BIP, the more successful it tends to be. If in doubt, split your BIP into several well-focused ones.
When the BIP draft is complete, a BIP editor will assign the BIP a number, label it as Standards Track, Informational, or Process, and merge the pull request to the BIPs git repository.
The BIP editors will not unreasonably reject a BIP.
Reasons for rejecting BIPs include duplication of effort, disregard for formatting rules, being too unfocused or too broad, being technically unsound, not providing proper motivation or addressing backwards compatibility, or not in keeping with the Bitcoin philosophy.
For a BIP to be accepted it must meet certain minimum criteria.
It must be a clear and complete description of the proposed enhancement.
The enhancement must represent a net improvement.
The proposed implementation, if applicable, must be solid and must not complicate the protocol unduly.
The BIP author may update the draft as necessary in the git repository. Updates to drafts should also be submitted by the author as pull requests.
===Transferring BIP Ownership===
It occasionally becomes necessary to transfer ownership of BIPs to a new champion. In general, we'd like to retain the original author as a co-author of the transferred BIP, but that's really up to the original author. A good reason to transfer ownership is because the original author no longer has the time or interest in updating it or following through with the BIP process, or has fallen off the face of the 'net (i.e. is unreachable or not responding to email). A bad reason to transfer ownership is because you don't agree with the direction of the BIP. We try to build consensus around a BIP, but if that's not possible, you can always submit a competing BIP.
If you are interested in assuming ownership of a BIP, send a message asking to take over, addressed to both the original author and the BIP editors. If the original author doesn't respond to email in a timely manner, the BIP editors will make a unilateral decision (it's not like such decisions can't be reversed :).
===BIP Editors===
The current BIP editors are:
* Bryan Bishop ([[mailto:kanzure@gmail.com|kanzure@gmail.com]])
* Jon Atack ([[mailto:jon@atack.com|jon@atack.com]])
* Luke Dashjr ([[mailto:luke_bipeditor@dashjr.org|luke_bipeditor@dashjr.org]])
* Mark "Murch" Erhardt ([[mailto:murch@murch.one|murch@murch.one]])
* Olaoluwa Osuntokun ([[mailto:laolu32@gmail.com|laolu32@gmail.com]])
* Ruben Somsen ([[mailto:rsomsen@gmail.com|rsomsen@gmail.com]])
===BIP Editor Responsibilities & Workflow===
The BIP editors subscribe to the Bitcoin development mailing list.
Off-list BIP-related correspondence should be sent (or CC'd) to the BIP editors.
For each new BIP that comes in an editor does the following:
* Read the BIP to check if it is ready: sound and complete. The ideas must make technical sense, even if they don't seem likely to be accepted.
* The title should accurately describe the content.
* The BIP draft must have been sent to the Bitcoin development mailing list for discussion.
* Motivation and backward compatibility (when applicable) must be addressed.
* The defined Layer header must be correctly assigned for the given specification.
* Licensing terms must be acceptable for BIPs.
If the BIP isn't ready, the editor will send it back to the author for revision, with specific instructions.
Once the BIP is ready for the repository it should be submitted as a "pull request" to the [https://github.com/bitcoin/bips BIPs git repository] where it may get further feedback.
The BIP editor will:
* Assign a BIP number in the pull request.
* Merge the pull request when it is ready.
* List the BIP in [[README.mediawiki]]
The BIP editors are intended to fulfill administrative and editorial responsibilities. The BIP editors monitor BIP changes, and update BIP headers as appropriate.
BIP editors may also, at their option, unilaterally make and merge strictly-editorial changes to BIPs, such as correcting misspellings, fixing broken links, etc.
==BIP format and structure==
===Specification===
BIPs should be written in mediawiki or markdown format.
Each BIP should have the following parts:
* Preamble -- Headers containing metadata about the BIP ([[#BIP header preamble|see below]]).
* Abstract -- A short (~200 word) description of the technical issue being addressed.
* Copyright -- The BIP must be explicitly licensed under acceptable copyright terms ([[#BIP licensing|see below]]).
* Specification -- The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Bitcoin platforms.
* Motivation -- The motivation is critical for BIPs that want to change the Bitcoin protocol. It should clearly explain why the existing protocol is inadequate to address the problem that the BIP solves.
* Rationale -- The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work. The rationale should provide evidence of consensus within the community and discuss important objections or concerns raised during discussion.
* Backwards compatibility -- All BIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The BIP must explain how the author proposes to deal with these incompatibilities.
* Reference implementation -- The reference implementation must be completed before any BIP is given status "Final", but it need not be completed before the BIP is accepted. It is better to finish the specification and rationale first and reach consensus on it before writing code. The final implementation must include test code and documentation appropriate for the Bitcoin protocol.
====BIP header preamble====
Each BIP must begin with an RFC 822 style header preamble. The headers must appear in the following order. Headers marked with "*" are optional and are described below. All other headers are required.
The Layer header (only for Standards Track BIPs) documents which layer of Bitcoin the BIP applies to.
See [[bip-0123.mediawiki|BIP 123]] for definitions of the various BIP layers. Activation of this BIP implies activation of BIP 123.
The Author header lists the names and email addresses of all the authors/owners of the BIP.
The format of the Author header value must be
Random J. User
If there are multiple authors, each should be on a separate line following RFC 2822 continuation line conventions.
While a BIP is in private discussions (usually during the initial Draft phase), a Discussions-To header will indicate the mailing list or URL where the BIP is being discussed. No Discussions-To header is necessary if the BIP is being discussed privately with the author, or on the bitcoin email mailing lists.
The Type header specifies the type of BIP: Standards Track, Informational, or Process.
The Created header records the date that the BIP was assigned a number, while Post-History is used to record when new versions of the BIP are posted to bitcoin mailing lists.
Dates should be in yyyy-mm-dd format, e.g. 2001-08-14.
Post-History is permitted to be a link to a specific thread in a mailing list archive.
BIPs may have a Requires header, indicating the BIP numbers that this BIP depends on.
BIPs may also have a Superseded-By header indicating that a BIP has been rendered obsolete by a later document; the value is the number of the BIP that replaces the current document. The newer BIP must have a Replaces header containing the number of the BIP that it rendered obsolete.
====Auxiliary Files====
BIPs may include auxiliary files such as diagrams. Auxiliary files should be included in a subdirectory for that BIP, or must be named BIP-XXXX-Y.ext, where "XXXX" is the BIP number, "Y" is a serial number (starting at 1), and "ext" is replaced by the actual file extension (e.g. "png").
==BIP types==
There are three kinds of BIP:
* A Standards Track BIP describes any change that affects most or all Bitcoin implementations, such as a change to the network protocol, a change in block or transaction validity rules, or any change or addition that affects the interoperability of applications using Bitcoin. Standards Track BIPs consist of two parts, a design document and a reference implementation.
* An Informational BIP describes a Bitcoin design issue, or provides general guidelines or information to the Bitcoin community, but does not propose a new feature. Informational BIPs do not necessarily represent a Bitcoin community consensus or recommendation, so users and implementers are free to ignore Informational BIPs or follow their advice.
* A Process BIP describes a process surrounding Bitcoin, or proposes a change to (or an event in) a process. Process BIPs are like Standards Track BIPs but apply to areas other than the Bitcoin protocol itself. They may propose an implementation, but not to Bitcoin's codebase; they often require community consensus; unlike Informational BIPs, they are more than recommendations, and users are typically not free to ignore them. Examples include procedures, guidelines, changes to the decision-making process, and changes to the tools or environment used in Bitcoin development. Any meta-BIP is also considered a Process BIP.
==BIP status field==
===Specification===
The typical paths of the status of BIPs are as follows:
Champions of a BIP may decide on their own to change the status between Draft, Deferred, or Withdrawn.
A BIP editor may also change the status to Deferred when no progress is being made on the BIP.
A BIP may only change status from Draft (or Rejected) to Proposed, when the author deems it is complete, has a working implementation (where applicable), and has community plans to progress it to the Final status.
BIPs should be changed from Draft or Proposed status, to Rejected status, upon request by any person, if they have not made progress in three years. Such a BIP may be changed to Draft status if the champion provides revisions that meaningfully address public criticism of the proposal, or to Proposed status if it meets the criteria required as described in the previous paragraph.
A Proposed BIP may progress to Final only when specific criteria reflecting real-world adoption has occurred. This is different for each BIP depending on the nature of its proposed changes, which will be expanded on below. Evaluation of this status change should be objectively verifiable, and/or be discussed on the development mailing list.
When a Final BIP is no longer relevant, its status may be changed to Replaced or Obsolete (which is equivalent to Replaced). This change must also be objectively verifiable and/or discussed.
A process BIP may change status from Draft to Active when it achieves rough consensus on the mailing list. Such a proposal is said to have rough consensus if it has been open to discussion on the development mailing list for at least one month, and no person maintains any unaddressed substantiated objections to it. Addressed or obstructive objections may be ignored/overruled by general agreement that they have been sufficiently addressed, but clear reasoning must be given in such circumstances.
====Progression to Final status====
A soft-fork BIP strictly requires a clear miner majority expressed by blockchain voting (eg, using BIP 9). In addition, if the economy seems willing to make a "no confidence" hard-fork (such as a change in proof-of-work algorithm), the soft-fork does not become Final for as long as such a hard-fork might have majority support, or at most three months. Soft-fork BIPs may also set additional requirements for their adoption. Because of the possibility of changes to miner dynamics, especially in light of delegated voting (mining pools), it is highly recommended that a supermajority vote around 95% be required by the BIP itself, unless rationale is given for a lower threshold.
A hard-fork BIP requires adoption from the entire Bitcoin economy, particularly including those selling desirable goods and services in exchange for bitcoin payments, as well as Bitcoin holders who wish to spend or would spend their bitcoins (including selling for other currencies) differently in the event of such a hard-fork. Adoption must be expressed by de facto usage of the hard-fork in practice (ie, not merely expressing public support, although that is a good step to establish agreement before adoption of the BIP). This economic adoption cannot be established merely by a super-majority, except by literally forcing the minority to accept the hard-fork (whether this is viable or not is outside the scope of this document).
Peer services BIPs should be observed to be adopted by at least 1% of public listening nodes for one month.
API/RPC and application layer BIPs must be implemented by at least two independent and compatible software applications.
Software authors are encouraged to publish summaries of what BIPs their software supports to aid in verification of status changes. Good examples of this at the time of writing this BIP, can be observed in [https://github.com/bitcoin/bitcoin/blob/master/doc/bips.md Bitcoin Core's doc/bips.md file] as well as [https://github.com/bitcoin-wallet/bitcoin-wallet/blob/master/wallet/README.specs.md Bitcoin Wallet for Android's wallet/README.specs.md file].
These criteria are considered objective ways to observe the de facto adoption of the BIP, and are not to be used as reasons to oppose or reject a BIP. Should a BIP become actually and unambiguously adopted despite not meeting the criteria outlined here, it should still be updated to Final status.
===Rationale===
Why is this necessary at all?
* BIP 1 defines an ambiguous criteria for the Status field of BIPs, which is often a source of confusion. As a result, many BIPs with significant real-world use have been left as Draft or Proposed status longer than appropriate. By giving objective criteria to judge the progression of BIPs, this proposal aims to help keep the Status accurate and up-to-date.
How is the entire Bitcoin economy defined by people selling goods/services and holders?
* For Bitcoin to function as a currency, it must be accepted as payment. Bitcoins have no value if you cannot acquire anything in exchange for them. If everyone accepting such payments requires a particular set of consensus rules, "bitcoins" are de facto defined by that set of rules - this is already the case today. If those consensus rules are expected to broaden (as with a hard-fork), those merchants need to accept payments made under the new set of rules, or they will reject "bitcoins" as invalid. Holders are relevant to the degree in that they choose the merchants they wish to spend their bitcoins with, and could also as a whole decide to sell under one set of consensus rules or the other, thus flooding the market with bitcoins and crashing the price.
Why aren't included in the economy?
* Some entities may, to some degree, also be involved in offering goods and/or services in exchange for bitcoins, thus in that capacity (but not their capacity as ) be involved in the economy.
* Miners are not included in the economy, because they merely *rely on* others to sell/spend their otherwise-worthless mined produce. Therefore, they must accept everyone else's direction in deciding the consensus rules.
* Exchanges are not included in the economy, because they merely provide services of connecting the merchants and users who wish to trade. Even if all exchanges were to defect from Bitcoin, those merchants and users can always trade directly and/or establish their own exchanges.
* Developers are not included in the economy, since they merely write code, and it is up to others to decide to use that code or not.
But they're doing something important and have invested a lot in Bitcoin! Shouldn't they be included in such an important decision?
* This BIP does not aim to address what "should" be the basis of decisions. Such a statement, no matter how perfect in its justification, would be futile without some way to force others to use it. The BIP process does not aim to be a kind of forceful "governance" of Bitcoin, merely to provide a collaborative repository for proposing and providing information on standards, which people may voluntarily adopt or not. It can only hope to achieve accuracy in regard to the "Status" field by striving to reflect the reality of *how things actually are*, rather than *how they should be*.
What if a single merchant wishes to block a hard-fork?
* This BIP addresses only the progression of the BIP Status field, not the deployment of the hard-fork (or any other change) itself.
* Regardless, one shop cannot operate in a vacuum: if they are indeed alone, they will soon find themselves no longer selling in exchange for bitcoin payments, as nobody else would exist willing to use the previous blockchain to pay them. If they are no longer selling, they cease to meet the criteria herein which enables their veto.
How about a small number of merchants (maybe only two) who sell products to each other?
* In this scenario, it would seem the previous Bitcoin is alive and working, and that the hard-fork has failed. How to resolve such a split is outside the scope of this BIP.
How can economic agreement veto a soft-fork?
* The group of miners is determined by the consensus rules for the dynamic-membership multi-party signature (for Bitcoin, the proof-of-work algorithm), which can be modified with a hard-fork. Thus, if the same conditions required to modify this group are met in opposition to a soft-fork, the miner majority supporting the soft-fork is effectively void because the economy can decide to replace them with another group of would-be miners who do not support the soft-fork.
What happens if the economy decides to hard-fork away from a controversial soft-fork, more than three months later?
* The controversial soft-fork, in this circumstance, changes from Final to Replaced status to reflect the nature of the hard-fork replacing the previous (final) soft-fork.
What is the ideal percentage of listening nodes needed to adopt peer services proposals?
* This is unknown, and set rather arbitrarily at this time. For a random selection of peers to have at least one other peer implementing the extension, 13% or more would be necessary, but nodes could continue to scan the network for such peers with perhaps some reasonable success. Furthermore, service bits exist to help identification upfront.
Why is it necessary for at least two software projects to release an implementation of API/RPC and application layer BIPs, before they become Final?
* If there is only one implementation of a specification, there is no other program for which a standard interface is used with or needed.
* Even if there are only two projects rather than more, some standard coordination between them exists.
What if a BIP is proposed that only makes sense for a single specific project?
* The BIP process exists for standardisation between independent projects. If something only affects one project, it should be done through that project's own internal processes, and never be proposed as a BIP in the first place.
==BIP comments==
===Specification===
Each BIP should, in its preamble, link to a public wiki page with a summary tone of the comments on that page.
Reviewers of the BIP who consider themselves qualified, should post their own comments on this wiki page.
The comments page should generally only be used to post final comments for a completed BIP.
If a BIP is not yet completed, reviewers should instead post on the applicable development mailing list thread to allow the BIP author(s) to address any concerns or problems pointed out by the review.
Some BIPs receive exposure outside the development community prior to completion, and other BIPs might not be completed at all. To avoid a situation where critical BIP reviews may go unnoticed during this period, reviewers may, at their option, still post their review on the comments page, provided they first post it to the mailing list and plan to later remove or revise it as applicable based on the completed version. Such revisions should be made by editing the previous review and updating the timestamp. Reviews made prior to the complete version may be removed if they are no longer applicable and have not been updated in a timely manner (eg, within one month).
Pages must be named after the full BIP number (eg, "BIP 0001") and placed in the "Comments" namespace.
For example, the link for BIP 1 will be https://github.com/bitcoin/bips/wiki/Comments:BIP-0001 .
Comments posted to this wiki should use the following format:
--,
BIPs may also choose to list a second forum for BIP comments, in addition to the BIPs wiki.
In this case, the second forum's URI should be listed below the primary wiki's URI.
After some time, the BIP itself may be updated with a summary tone of the comments.
Summary tones may be chosen from the following, but this BIP does not intend to cover all possible nuances and other summaries may be used as needed:
* No comments yet.
* Unanimously Recommended for implementation
* Unanimously Discourage for implementation
* Mostly Recommended for implementation, with some Discouragement
* Mostly Discouraged for implementation, with some Recommendation
For example, the preamble to BIP 1 might be updated to include the line:
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0001
https://some-other-wiki.org/BIP_1_Comments
These fields must follow the "Discussions-To" header defined in BIP 1 (if that header is not present, it should follow the position where it would be present; generally this is immediately above the Status header).
To avoid doubt: comments and status are unrelated metrics to judge a BIP, and neither should be directly influencing the other.
===Rationale===
What is the purpose of BIP comments?
* Various BIPs have been adopted (the criteria required for "Final" Status) despite being considered generally inadvisable. Some presently regard BIPs as a "good idea" simply by virtue of them being assigned a BIP number. Due to the low barrier of entry for submission of new BIPs, it seems advisable for a way for reviewers to express their opinions on them in a way that is consumable to the public without needing to review the entire development discussion.
Will BIP comments be censored or limited to particular participants/"experts"?
* Participants should freely refrain from commenting outside of their area of knowledge or expertise. However, comments should not be censored, and participation should be open to the public.
==BIP licensing==
===Specification===
New BIPs may be accepted with the following licenses. Each new BIP must identify at least one acceptable license in its preamble. The License header in the preamble must be placed after the Created header. Each license must be referenced by their respective abbreviation given below.
For example, a preamble might include the following License header:
License: BSD-2-Clause
GNU-All-Permissive
In this case, the BIP text is fully licensed under both the OSI-approved BSD 2-clause license as well as the GNU All-Permissive License, and anyone may modify and redistribute the text provided they comply with the terms of *either* license. In other words, the license list is an "OR choice", not an "AND also" requirement.
It is also possible to license source code differently from the BIP text. An optional License-Code header is placed after the License header. Again, each license must be referenced by their respective abbreviation given below.
For example, a preamble specifying the optional License-Code header might look like:
License: BSD-2-Clause
GNU-All-Permissive
License-Code: GPL-2.0+
In this case, the code in the BIP is not available under the BSD or All-Permissive licenses, but only under the terms of the GNU General Public License (GPL), version 2 or newer.
If the code were to be available under *only* version 2 exactly, the "+" symbol should be removed from the license abbreviation.
For a later version (eg, GPL 3.0), you would increase the version number (and retain or remove the "+" depending on intent).
License-Code: GPL-2.0 # This refers to GPL v2.0 *only*, no later license versions are acceptable.
License-Code: GPL-2.0+ # This refers to GPL v2.0 *or later*.
License-Code: GPL-3.0 # This refers to GPL v3.0 *only*, no later license versions are acceptable.
License-Code: GPL-3.0+ # This refers to GPL v3.0 *or later*.
In the event that the licensing for the text or code is too complicated to express with a simple list of alternatives, the list should instead be replaced with the single term "Complex". In all cases, details of the licensing terms must be provided in the Copyright section of the BIP.
BIPs are not required to be *exclusively* licensed under approved terms, and may also be licensed under unacceptable licenses *in addition to* at least one acceptable license.
In this case, only the acceptable license(s) should be listed in the License and License-Code headers.
====Recommended licenses====
* BSD-2-Clause: [https://opensource.org/license/BSD-2-Clause OSI-approved BSD 2-clause license]
* BSD-3-Clause: [https://opensource.org/license/BSD-3-Clause OSI-approved BSD 3-clause license]
* CC0-1.0: [https://creativecommons.org/publicdomain/zero/1.0/ Creative Commons CC0 1.0 Universal]
* FSFAP: [https://www.gnu.org/prep/maintain/html_node/License-Notices-for-Other-Files.html FSF All Permissive License]
In addition, it is recommended that literal code included in the BIP be dual-licensed under the same license terms as the project it modifies. For example, literal code intended for Bitcoin Core would ideally be dual-licensed under the MIT license terms as well as one of the above with the rest of the BIP text.
====Not recommended, but acceptable licenses====
* Apache-2.0: [https://www.apache.org/licenses/LICENSE-2.0 Apache License, version 2.0]
* BSL-1.0: [https://www.boost.org/LICENSE_1_0.txt Boost Software License, version 1.0]
* CC-BY-4.0: [https://creativecommons.org/licenses/by/4.0/ Creative Commons Attribution 4.0 International]
* CC-BY-SA-4.0: [https://creativecommons.org/licenses/by-sa/4.0/ Creative Commons Attribution-ShareAlike 4.0 International]
* MIT: [https://opensource.org/license/MIT The MIT License]
* AGPL-3.0+: [https://www.gnu.org/licenses/agpl-3.0.en.html GNU Affero General Public License (AGPL), version 3 or newer]
* FDL-1.3: [https://www.gnu.org/licenses/fdl-1.3.en.html GNU Free Documentation License, version 1.3]
* GPL-2.0+: [https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html GNU General Public License (GPL), version 2 or newer]
* LGPL-2.1+: [https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html GNU Lesser General Public License (LGPL), version 2.1 or newer]
====Not acceptable licenses====
All licenses not explicitly included in the above lists are not acceptable terms for a Bitcoin Improvement Proposal unless a later BIP extends this one to add them.
However, BIPs predating the acceptance of this BIP were allowed under other terms, and should use these abbreviation when no other license is granted:
* OPUBL-1.0: [https://opencontent.org/openpub/ Open Publication License, version 1.0]
* PD: Released into the public domain
===Rationale===
BIP 1 allowed the Open Publication License or releasing into the public domain; was this insufficient?
* The OPUBL-1.0 is generally regarded as obsolete, and not a license suitable for new publications.
* Many are unfamiliar with the OPUBL-1.0 terms, and may just prefer to use the public domain rather than license under uncertain terms.
* The OPUBL-1.0 license terms allowed for the author to prevent publication and derived works, which was widely considered inappropriate for Bitcoin standards.
* Public domain is not universally recognised as a legitimate action, thus it is inadvisable.
Why are there software licenses included?
* Some BIPs, especially consensus layer, may include literal code in the BIP itself which may not be available under the exact license terms of the BIP.
* Despite this, not all software licenses would be acceptable for content included in BIPs.
Why is Public Domain no longer acceptable for new BIPs?
* In some jurisdictions, public domain is not recognised as a legitimate legal action, leaving the BIP simply copyrighted with no redistribution or modification allowed at all.
==Changes from BIP 1==
* Acceptable licenses are entirely rechosen, allowing a wide variety of open licenses, while prohibiting the problematic older choices.
* Accepted Status has been renamed to Proposed.
* An implementation is now required (when applicable) before BIPs can proceed to Proposed Status.
* BIP Comments are newly introduced.
* The License preamble headers have been added.
* The Layer header is included from BIP 123.
* Non-image auxiliary files are permitted in the bip-XXXX subdirectory.
* Email addresses are now required for authors.
* The Post-History header may be provided as a link instead of a simple date.
* The Resolution header has been dropped, as it is not applicable to a decentralised system where no authority exists to make final decisions.
==See Also==
* [[bip-0001.mediawiki|BIP 1: BIP Purpose and Guidelines]]
* [[bip-0123.mediawiki|BIP 123: BIP Classification]]
* [https://tools.ietf.org/html/rfc7282 RFC 7282: On Consensus and Humming in the IETF]
================================================
FILE: bip-0003.md
================================================
```
BIP: 3
Title: Updated BIP Process
Authors: Murch
Status: Deployed
Type: Process
Assigned: 2025-01-09
License: BSD-2-Clause
Discussion: https://github.com/murchandamus/bips/pull/2
https://gnusha.org/pi/bitcoindev/59fa94cea6f70e02b1ce0da07ae230670730171c.camel@timruffing.de/#t
Version: 1.4.0
Requires: 123
Replaces: 2
```
## Abstract
This _Bitcoin Improvement Proposal (BIP)_ provides information about the preparation of BIPs and policies relating to
the publication of BIPs. It replaces [BIP 2](bip-0002.mediawiki) with a streamlined process, and may be amended to
address the evolving needs of the BIP process.
## Motivation
BIP 2 was written in 2016.
This BIP revisits aspects of the BIP 2 process
that did not achieve broad adoption, reduces the judgment calls assigned to the BIP Editor role, delineates the
BIP types more clearly, and generalizes the BIP process to fit the community’s use of the repository.
## Fundamentals
### What is a BIP?
BIPs are improvement proposals for Bitcoin. The main topic is information and technologies that support and expand the utility of the Bitcoin
currency. Most BIPs provide a concise, self-contained, technical description of one new concept, feature, or standard.
Some BIPs describe processes, implementation guidelines, best practices, incident reports (e.g.,
[BIP 50](bip-0050.mediawiki)), or other information relevant to the Bitcoin community. However, any topics related to
the Bitcoin protocol, peer-to-peer network, and client software may be acceptable.
BIPs are intended to be a means for proposing new protocol features, coordinating client standards, and
documenting design decisions that have gone into implementations. BIPs may be submitted by anyone, provided the
content is of high quality, e.g., does not waste the community’s time.
The scope of the BIPs
repository is limited to BIPs that do not oppose the fundamental principle that Bitcoin constitutes a peer-to-peer
electronic cash system for the Bitcoin currency.
### BIP Ownership
Each BIP is primarily owned by its authors and represents the authors’ opinion or recommendation. The authors are
expected to foster discussion, address feedback and dissenting opinions, and, if applicable, advance the adoption of
their proposal within the Bitcoin community. As a BIP progresses through the workflow, it becomes increasingly
co-owned by the Bitcoin community.
#### Authors and Deputies
Authors may want additional help with the BIP process after writing an initial draft. In that case, they may assign
one or more Deputies to their BIP. Deputies are stand-in owners of a BIP who were not involved in writing the
document. They support the authors in advancing the proposal, or act as a point of contact for the BIP in the absence of the
authors. Deputies may perform the role of Authors for any aspect of the BIP process unless overruled by an Author.
Deputies share ownership of the BIP at the discretion of the Authors.
### What is the Significance of BIPs?
BIPs do not define what Bitcoin is: individual BIPs do not represent Bitcoin community consensus or a general
recommendation for implementation. A BIP represents a personal recommendation by the BIP authors to the Bitcoin
community. Some BIPs may never be adopted. Some BIPs may be adopted by one or more Bitcoin clients or other related
software. Some may even end up changing the consensus rules that the Bitcoin ecosystem jointly enforces.
### What is the Purpose of the BIPs Repository?
The [BIPs repository](https://github.com/bitcoin/bips/) serves as a publication medium and archive for mature proposals.
Through its high visibility, it facilitates the community-wide consideration of BIPs and provides a well-established
source to retrieve the latest version of any BIP. The repository transparently records all changes to each BIP and
allows any community member to retain a complete copy of the archive easily.
The BIPs repository neither tracks community sentiment[^acceptance] nor ecosystem adoption[^adoption] of BIPs beyond
the brief overview provided via the BIP status (see [Workflow](#workflow) below).
Proposals are published in this repository if they are on-topic and fulfill the editorial criteria.
No formal or informal decision body governs Bitcoin development or decides adoption of BIPs.
## BIP Format and Structure
### Specification
Authors may choose to submit BIPs in MediaWiki or Markdown[^markdown] format.
Each BIP must have a _Preamble_, an _Abstract_, a _Copyright_, and a _Motivation_ section. Authors should consider all issues in the
following list and address each as appropriate.
* Preamble — Headers containing metadata about the BIP (see the section [BIP Header Preamble](#bip-header-preamble)
below).
* Abstract — A short description of the issue being addressed.
* Motivation — Why is this BIP being written? Clearly explain how the existing situation presents a problem and why the proposed idea resolves the
issue or improves upon the current situation.
* Specification — The technical specification should describe the syntax and semantics of any new feature. The
specification should be detailed enough to enable any Bitcoin project to create an interoperable implementation.
* Rationale — The rationale fleshes out the specification by describing what inspired the design and why particular
design decisions were made. It should describe related work and alternate designs that were considered. The rationale
should record relevant objections or important concerns that were raised and addressed as this proposal was developed.
* Backward Compatibility — Any BIP that introduces incompatibilities must include a section describing these incompatibilities and their severity as well as provide instructions on how
implementers and users should deal with these incompatibilities.
* Reference Implementation — Where applicable, a reference implementation, test vectors, and documentation must be
finished before the BIP can be given the status "Complete". Test vectors must be provided in the BIP or
as auxiliary files (see [Auxiliary Files](#auxiliary-files)) under an acceptable license. The reference implementation
can be provided in the BIP, as an auxiliary file, or per linking another code reference that is expected to remain
available permanently such as a pull request, a dedicated branch, a new repository, or similar.
* Changelog — A section to track modifications to a BIP after reaching Complete status.
* Copyright — The BIP must be placed under an acceptable license (see [BIP Licensing](#bip-licensing) below).
#### BIP Header Preamble
Each BIP must begin with an [RFC 822-style header preamble](https://www.w3.org/Protocols/rfc822/). The headers must
appear in the following order. Headers marked with "\*" are optional. All other headers are required.
##### Overview
```
BIP:
* Layer:
Title:
Authors:
* Deputies:
Status:
Type:
Assigned:
License:
* Discussion:
* Version:
* Requires:
* Replaces:
* Proposed-Replacement:
```
##### Header Descriptions
* BIP — The assigned number of the BIP (without leading zeros). Please use "?" before a number has been assigned by the BIP Editors.
* Layer — The layer of Bitcoin the BIP applies to using the BIP classification defined in [BIP 123](bip-0123.mediawiki).
* Authors — The names (or pseudonyms) and email addresses of all authors of the BIP. The format of each authors header
value must be
Random J. User
Multiple authors are recorded on separate lines:
Authors: Random J. User
Anata Sample
* Deputies — Additional owners of the BIP that are not authors. The Deputies header uses the same format as the
Authors header. See the [BIP Ownership](#bip-ownership) section above.
* Status — The stage of the workflow of the proposal. See the [Workflow](#workflow) section below.
* Type — See the [BIP Types](#bip-types) section below for a description of the three BIP types.
* Assigned – The date a BIP was assigned its number. Please use "?" before a number has been assigned by the BIP Editors.
* License — The License header specifies SPDX License Expressions describing the terms under which the
BIP and its auxiliary files are available. See the [BIP Licensing](#bip-licensing) section below.
* Discussion — The Discussion header points the audience to relevant discussions of the BIP, e.g., the mailing list
thread in which the idea for the BIP was discussed, a thread where a new version of the BIP was presented, or relevant
discussion threads on other platforms. Entries take the format "yyyy-mm-dd: URL", e.g., `2009-01-09:
https://www.mail-archive.com/cryptography@metzdowd.com/msg10142.html`, using the date and URL of the start of the
conversation. Multiple discussions should be listed on separate lines.
* Version — The current version number of this BIP. See the [Changelog](#changelog-section-and-version-header) section below.
* Requires — A list of existing BIPs the new proposal depends on. If multiple BIPs
are required, they should be listed in one line separated by a comma and space (e.g., "1, 2").
* Replaces[^proposes-to-replace] — BIP authors may put the numbers of one or more prior BIPs in the Replaces header to recommend that their
BIP succeeds, supersedes, or renders obsolete those prior BIPs.
* Proposed-Replacement[^superseded-by-proposed-replacement] — When a later BIP indicates that it intends to supersede an
existing BIP, the later BIP’s number is added to the Proposed-Replacement header of the existing BIP to indicate the
potential successor BIP.
#### Auxiliary Files
BIPs may include auxiliary files such as diagrams and source code. Auxiliary files must be included in a subdirectory
for that BIP named `bip-XXXX`, where "XXXX" is the BIP number zero-padded to four digits. File names in the subdirectory
do not need to adhere to a specific convention.
### BIP Types
* A **Specification BIP** defines a set of technical rules describing a new feature or affecting the interoperability of implementations. The
distinguishing characteristic of a Specification BIP is that it can be implemented, and implementations can be compliant with
it. Specification BIPs must have a Specification section, must have a Backward Compatibility section (if incompatibilities are introduced), and can only be advanced to Complete after they contain or refer to a reference implementation and test vectors.
* An **Informational BIP** describes a Bitcoin design issue, or provides general guidelines or other information to the
Bitcoin community.
* A **Process BIP** describes a process surrounding Bitcoin, or proposes a change to (or an event in) a process. Process
BIPs are like Specification BIPs, but apply to topics other than the Bitcoin protocol and Bitcoin implementations.
They often require community consensus and are typically binding for the corresponding process. Examples include
procedures, guidelines, and changes to decision-making processes such as the BIP process.
## Workflow
The BIP process starts with a new idea for Bitcoin. Each potential BIP must have authors—people who write the BIP,
gather feedback, shepherd the discussion in the appropriate forums, and finally recommend a mature proposal to the
community.

### Ideation
After having an idea, the authors should evaluate whether it meets the criteria to become a BIP, as described in this
BIP. The idea must be of interest to the broader community or relevant to multiple software projects. Minor improvements
and matters concerning only a single project usually do not require standardization and should instead be brought up directly to
the relevant project.
The authors should first research whether their idea has been considered before. Ideas in Bitcoin are often rediscovered,
and prior related discussions may inform the authors of the issues that may arise in its progression. After some investigation,
the novelty and viability of the idea should be tested by posting a new, dedicated thread about the idea to the [Bitcoin Development Mailing
List](https://groups.google.com/g/bitcoindev). Prior correspondence can be found in the [mailing list
archive](https://gnusha.org/pi/bitcoindev/).
It is recommended that authors establish before or at the start of working on a draft whether their idea may be of
interest to the Bitcoin community.
Authors should avoid opening a pull request with a BIP draft out of the blue.
Vetting an idea publicly before investing time and effort to formally describe the idea is meant to save time for both the authors and
the community. Not only may someone point out relevant discussion topics that were missed in the authors’
research, or that an idea is guaranteed to be rejected based on prior discussions, but describing an idea publicly also
tests whether it is of interest to more people beside the authors.
As a first sketch of the proposal is taking shape, the authors should present it to the [Bitcoin Development Mailing
List](https://groups.google.com/g/bitcoindev). This gives the authors a chance to collect initial feedback and address
fundamental concerns. If the authors wish to work in public on the proposal at this stage, it is recommended that they
open a pull request against one of their forks of the BIPs repository instead of the main BIPs repository.
It is recommended that complicated proposals be split into separate BIPs that each focus on a specific component of the
overall proposal.
### Progression through BIP Statuses
The following sections refer to BIP Status field values. The BIP Status field is defined in the Header Preamble
specification above.
#### Draft
After fleshing out the proposal further and ensuring that it is of high quality and properly formatted, the authors
should open a pull request to the [BIPs repository](https://github.com/bitcoin/bips). The document must adhere to the
formatting requirements specified above and should be provided as a file named with a working title of the form
"bip-title.[md|mediawiki]". Only BIP Editors may assign BIP numbers. Until one has done so, authors should refer to their
BIP by name only.
BIPs that (1) adhere to the formatting requirements, (2) are on-topic, and (3) have materially progressed beyond the
ideation phase, e.g., by generating substantial public discussion and commentary from diverse contributors, by
independent Bitcoin projects working on adopting the proposal, or by the authors working for an extended period toward
improving the proposal based on community feedback, will be assigned a number by a BIP Editor. A number may be
considered assigned only after it has been publicly announced in the pull request by a BIP Editor. The BIP Editors should
not assign a number when they perceive a proposal being met with lack of interest: number assignment facilitates the
distributed discussion of ideas, but before a proposal garners some interest in the Bitcoin community, there is no need
to refer to it by a number.
Proposals are also not ready for number assignment if they duplicate efforts, disregard formatting rules, are too
unfocused or too broad, fail to provide proper motivation, fail to address backward compatibility where necessary, or
fail to specify the feature clearly and comprehensively. Reviewers and BIP Editors should provide guidance on how the
proposal may be improved to progress toward readiness. Pull requests that are proposing off-topic ideas or
have stopped making progress may be closed.
When the proposal is ready and has been assigned a number, a BIP Editor will merge it into the BIPs repository. After the
BIP has been merged to the repository, its main focus should no longer shift significantly, even while the authors may
continue to update the proposal as necessary. Updates to merged documents by the authors should also be submitted as
pull requests.
#### Complete[^complete]
When the authors have concluded all planned work on their proposal, are confident that their BIP represents a net
improvement, is clear, comprehensive, and is
ready for adoption by the Bitcoin community, they may update the BIP’s status to Complete to indicate that they
recommend adoption, implementation, or deployment of the BIP. Where applicable, the authors must ensure that any
proposed specification is solid, not unduly complicated, and definitive. Specification BIPs must come with or refer to a working reference implementation and comprehensive test vectors before they can be moved to Complete. Subsequently, the BIP’s content should only be
adjusted in minor details, e.g., to improve language, clarify ambiguities, backfill omissions in the specification, add
test vectors for edge cases, or address other issues discovered as the BIP is being adopted.
A Complete BIP can only move to Deployed or Closed. Any necessary changes to the specification should be minimal and
interfere as little as possible with ongoing adoption. If a Complete BIP is found to need substantial functional
changes, it may be preferable to move it to Closed[^new-BIP], and to start a new BIP with the changes instead.
Otherwise, it could cause confusion as to what being compliant with the BIP means.
A BIP may remain in the Complete status indefinitely unless its authors or deputies decide to move it to Closed or it is advanced to
Deployed.
Complete is the final status for most successful Informational BIPs.
#### Deployed
A Complete BIP should only be moved to Deployed once it is settled: after its approach has solidified, its
Specification has been put through its paces, feedback from early adopters has been processed, and amendments to the BIP have stopped.
Then, a BIP may be advanced to Deployed upon request by any community member with evidence[^evidence] that
the BIP is in active use. Convincing evidence includes for example: an established project having deployed support
for the BIP in mainnet software releases, a soft fork proposal’s activation criteria having been met on the network, or
rough consensus for the BIP having been demonstrated.
Once Deployed, the BIP is considered final.
Any modifications to the BIP beyond bug fixes, other minor amendments, additions to the test vectors, or editorial
changes should be avoided.
Any breaking changes to the BIP’s Specification should be proposed as a new separate BIP.[^new-BIP]
##### Process BIPs
A Process BIP may change status from Complete to Deployed when it achieves rough consensus on the Bitcoin Development Mailing List. A
proposal is said to have rough consensus if its advancement has been open to discussion on the mailing list for at least
one month, the discussion achieved meaningful engagement, and no person maintains any unaddressed substantiated objections to it. Addressed or obstructive objections
may be ignored/overruled by general agreement that they have been sufficiently addressed, but clear reasoning must be
given in such circumstances. Deployed Process BIPs may be modified indefinitely as long as a proposed modification has
rough consensus per the same criteria.[^living-documents]
#### Closed[^closed]
A BIP that is of historical interest only, and is not being actively worked on, promoted or in active use, should be
marked as Closed. The reason for moving the
proposal to (or from) Closed should be recorded in the Changelog section in the same commit that updates the status.
BIPs do not get deleted, they are retained even after being updated to Closed.
Transitions involving the Closed state are:
##### Draft ↦ Closed
BIP authors may decide on their own to change their BIP’s status from Draft to Closed. If a Draft BIP stops making
progress, sees accumulated feedback unaddressed, or otherwise appears stalled for a year, anyone may propose the BIP
status be updated to Closed. The BIP is then updated to Closed unless the authors assert that they intend to continue work within four weeks of being contacted.
##### Complete ↦ Closed
BIPs that had attained the Complete status, i.e., that had been recommended for adoption, may be moved to Closed per the
authors’ announcement to the Bitcoin Development Mailing List[^bip-announcements-to-list]. However, if someone volunteers to adopt the proposal
within four weeks, they become the BIP's author or deputy (see [Transferring BIP Ownership](#transferring-bip-ownership) below), and the BIP will
remain Complete instead.
##### Deployed ↦ Closed
A BIP may evolve from Deployed to Closed when it is no longer in active use. Any community member may initiate this
Status update by announcing it to the mailing list[^bip-announcements-to-list], and proceed if no objections have been raised for four weeks.
##### Closed ↦ Draft
The Closed status is generally intended to be a final status for BIPs,
and if BIP authors decide to make another attempt at a previously Closed BIP, it is generally recommended to create a new
proposal. (Obviously, the authors may borrow any amount of inspiration or actual text from any prior BIPs as licensing
permits.) The authors should take special care to address the issues that caused the prior attempt’s abandonment. Even
if the prior attempt had been assigned a number, the new BIP will generally be assigned a distinct number. However, if it is
obvious that the new attempt directly continues work on the same idea, it may be reasonable to return the
Closed BIP to Draft status.
### Changelog Section and Version Header
To help implementers understand updates to a BIP, any changes after it has reached Complete must be tracked with version,
date, and description in a Changelog section sorted by most recent version first. The version number is inspired by semantic versioning (MAJOR.MINOR.PATCH).
The MAJOR version is incremented if changes to the BIP’s Specification are introduced that are incompatible with prior
versions (which should be rare after a BIP is Complete, and only happen in well-grounded exceptional cases to a BIP that
is Deployed). The MINOR version is incremented whenever the specification of the BIP is changed or extended in a
backward-compatible way. The PATCH version is incremented for other changes to the BIP that are noteworthy (bug fixes,
test vectors, important clarifications, etc.). Version 1.0.0 is used to label the promotion to
Complete. A Changelog section may be introduced during the Draft phase to record significant changes (using versions 0.x.y).
Example:
> __Changelog__
>
> * __2.0.0__ (2025-01-22):
> * Introduce a breaking change in the specification to fix a bug.
> * __1.1.0__ (2025-01-17):
> * Add a backward compatible extension to the BIP.
> * __1.0.1__ (2025-01-15):
> * Clarify an edge case and add corresponding test vectors.
> * __1.0.0__ (2025-01-14):
> * Complete planned work on the BIP.
After a BIP receives a Changelog, the
Preamble must indicate the latest version in the Version header. The Changelog highlights revisions to BIPs to human readers. A single
BIP shall not recommend more than one variant of an idea at the same time. A different or
competing variant of an existing BIP must be published as a separate BIP.
### Adoption of Proposals
The BIPs repository does not track the sentiment on proposals and does not track the adoption of BIPs beyond whether they
are in active use or not. It is not intended for BIPs to list additional implementations beyond the reference
implementation: the BIPs repository is not a signpost where to find implementations.[^OtherImplementations] After a BIP
is advanced to Complete, it is up to the Bitcoin community to evaluate, adopt, ignore, or reject a BIP. Individual
Bitcoin projects are encouraged to publish a list of BIPs they implement. A good example of this at the time of writing
this BIP can be observed in Bitcoin Core’s [doc/bips.md](https://github.com/bitcoin/bitcoin/blob/master/doc/bips.md)
file.
### Transferring BIP Ownership
It occasionally becomes necessary to transfer ownership of BIPs to new owners. In general, it would be preferable to
retain the original authors of the transferred BIP, but that is up to the original authors. A good reason to transfer
ownership is because the original authors no longer have the time or interest in updating it or following through with
the BIP process, or are unreachable or unresponsive. A bad reason
to transfer ownership is because someone doesn't agree with the direction of the BIP. The community tries to build
consensus around a BIP, but if that's not possible, rather than fighting over control, the dissenters should supply a
competing BIP.
If someone is interested in assuming ownership of a BIP, they should send an email asking to take over, addressed to the
original authors, the BIP Editors, and the Bitcoin Development Mailing List[^bip-announcements-to-list]. If the authors are unreachable or do not respond in a timely
manner (e.g., four weeks), the BIP Editors will make a unilateral decision whether to appoint the applicants as
[Authors or Deputies](#authors-and-deputies) (which may be amended should the original authors make a delayed reappearance).
## BIP Licensing
The Bitcoin project develops a global peer-to-peer digital cash system. Open standards are indispensable for continued
interoperability. Open standards reduce friction, and encourage anybody and everyone to contribute, compete, and
innovate on a level playing field. Only freely licensed contributions are accepted to the BIPs repository.
### Specification
Each new BIP must specify in two ways under which license terms it is made available. First, it must specify an [SPDX
License Expression](https://spdx.dev/ids/) in the License field in the preamble. Second, it must include a matching
Copyright section, possibly providing further details on licensing.
For example, a preamble might include the following License header:
License: CC0-1.0 OR MIT
In this case, the BIP (including all auxiliary files) is made available under the terms of both CC0 1.0 Universal as well as the
MIT License, and anyone may modify and redistribute it provided they comply with the terms of
*either* license, at their option. In other words, the license list is an "OR choice", not an "AND also" requirement. See the [SPDX
documentation](https://spdx.dev/ids/) and the [SPDX License List](https://spdx.org/licenses/) for further details.
Wherever different from those specified in the License header, an auxiliary file or directory should specify the license terms under which it is made available as is common in
software (e.g., with a [`SPDX-License-Identifier: ` comment](https://spdx.dev/ids/),
a license header, or a LICENSE/COPYING file). Such exceptions should also be mentioned in the Copyright section. It is recommended to make any test vectors available
under CC0-1.0 or FSFAP in addition to any other licenses to allow anyone to copy test vectors into their
implementations without introducing license hindrances.
A few BIP2-era BIPs (98, 116, 117, 330, 340) have a no longer used "License-Code" header indicating the license terms applicable to auxiliary source code files. For such cases, please refer to BIP2.
It is recommended that source code included in a BIP (whether within the text or in auxiliary files) be licensed under the same license terms as the project it
is proposed to modify, if any. For example, changes intended for Bitcoin Core would ideally be licensed (also) under the MIT
License.
In all cases, details of the licensing terms must be provided in the Copyright section of the BIP.
#### Acceptable Licenses[^licenses]
Each new BIP must be made available under at least one acceptable license as listed below. BIPs are not required to be
*exclusively* licensed under approved terms, and may also be licensed under other licenses *in addition to* at least one
acceptable license.
In other words, a new BIP must specify an SPDX License Expression that is either "L" or equivalent to "L OR E" for some
acceptable license L from the following list and another SPDX License Expression E.
* BSD-2-Clause: [BSD 2-Clause License](https://opensource.org/license/BSD-2-Clause)
* BSD-3-Clause: [BSD 3-Clause License](https://opensource.org/license/BSD-3-Clause)
* CC0-1.0: [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/)
* FSFAP: [FSF All Permissive License](https://www.gnu.org/prep/maintain/html_node/License-Notices-for-Other-Files.html)
* CC-BY-4.0: [Creative Commons Attribution 4.0 International](https://creativecommons.org/licenses/by/4.0/)
* MIT: [The MIT License](https://opensource.org/license/MIT)
* MIT-0: [MIT No Attribution License](https://opensource.org/license/MIT-0)
* Apache-2.0: [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)
* BSL-1.0: [Boost Software License 1.0](https://www.boost.org/LICENSE_1_0.txt)
#### Not Acceptable Licenses
All licenses not explicitly included in the above lists are not acceptable terms for a Bitcoin Improvement Proposal.
However, BIPs predating this proposal were accepted under other terms, and should use one of the following identifiers.
* LicenseRef-PD: Placed into the public domain
* OPUBL-1.0: [Open Publication License 1.0](https://opencontent.org/openpub/)
## BIP Editors
The current BIP Editors are:
* Bryan Bishop ([kanzure@gmail.com](mailto:kanzure@gmail.com))
* Jon Atack ([jon@atack.com](mailto:jon@atack.com))
* Luke Dashjr ([luke_bipeditor@dashjr.org](mailto:luke_bipeditor@dashjr.org))
* Mark "Murch" Erhardt ([murch@murch.one](mailto:murch@murch.one))
* Olaoluwa Osuntokun ([laolu32@gmail.com](mailto:laolu32@gmail.com))
* Ruben Somsen ([rsomsen@gmail.com](mailto:rsomsen@gmail.com))
### BIP Editor Responsibilities and Workflow
The BIP Editors subscribe to the Bitcoin Development Mailing List and watch the [BIPs
repository](https://github.com/bitcoin/bips).
When either a new BIP idea or an early draft is submitted to the mailing list, BIP Editors or other community members should comment in regard
to:
* Novelty of the idea
* Viability, utility, and relevance of the concept
* Readiness of the proposal
* On-topic for the Bitcoin community
Discussion in pull request comments can often be hard to follow as feedback gets marked as resolved when it is addressed
by authors. Substantive discussion of ideas may be more accessible to a broader audience on the mailing list, where it
is also more likely to be retained by the community memory.
If the BIP needs more work, an editor should ensure that constructive, actionable feedback is provided to the authors
for revision. Once the BIP is ready it should be submitted as a "pull request" to the [BIPs
repository](https://github.com/bitcoin/bips) where it may get further feedback.
For each new BIP pull request that comes in, an editor checks the following:
* The idea has been previously proposed to the Bitcoin Development Mailing List and discussed there
* The described idea is on-topic for the repository
* A draft of the BIP by one of the authors has been previously discussed on the Bitcoin Development Mailing List
* Title accurately describes the content
* Proposal is of general interest and/or pertains to more than one Bitcoin project/implementation
* Document is properly formatted
* Licensing terms are acceptable
* Motivation, Rationale, and Backward Compatibility have been addressed
* Specification provides sufficient detail for implementation
* The defined Layer and Type headers must be correctly assigned for the given specification
* The BIP is ready: it is comprehensible, technically feasible and sound, and all aspects are addressed as necessary
Editors do NOT evaluate whether the proposal is likely to be adopted.
Then, a BIP Editor will:
* Assign a BIP number in the pull request
* Ensure that the BIP is listed in the [README](README.mediawiki)
* Merge the pull request when it is ready
The BIP Editors are intended to fulfill administrative and editorial responsibilities. The BIP Editors monitor BIP
changes, and update BIP headers as appropriate.
BIP Editors may also, at their option, unilaterally make and merge strictly editorial changes to BIPs, such as
correcting misspellings, mending grammar mistakes, fixing broken links, etc. as long as they do not change the meaning or conflict with the
original intent of the authors. Such a change must be recorded in the Changelog if it’s noteworthy per the criteria
mentioned in the [Changelog](#changelog) section.
## Backward Compatibility
### Changes from BIP 2
#### Workflow
- Status field values are reduced from nine to four:
- Deferred, Obsolete, Rejected, Replaced, and Withdrawn are gathered up into Closed.[^closed]
- Final and Active are collapsed into Deployed.
- Proposed is renamed to Complete.
- The remaining statuses are Draft, Complete, Deployed, and Closed.
- The comment system is abolished.[^comments]
- A BIP in Draft or Complete status may no longer be closed solely on grounds of not making progress for three years.[^rejection]
- A BIP in Draft status may be updated to Closed status if it appears to have stopped making progress for at least a
year and its authors do not assert within four weeks of being contacted that they intend to continue working on it.
- Complete BIPs can only be moved to Closed by its authors and may remain in Complete indefinitely.
- A Changelog section is introduced to track significant changes to BIPs after they have reached the Complete status.
- Process BIPs are living documents that do not ossify and may be modified indefinitely.
- Some judgment calls previously required from BIP Editors are reassigned either to the BIP authors or the repository’s
audience.
#### BIP Format
- The Standards Track type is superseded by the similar Specification type.[^standard-track]
- Many sections are declared optional; it is up to the authors and reviewers to judge whether all relevant topics have
been comprehensively addressed and which topics require a designated section to do so.
- "Other Implementations" sections are discouraged.[^OtherImplementations]
- Auxiliary files are only permitted in the corresponding BIP’s subdirectory, as no one used the alternative of labeling
them with the BIP number.
- Tracking of community consensus and adoption is out of scope for the BIPs repository, except to determine
whether a BIP is in active use for the move into or out of the Deployed status.
- The distinction between recommended and acceptable licenses was dropped.
- Most licenses that have not been used in the BIP process have been dropped from the list of acceptable licenses.
#### Preamble
- "Comments-URI" and "Comments-Summary" headers are dropped from the preamble.[^comments]
- The "Superseded-By" header is replaced with the "Proposed-Replacement" header.
- The "Post-History" header is replaced with the "Discussion" header.
- The optional "Version" header is introduced.
- The "Discussions-To" header is dropped, as it has never been used in any BIP.
- The "License-Code" header has been sunset, as it was used by only five BIPs (98, 116, 117, 330, 340) and created more ambiguity than clarity.
- The "Created" header is renamed to "Assigned", as the header’s value is the date of number assignment.[^assigned]
- Introduce Deputies and optional "Deputies" header.
- The BIP "Title" header may now contain up to 50 characters (increased from 44 in BIP 2).
- The "Layer" header is optional for Specification BIPs or Informational BIPs, as it does not make sense for all BIPs.[^layer]
- Rename the "Author" field to "Authors".
### Updates to Existing BIPs should this BIP be Activated
#### Previous BIP Process
This BIP replaces BIP 2 as the guideline for the BIP process.
#### BIP Types
Standards Track BIPs and eligible Informational BIPs are assigned the Specification type. The Standards Track type is
considered obsolete. Specification BIPs use the Layer header rules specified in [BIP 123](bip-0123.mediawiki).
#### Comments
The Comments-URI and Comments-Summary headers should be removed from all BIPs whose comment page in the wiki is empty.
For existing BIPs whose comment page has content, BIP Authors may keep both headers or remove both headers at their
discretion. It is recommended that existing wiki pages are not modified due to the activation of this BIP.
#### Status Field
After the activation of this BIP, the Status fields of existing BIPs that do not fit the specification in this BIP are
updated to the corresponding values prescribed in this BIP. BIPs that have had Draft status for extended periods will be
moved to Complete or Deployed as applicable in collaboration with their authors. The authors of incomplete Draft BIPs
will be contacted to learn whether the BIPs are still in progress toward Complete, and will otherwise be updated to
Closed as described in the [Workflow](#workflow) section above.
#### Authors Header
The Author header is replaced with the Authors header in all BIPs.
#### Discussion Header
The Post-History header is replaced with the Discussion header in all BIPs.
#### Proposed-Replacement Header
The Superseded-By header is replaced with the Proposed-Replacement header in all BIPs.
#### Licenses
Existing BIPs retain their license terms unchanged.
The License and License-Code headers of BIPs are updated to express those terms using SPDX License Expressions.
## Changelog
* __1.4.0__ (2025-12-09):
* Revert AI guidance, add Changelog section, broaden reference implementation formats, move Type header responsibility to authors, other editorial changes
* __1.3.1__ (2025-11-10):
* Reiterate that numbers are assigned by BIP Editors in pull requests
* __1.3.0__ (2025-10-22):
* Restrict use of AI/LLM tools, require original work.
* __1.2.1__ (2025-09-19):
* Clarify that idea should be discussed on dedicated mailing list thread
* __1.2.0__ (2025-09-19):
* Rename Created header to Assigned to clarify that it holds the date of number assignment
* __1.1.0__ (2025-07-18):
* Switch to SPDX License Expressions, drop License-Code header, and make editorial changes to BIP Licensing section.
* __1.0.1__ (2025-06-27):
* Improve description of acceptance, purpose of the BIPs repository, when Draft BIPs can be closed due to not
making progress, and make other minor improvements to phrasing.
* __1.0.0__ (2025-03-18):
* Complete planned work and move to Proposed.
## Copyright
This BIP is licensed under the [BSD-2-Clause License](https://opensource.org/licenses/BSD-2-Clause). Some content was
adapted from [BIP 2](bip-0002.mediawiki) which was also licensed under the BSD-2-Clause.
## Related Work
- [BIP 1: BIP Purpose and Guidelines](bip-0001.mediawiki)
- [BIP 2: BIP Process, revised](bip-0002.mediawiki)
- [BIP 123: BIP Classification](bip-0123.mediawiki)
- [RFC 822: Standard for ARPA Internet Text Messages](https://datatracker.ietf.org/doc/html/rfc822)
- [RFC 2223: Instructions to RFC Authors](https://datatracker.ietf.org/doc/html/rfc2223)
- [RFC 7282: On Consensus and Humming in the IETF](https://tools.ietf.org/html/rfc7282)
## Acknowledgements
We thank AJ Towns, Jon Atack, Jonas Nick, Larry Ruane, Pieter Wuille, Tim Ruffing, and others for their review,
feedback, and helpful comments.
## Rationale
[^assigned]: **Why was the Created header renamed to Assigned?**
Both BIP 1 and BIP 2 described the Created header as "date created on" in the preamble template, but followed that
up with "Created header records the date that the BIP was assigned a number" as the description of the field. This
has frequently led to confusion, with authors using the date of opening the pull request, the date they started
writing their proposal, the date of number assignment (as prescribed), or various other dates. Aligning the name of
the header and the text in the preamble template with the descriptions will reduce the confusion.
[^standard-track]: **Why was the Specification type introduced?**
The definitions of Informational and Standards Track BIPs caused some confusion in the past. Due to Informational
BIPs being described as optional, Standards Track BIPs were sometimes misunderstood to be generally recommended.
This has led to a number of BIPs that propose new features affecting interoperability of implementations being
assigned the Informational type. The situation is remedied by introducing a new _Specification BIP_ type that is
inclusive of any BIPs that can be implemented and affect interoperability of Bitcoin applications. Since all BIPs
are individual recommendations by the authors (even if some may eventually achieve endorsement by the majority of
the community), the prior reminder that Informational BIPs are optional is dropped.
[^comments]: **Why were comments, Comments-URI, and Comments-Summary removed from the process?**
The comments feature saw insignificant adoption. Few BIPs received any comments and barely any more than two with
only a handful of contributors commenting at all. This led to many situations in which one or two comments ended up
dominating the comment summary. While some of those comments may have been representative of broadly held opinions,
it also overstated the importance of individual comments directly in the Preamble of BIPs. As collecting feedback in
this accessible fashion failed, the new process puts the burden back on the audience to make their own evaluation.
[^layer]: **Why is the layer header now permitted for other BIP types?**
The layer header had already been used by many Informational BIPs, so the rule that it is only available to
Standards Track BIPs is dropped.
[^OtherImplementations]: **What is the issue with "Other Implementations" sections in BIPs?**
In the past, some BIPs had "Other Implementations" sections that caused frequent change requests to existing BIPs.
This put a burden on the BIP authors and BIP Editors, and frequently led to lingering pull requests due to the corresponding BIPs’
authors no longer participating in the process. Many of these alternative implementations eventually became
unmaintained or were low-quality to begin with. Therefore, "Other Implementations" sections are heavily discouraged.
[^complete]: **Why was the Proposed status renamed to Complete?**
Some reviewers of this BIP raised that in a process which outlines the workflow of Bitcoin Improvement _Proposals_
using "Proposed" as a status field value was overloading the term: clearly _proposals_ are proposed at all stages of
the process. "Complete" expresses that the authors have concluded planned work on all parts of the proposal and are
ready to recommend their BIP for adoption. The term "ready" was also considered, but considered too subjective.
[^rejection]: **Why can proposals remain in Draft or Complete indefinitely?**
The automatic 3-year timeout of BIPs has led to some disagreement in the past and seems unnecessary in cases where
the authors remain active in the community and still consider their idea worth pursuing. On the other hand,
Draft proposals that appear stale may be closed after only one year, which should achieve the main goal of
the original rule by limiting the effort and attention spent on proposals that never reach Complete.
[^closed]: **Why was the Closed Status introduced?**
The Closed Status provides value to the audience by indicating which documents are only of historical significance.
Previously, the process had Deferred, Obsolete, Rejected, Replaced, and Withdrawn, which all meant some flavor of
"work has stopped on this." The many statuses complicated the process, may have contributed to process fatigue, and
may have resulted in BIPs’ statuses not being maintained well. The author of this BIP feels that all of the
aforementioned can be represented by _Closed_ without significantly impacting the information quality of the
overview table. Where the many Status variants provided minuscule additional information, the simplification is more
valuable and the Changelog section now collects specific details.
[^acceptance]: **When is a BIP "accepted"?**
Many standards processes such as the PEPs or the IETF have a mechanism for a proposal to be formally accepted by
some council or committee. The BIP Process does not have such a decision body. Bitcoin development and "acceptance"
of BIPs emerges from the participation of stakeholders across the ecosystem, and refers to some vague notion of community
interest and support for a proposal.
BIP 2 had made an attempt to gather community feedback into comment summaries in BIPs directly. Given the low
participation and corresponding low information quality of the summaries that resulted from that feature, this BIP
instead intends to leave the evaluation of BIPs to the reviewers and users.
[^adoption]: **Why does the BIPs repository no longer track adoption?**
In the past, some BIPs maintained lists of projects that had implemented the BIP. These lists generated
noise for subscribers of the repository, often listed implementations of questionable quality, and quickly
grew outdated, therefore providing little value. The repository no longer tracks which projects have implemented
BIPs. Instead, it is recommended that projects publish a list of the BIPs they implement.
[^markdown]: **Which flavor of Markdown is allowed?**
The author of this proposal has no opinion on Markdown flavors, but recommends that proposals stick to the basic
Markdown syntax features commonly shared across Markdown dialects.
[^living-documents]: **Why are Process BIPs living documents?**
In the past years, the existing BIPs process has not always provided a clear approach to all situations. For
example, the content of BIP 2 appears to have been penned especially with fork proposals in mind. It seems clear
that Bitcoin development will evolve in many surprising ways in the future. Instead of mandating the effort of
writing a new process document every time new situations arise, it seems preferable to allow the process to adapt to
the concerns of the future in specific aspects. Therefore, Process BIPs are defined as living documents that remain
open to amendment. If a Process BIP requires large modifications or even a complete overhaul, a new BIP should be
preferred.
[^new-BIP]: **Why should the specification of an implemented BIP no longer be changed?**
After a Complete or Deployed BIP has been deployed by one or more implementations, breaking changes to the
specification could lead to a situation where multiple "compliant" implementations fail at being interoperable,
because they implemented different versions of the same BIP. Therefore, even changes to the specification of
Complete BIPs should be avoided, but Deployed BIPs should never be subject to breaking changes to their
specification.
[^bip-announcements-to-list]: **Why are some BIP status changes announced to the mailing list?**
The BIPs repository does not and cannot track who might be interested in or has deployed a BIP. While concerns were
raised that making announcements to the Bitcoin Developer Mailing List would introduce unnecessary noise, our
rationale is that 1) moving Complete and Deployed BIPs to the Closed status will be a rare occurrence, 2) status
updates will usually not generate a lot of discussion, 3) while the mailing list should preferably only used for
getting review for new BIPs, it is the only channel available to us that can be considered a public announcement to
the audience of the BIPs repository: even if the authors, implementers, or other parties interested in a BIP do not
see the announcement themselves, they may be made aware by someone that does see it.
[^superseded-by-proposed-replacement]: **Why is Superseded-By replaced with Proposed-Replacement?**
Reviewers asked who should get to decide whether a BIP is superseded in case of a disagreement among the authors of
the original BIP, the authors of the new BIP, the editors, or the community? This is addressed by making the
"Replaces" header part of the recommendation of the authors of the new document, and replacing the "Superseded-By"
header with the "Proposed-Replacement" header that lists any proposals that recommend replacing the original document.
[^proposes-to-replace]: **Why was "Replaces" retained instead of changing it to "Proposes-to-Replace"?**
When one BIP proposes to supersede another, it is on the original BIP where things get complicated. The BIP is an
author document, but depending on its progress through the workflow, it may meanwhile be co-owned by the community. Who may decide
whether the original document should endorse a potential replacement BIP? Is it the original authors, the authors of the new
proposal, the BIP Editors, some sort of community process, or a mix of all of the above?
On the new BIP these problems don’t exist in the same manner. As it is freshly written, it is wholly owned by its
authors. The community is not yet invested and the original BIP’s authors do not have a privileged role
in determining the content of the new BIP. The authors of the new BIP can unilaterally recommend that it be
considered a replacement for a prior BIP. From there, the community can evaluate the proposal and adopt or
reject it, thus establishing whether it is successful in superseding the original or not.
[^evidence]: **How is evidence for advancing to Deployed evaluated?**
Whether evidence is deemed convincing to move a BIP to Deployed is up to the BIP Editors and Bitcoin community.
Running a single instance of a personal fork of a software project might be rejected, while a small software project with
dozens of users may be sufficient. The main point of the Deployed status is to indicate that changes to the BIP
could negatively impact users of projects that have already implemented support.
[^licenses]: **Why were some licenses dropped?**
Among the 141 BIPs with licenses in the repository, only nine licenses have ever been used to license BIPs
(although, some BIPs were made available under more than one license) and only one license has been used to license
code:
Licenses used:
* BSD-2-Clause: 55
* PD: 42
* CC0-1.0: 23
* BSD-3-Clause: 19
* OPUBL-1.0: 5
* CC-BY-SA-4.0: 4
* FSFAP: 3
* MIT: 2
* CC-BY-4.0: 1
License-Code used (previous BIP2 format):
* BSD-2-Clause: 1
* CC0-1.0: 1
* MIT: 5
The following previously acceptable licenses were retained per request of reviewers, even though they have so far
never been used in the BIPs process:
* Apache-2.0: [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)
* BSL-1.0: [Boost Software License 1.0](https://www.boost.org/LICENSE_1_0.txt)
The following previously acceptable licenses have never been used in the BIPs Process and have been dropped:
* AGPL-3.0+: [GNU Affero General Public License (AGPL) 3](https://www.gnu.org/licenses/agpl-3.0.en.html)
* FDL-1.3: [GNU Free Documentation License 1.3](https://www.gnu.org/licenses/fdl-1.3.en.html)
* GPL-2.0+: [GNU General Public License (GPL) 2 or newer](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
* LGPL-2.1+: [GNU Lesser General Public License (LGPL) 2.1 or newer](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
Why are software licenses included?
* Some BIPs, in particular those concerning the consensus layer, may include literal code in the BIP itself which
may not be available under the license terms the authors wish to use for the BIP.
* The author of this BIP has been provided with a learned opinion indicating that software licenses are perfectly
acceptable for licensing "human code" i.e., text as well as Markdown or MediaWiki code.
Why is CC-BY-SA-4.0 no longer acceptable for new BIPs?
* Specification BIPs are required to have a Reference Implementation and Test Vectors to be advanced to Complete. As
the BIPs repository is aiming to make proposals easily adoptable, the intention is for the reference
implementation and test vectors to be as accessible as possible. Copyleft licenses may introduce friction here,
and therefore CC-BY-SA-4.0 (and the GPL-flavors) is no longer considered acceptable for new BIPs. As mentioned
above, existing BIPs will retain their original licensing.
Why are Open Publication License and Public Domain no longer acceptable for new BIPs?
* Public domain is not universally recognised as a legitimate action, thus it is inadvisable.
* The Open Publication License is generally regarded as obsolete, and not a license suitable for new publications.
================================================
FILE: bip-0008/assignments.mediawiki
================================================
==Deployments==
List of deployments.
State can be defined, active, failed. Dates are in UTC.
================================================
FILE: bip-0008/states.dot
================================================
digraph {
rankdir=TD;
node [style="rounded,filled,bold", shape=box, fixedsize=true, width=1.5, fontname="Arial"];
edge [weight = 100];
"DEFINED" -> "STARTED" [label="height >= start_height"];
"STARTED" -> "MUST_SIGNAL" [label="height + 2016 >= timeoutheight AND lockinontimeout"];
"STARTED" -> "FAILED" [label="height >= timeoutheight\nAND\nNOT lockinontimeout"];
"LOCKED_IN" -> "ACTIVE" [label="height >= minimum_activation_height"];
"LOCKED_IN":se -> "LOCKED_IN":ne [label="height < minimum_activation_height"];
"MUST_SIGNAL" -> "LOCKED_IN" [label="always"];
edge [weight = 1];
"STARTED" -> "LOCKED_IN" [label="height < timeoutheight\nAND\nthreshold reached"];
"FAILED" -> "LOCKED_IN" [style=invis];
"DEFINED":sw -> "DEFINED":nw;
"STARTED":sw -> "STARTED":nw;
"ACTIVE":sw -> "ACTIVE":nw;
"FAILED":sw -> "FAILED":nw;
"STARTED" [fillcolor="#a0a0ff"];
"MUST_SIGNAL" [fillcolor="#a0a0ff"];
"LOCKED_IN" [fillcolor="#ffffa0"];
"ACTIVE" [fillcolor="#a0ffa0"];
"FAILED" [fillcolor="#ffa0a0"];
{ rank=same; "STARTED" "MUST_SIGNAL" }
{ rank=same; "FAILED" "LOCKED_IN" }
{ rank=sink; "ACTIVE" }
}
================================================
FILE: bip-0008.mediawiki
================================================
BIP: 8
Title: Version bits with lock-in by height
Authors: Shaolin Fry
Luke Dashjr
Status: Draft
Type: Informational
Assigned: 2017-02-01
License: BSD-3-Clause OR CC0-1.0
==Abstract==
This document specifies an alternative to [[bip-0009.mediawiki|BIP9]] that corrects for a number of perceived mistakes.
Block heights are used for start and timeout rather than POSIX timestamps.
It additionally introduces an activation parameter that can guarantee activation of backward-compatible changes (further called "soft forks").
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
==Motivation==
BIP9 introduced a mechanism for doing parallel soft forking deployments based on repurposing the block nVersion field. Activation is dependent on near unanimous hashrate signalling which may be impractical and result in veto by a small minority of non-signalling hashrate. Super majority hashrate based activation triggers allow for accelerated activation where the majority hash power enforces the new rules in lieu of full nodes upgrading. Since all consensus rules are ultimately enforced by full nodes, eventually any new soft fork will be enforced by the economy. This proposal combines these two aspects to provide optional flag day activation after a reasonable time, as well as for accelerated activation by majority of hash rate before the flag date.
Due to using timestamps rather than block heights, it was found to be a risk that a sudden loss of significant hashrate could interfere with a late activation.
Block time is somewhat unreliable and may be intentionally or unintentionally inaccurate, so thresholds based on block time are not ideal. Secondly, BIP9 specified triggers based on the first retarget after a given time, which is non-intuitive. Since each new block must increase the height by one, thresholds based on block height are much more reliable and intuitive and can be calculated exactly for difficulty retarget.
==Specification==
===Parameters===
Each soft fork deployment is specified by the following per-chain parameters (further elaborated below):
# The '''name''' specifies a very brief description of the soft fork, reasonable for use as an identifier.
# The '''bit''' determines which bit in the nVersion field of the block is to be used to signal the soft fork lock-in and activation. It is chosen from the set {0,1,2,...,28}.
# The '''startheight''' specifies the height of the first block at which the bit gains its meaning.
# The '''timeoutheight''' specifies a block height at which the miner signalling ends. Once this height has been reached, if the soft fork has not yet locked in (excluding this block's bit state), the deployment is considered failed on all descendants of the block.
# The '''threshold''' specifies the minimum number of block per retarget period which indicate lock-in of the soft fork during the subsequent period.
# The '''minimum_activation_height''' specifies the height of the first block at which the soft fork is allowed to become active.
# The '''lockinontimeout''' boolean if set to true, blocks are required to signal in the final period, ensuring the soft fork has locked in by timeoutheight.
===Selection guidelines===
The following guidelines are suggested for selecting these parameters for a soft fork:
# '''name''' should be selected such that no two softforks, concurrent or otherwise, ever use the same name. For deployments described in a single BIP, it is recommended to use the name "bipN" where N is the appropriate BIP number.
# '''bit''' should be selected such that no two concurrent softforks use the same bit. The bit chosen should not overlap with active usage (legitimately or otherwise) for other purposes.
# '''startheight''' should be set to some block height in the future. If '''minimum_activation_height''' is not going to be set, then '''startheight''' should be set to a height when a majority of economic activity is expected to have upgraded to software including the activation parameters. Some allowance should be made for potential release delays. If '''minimum_activation_height''' is going to be set, then '''startheight''' can be set to be soon after software with parameters is expected to be released. This shifts the time for upgrading from before signaling begins to during the LOCKED_IN state.
# '''timeoutheight''' should be set to a block height when it is considered reasonable to expect the entire economy to have upgraded by, probably at least 1 year, or 52416 blocks (26 retarget intervals) after '''startheight'''.
# '''threshold''' should be 1815 blocks (90% of 2016), or 1512 (75%) for testnet.
# '''minimum_activation_height''' should be set to several retarget periods in the future if the '''startheight''' is to be very soon after software with parameters is expected to be released. '''minimum_activation_height''' should be set to a height when a majority of economic activity is expected to have upgraded to software including the activation parameters. This allows more time to be spent in the LOCKED_IN state so that nodes can upgrade. This may be set to 0 to have the LOCKED_IN state be a single retarget period.
# '''lockinontimeout''' should be set to true for any softfork that is expected or found to have political opposition from a non-negligible percent of miners. (It can be set after the initial deployment, but cannot be cleared once set.)
A later deployment using the same bit is possible as long as the startheight is after the previous one's
timeoutheight or activation, but it is discouraged until necessary, and even then recommended to have a pause in between to detect buggy software.
'''startheight''', '''timeoutheight''', and '''minimum_activation_height''' must be an exact multiple of 2016 (ie, at a retarget boundary), and '''timeoutheight''' must be at least 4032 blocks (2 retarget intervals) after '''startheight'''.
===States===
With each block and soft fork, we associate a deployment state. The possible states are:
# '''DEFINED''' is the first state that each soft fork starts out as. The genesis block is by definition in this state for each deployment.
# '''STARTED''' for blocks at or beyond the startheight.
# '''MUST_SIGNAL''' for one retarget period prior to the timeout, if LOCKED_IN was not reached and '''lockinontimeout''' is true.
# '''LOCKED_IN''' for at least one retarget period after the first retarget period with STARTED (or MUST_SIGNAL) blocks of which at least threshold have the associated bit set in nVersion. A soft fork remains in LOCKED_IN until at least '''minimum_activation_height''' is reached.
# '''ACTIVE''' for all blocks after the LOCKED_IN state.
# '''FAILED''' for all blocks after the timeoutheight if LOCKED_IN is not reached.
===Bit flags===
The nVersion block header field is to be interpreted as a 32-bit little-endian integer (as present), and bits are selected within this integer as values (1 << N) where N is the bit number.
Blocks in the STARTED state get an nVersion whose bit position bit is set to 1. The top 3 bits of such blocks must be
001, so the range of actually possible nVersion values is [0x20000000...0x3FFFFFFF], inclusive.
Due to the constraints set by BIP 34, BIP 66 and BIP 65, we only have 0x7FFFFFFB possible nVersion values available.
This restricts us to at most 30 independent deployments. By restricting the top 3 bits to 001 we get 29 out of those
for the purposes of this proposal, and support two future upgrades for different mechanisms (top bits 010 and 011).
When a block nVersion does not have top bits 001, it is treated as if all
bits are 0 for the purposes of deployments.
Miners should continue setting the bit in LOCKED_IN phase so uptake is visible, though this has no effect on consensus rules.
===New consensus rules===
The new consensus rules for each soft fork are enforced for each block that has ACTIVE state.
During the MUST_SIGNAL phase, if '''(2016 - threshold)''' blocks in the retarget period have already failed to signal, any further blocks that fail to signal are invalid.
===State transitions===
Note that when '''lockinontimeout''' is true, the LOCKED_IN state will be reached no later than at a height of '''timeoutheight'''.
Regardless of the value of '''lockinontimeout''', if LOCKED_IN is reached, ACTIVE will be reached either one retarget period later, or at '''minimum_activation_height''', whichever comes later.
The genesis block has state DEFINED for each deployment, by definition.
State GetStateForBlock(block) {
if (block.height == 0) {
return DEFINED;
}
All blocks within a retarget period have the same state. This means that if
floor(block1.height / 2016) = floor(block2.height / 2016), they are guaranteed to have the same state for every
deployment.
if ((block.height % 2016) != 0) {
return GetStateForBlock(block.parent);
}
Otherwise, the next state depends on the previous state:
switch (GetStateForBlock(GetAncestorAtHeight(block, block.height - 2016))) {
We remain in the initial state until we reach the start block height.
case DEFINED:
if (block.height >= startheight) {
return STARTED;
}
return DEFINED;
After a period in the STARTED state, we tally the bits set,
and transition to LOCKED_IN if a sufficient number of blocks in the past period set the deployment bit in their
version numbers.
If the threshold hasn't been met, lockinontimeout is true, and we are at the last period before the timeout, then we transition to MUST_SIGNAL.
If the threshold hasn't been met and we reach the timeout, we transition directly to FAILED.
Note that a block's state never depends on its own nVersion; only on that of its ancestors.
case STARTED:
int count = 0;
walk = block;
for (i = 0; i < 2016; i++) {
walk = walk.parent;
if (walk.nVersion & 0xE0000000 == 0x20000000 && (walk.nVersion >> bit) & 1 == 1) {
++count;
}
}
if (count >= threshold) {
return LOCKED_IN;
} else if (lockinontimeout && block.height + 2016 >= timeoutheight) {
return MUST_SIGNAL;
} else if (block.height >= timeoutheight) {
return FAILED;
}
return STARTED;
If we have finished a period of MUST_SIGNAL, we transition directly to LOCKED_IN.
case MUST_SIGNAL:
return LOCKED_IN;
After at least one retarget period of LOCKED_IN, we automatically transition to ACTIVE if the minimum activation height is reached. Otherwise LOCKED_IN continues.
case LOCKED_IN:
if (block.height >= minimum_activation_height) {
return ACTIVE;
} else {
return LOCKED_IN;
}
And ACTIVE and FAILED are terminal states, which a deployment stays in once they're reached.
case ACTIVE:
return ACTIVE;
case FAILED:
return FAILED;
}
}
'''Implementation'''
It should be noted that the states are maintained along block chain
branches, but may need recomputation when a reorganization happens.
Given that the state for a specific block/deployment combination is completely determined by its ancestry before the
current retarget period (i.e. up to and including its ancestor with height block.height - 1 - (block.height % 2016)),
it is possible to implement the mechanism above efficiently and safely by caching the resulting state of every multiple-of-2016
block, indexed by its parent.
===Mandatory signalling===
Blocks received while in the MUST_SIGNAL phase must be checked to ensure that they signal as required. For example:
if (GetStateForBlock(block) == MUST_SIGNAL) {
int nonsignal = 0;
walk = block;
while (true) {
if ((walk.nVersion & 0xE0000000) != 0x20000000 || ((walk.nVersion >> bit) & 1) != 1) {
++nonsignal;
if (nonsignal > 2016 - threshold) {
return state.Invalid(BlockValidationResult::RECENT_CONSENSUS_CHANGE, "bad-version-bip8-must-signal");
}
}
if (walk.nHeight % 2016 == 0) {
// checked every block in this retarget period
break;
}
walk = walk.parent;
}
}
Implementations should be careful not to ban peers that send blocks that are invalid due to not signalling (or blocks that build on those blocks), as that would allow an incompatible chain that is only briefly longer than the compliant chain to cause a split of the p2p network. If that occurred, nodes that have not set ''lockinontimeout'' may not see new blocks in the compliant chain, and thus not reorg to it at the point when it has more work, and would thus not be following the valid chain with the most work.
Implementations with ''lockinontimeout'' set to true may potentially follow a lower work chain than nodes with ''lockinontimeout'' set to false for an extended period. In order for this not to result in a net split nodes with ''lockinontimeout'' set to true, those nodes may need to preferentially connect to each other. Deployments proposing that implementations set ''lockinontimeout'' to true should either use parameters that do not risk there being a higher work alternative chain, or specify a mechanism for implementations that support the deployment to preferentially peer with each other.
===Warning mechanism===
To support upgrade warnings, an extra "unknown upgrade" is tracked, using the "implicit bit" mask = (block.nVersion & ~expectedVersion) != 0. Mask will be non-zero whenever an unexpected bit is set in nVersion. Whenever LOCKED_IN for the unknown upgrade is detected, the software should warn loudly about the upcoming soft fork. It should warn even more loudly after the next retarget period (when the unknown upgrade is in the ACTIVE state).
===getblocktemplate changes===
The template request Object is extended to include a new item:
{| class="wikitable"
!colspan=4| template request
|-
! Key !! Required !! Type !! Description
|-
| rules || No || Array of Strings || list of supported softfork deployments, by name
|}
The template Object is also extended:
{| class="wikitable"
!colspan=4| template
|-
! Key !! Required !! Type !! Description
|-
| rules || Yes || Array of Strings || list of softfork deployments, by name, that are active state
|-
| vbavailable || Yes || Object || set of pending, supported softfork deployments; each uses the softfork name as the key, and the softfork bit as its value
|-
| vbrequired || No || Number || bit mask of softfork deployment version bits the server requires enabled in submissions
|}
The "version" key of the template is retained, and used to indicate the server's preference of deployments.
If versionbits is being used, "version" MUST be within the versionbits range of [0x20000000...0x3FFFFFFF].
Miners MAY clear or set bits in the block version WITHOUT any special "mutable" key, provided they are listed among the template's "vbavailable" and (when clearing is desired) NOT included as a bit in "vbrequired".
Servers MUST set bits in "vbrequired" for deployments in MUST_SIGNAL state, to ensure blocks produced are valid.
Softfork deployment names listed in "rules" or as keys in "vbavailable" may be prefixed by a '!' character.
Without this prefix, GBT clients may assume the rule will not impact usage of the template as-is; typical examples of this would be when previously valid transactions cease to be valid, such as BIPs 16, 65, 66, 68, 112, and 113.
If a client does not understand a rule without the prefix, it may use it unmodified for mining.
On the other hand, when this prefix is used, it indicates a more subtle change to the block structure or generation transaction; examples of this would be BIP 34 (because it modifies coinbase construction) and 141 (since it modifies the txid hashing and adds a commitment to the generation transaction).
A client that does not understand a rule prefixed by '!' must not attempt to process the template, and must not attempt to use it for mining even unmodified.
=== Reference implementation ===
https://github.com/bitcoin/bitcoin/compare/master...luke-jr:bip8
==Contrasted with BIP 9==
* The '''lockinontimeout''' flag is added, providing a way to guarantee transition to LOCKED_IN.
* Block heights are used for the deployment monotonic clock, rather than median-time-past.
==Backwards compatibility==
BIP8 and BIP9 deployments should not share concurrent active deployment bits. Nodes that only implement BIP9 will not activate a BIP8 soft fork if hashpower threshold is not reached by '''timeoutheight''', however, those nodes will still accept the blocks generated by activated nodes.
==Deployments==
A living list of deployment proposals can be found [[bip-0008/assignments.mediawiki|here]].
==References==
[[bip-0009.mediawiki|BIP9]]
[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-February/013643.html Mailing list discussion]
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0009/assignments.mediawiki
================================================
==Deployments==
List of proposed deployments.
State can be defined, active, failed. Dates are in UTC.
{| class="wikitable sortable"
! Name
! Bit
! Mainnet Start
! Mainnet Expire
! Mainnet State
! Testnet Start
! Testnet Expire
! Testnet State
! BIPs
|-
| csv
| 0
| 2016-05-01 00:00:00
| 2017-05-01 00:00:00
| active since #419328
| 2016-03-01 00:00:00
| 2017-05-01 00:00:00
| active since #770112
| [[/bip-0068.mediawiki|68]], [[/bip-0112.mediawiki|112]], [[/bip-0113.mediawiki|113]]
|-
| segwit
| 1
| 2016-11-15 00:00:00
| 2017-11-15 00:00:00
| active since #481824
| 2016-05-01 00:00:00
| 2017-05-01 00:00:00
| active since #834624
| [[/bip-0141.mediawiki|141]], [[/bip-0143.mediawiki|143]], [[/bip-0147.mediawiki|147]]
|}
================================================
FILE: bip-0009/states.gv
================================================
/* There are many ways to compile this, but one of them is:
*
* $ dot -Tpng states.gv -o states.png
*/
digraph {
/* States. */
DEFINED; FAILED; STARTED; LOCKED_IN; ACTIVE;
/* Relationships between states, labeled where applicable. */
DEFINED -> DEFINED;
DEFINED -> FAILED [label = "timeout ≤ MTP"];
DEFINED -> STARTED [label = "starttime ≤ MTP < timeout"];
FAILED -> FAILED;
STARTED -> STARTED;
STARTED -> FAILED [label = "timeout ≤ MTP"];
STARTED -> LOCKED_IN [label = "(MTP < timeout) AND (threshold reached)"];
LOCKED_IN -> ACTIVE [label = "Always"];
ACTIVE -> ACTIVE;
/* Visualization hack to unclutter output. */
nodesep = 1.2;
}
================================================
FILE: bip-0009.mediawiki
================================================
BIP: 9
Title: Version bits with timeout and delay
Authors: Pieter Wuille
Peter Todd
Greg Maxwell
Rusty Russell
Status: Deployed
Type: Informational
Assigned: 2015-10-04
License: PD
==Abstract==
This document specifies a proposed change to the semantics of the 'version' field in Bitcoin blocks, allowing multiple backward-compatible changes (further called "soft forks") to be deployed in parallel. It relies on interpreting the version field as a bit vector, where each bit can be used to track an independent change. These are tallied each retarget period. Once the consensus change succeeds or times out, there is a "fallow" pause after which the bit can be reused for later changes.
==Motivation==
[[bip-0034.mediawiki|BIP 34]] introduced a mechanism for doing soft-forking changes without a predefined flag timestamp (or flag block height), instead relying on measuring miner support indicated by a higher version number in block headers. As it relies on comparing version numbers as integers however, it only supports one single change being rolled out at once, requiring coordination between proposals, and does not allow for permanent rejection: as long as one soft fork is not fully rolled out, no future one can be scheduled.
In addition, BIP 34 made the integer comparison (nVersion >= 2) a consensus rule after its 95% threshold was reached, removing 231+2 values from the set of valid version numbers (all negative numbers, as nVersion is interpreted as a signed integer, as well as 0 and 1). This indicates another downside this approach: every upgrade permanently restricts the set of allowed nVersion field values. This approach was later reused in [[bip-0066.mediawiki|BIP 66]] and [[bip-0065.mediawiki|BIP 65]], which further removed nVersions 2 and 3 as valid options. As will be shown further, this is unnecessary.
==Specification==
Each soft fork deployment is specified by the following per-chain parameters (further elaborated below):
# The '''name''' specifies a very brief description of the soft fork, reasonable for use as an identifier. For deployments described in a single BIP, it is recommended to use the name "bipN" where N is the appropriate BIP number.
# The '''bit''' determines which bit in the nVersion field of the block is to be used to signal the soft fork lock-in and activation. It is chosen from the set {0,1,2,...,28}.
# The '''starttime''' specifies a minimum median time past of a block at which the bit gains its meaning.
# The '''timeout''' specifies a time at which the deployment is considered failed. If the median time past of a block >= timeout and the soft fork has not yet locked in (including this block's bit state), the deployment is considered failed on all descendants of the block.
===Selection guidelines===
The following guidelines are suggested for selecting these parameters for a soft fork:
# '''name''' should be selected such that no two softforks, concurrent or otherwise, ever use the same name.
# '''bit''' should be selected such that no two concurrent softforks use the same bit.
# '''starttime''' should be set to some date in the future, approximately one month after a software release date including the soft fork. This allows for some release delays, while preventing triggers as a result of parties running pre-release software.
# '''timeout''' should be 1 year (31536000 seconds) after starttime.
A later deployment using the same bit is possible as long as the starttime is after the previous one's
timeout or activation, but it is discouraged until necessary, and even then recommended to have a pause in between to detect buggy software.
===States===
With each block and soft fork, we associate a deployment state. The possible states are:
# '''DEFINED''' is the first state that each soft fork starts out as. The genesis block is by definition in this state for each deployment.
# '''STARTED''' for blocks past the starttime.
# '''LOCKED_IN''' for one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion.
# '''ACTIVE''' for all blocks after the LOCKED_IN retarget period.
# '''FAILED''' for one retarget period past the timeout time, if LOCKED_IN was not reached.
===Bit flags===
The nVersion block header field is to be interpreted as a 32-bit little-endian integer (as present), and bits are selected within this integer as values (1 << N) where N is the bit number.
Blocks in the STARTED state get an nVersion whose bit position bit is set to 1. The top 3 bits of such blocks must be
001, so the range of actually possible nVersion values is [0x20000000...0x3FFFFFFF], inclusive.
Due to the constraints set by BIP 34, BIP 66 and BIP 65, we only have 0x7FFFFFFB possible nVersion values available.
This restricts us to at most 30 independent deployments. By restricting the top 3 bits to 001 we get 29 out of those
for the purposes of this proposal, and support two future upgrades for different mechanisms (top bits 010 and 011).
When a block nVersion does not have top bits 001, it is treated as if all
bits are 0 for the purposes of deployments.
Miners should continue setting the bit in LOCKED_IN phase so uptake is visible, though this has no effect on
consensus rules.
===New consensus rules===
The new consensus rules for each soft fork are enforced for each block that has ACTIVE state.
===State transitions===
The genesis block has state DEFINED for each deployment, by definition.
State GetStateForBlock(block) {
if (block.height == 0) {
return DEFINED;
}
All blocks within a retarget period have the same state. This means that if
floor(block1.height / 2016) = floor(block2.height / 2016), they are guaranteed to have the same state for every
deployment.
if ((block.height % 2016) != 0) {
return GetStateForBlock(block.parent);
}
Otherwise, the next state depends on the previous state:
switch (GetStateForBlock(GetAncestorAtHeight(block, block.height - 2016))) {
We remain in the initial state until either we pass the start time or the timeout. GetMedianTimePast in the code below
refers to the median nTime of a block and its 10 predecessors. The expression GetMedianTimePast(block.parent) is
referred to as MTP in the diagram above, and is treated as a monotonic clock defined by the chain.
case DEFINED:
if (GetMedianTimePast(block.parent) >= timeout) {
return FAILED;
}
if (GetMedianTimePast(block.parent) >= starttime) {
return STARTED;
}
return DEFINED;
After a period in the STARTED state, if we're past the timeout, we switch to FAILED. If not, we tally the bits set,
and transition to LOCKED_IN if a sufficient number of blocks in the past period set the deployment bit in their
version numbers. The threshold is ≥1916 blocks (95% of 2016), or ≥1512 for testnet (75% of 2016).
The transition to FAILED takes precedence, as otherwise an ambiguity can arise.
There could be two non-overlapping deployments on the same bit, where the first one transitions to LOCKED_IN while the
other one simultaneously transitions to STARTED, which would mean both would demand setting the bit.
Note that a block's state never depends on its own nVersion; only on that of its ancestors.
case STARTED:
if (GetMedianTimePast(block.parent) >= timeout) {
return FAILED;
}
int count = 0;
walk = block;
for (i = 0; i < 2016; i++) {
walk = walk.parent;
if (walk.nVersion & 0xE0000000 == 0x20000000 && (walk.nVersion >> bit) & 1 == 1) {
count++;
}
}
if (count >= threshold) {
return LOCKED_IN;
}
return STARTED;
After a retarget period of LOCKED_IN, we automatically transition to ACTIVE.
case LOCKED_IN:
return ACTIVE;
And ACTIVE and FAILED are terminal states, which a deployment stays in once they're reached.
case ACTIVE:
return ACTIVE;
case FAILED:
return FAILED;
}
}
'''Implementation'''
It should be noted that the states are maintained along block chain
branches, but may need recomputation when a reorganization happens.
Given that the state for a specific block/deployment combination is completely determined by its ancestry before the
current retarget period (i.e. up to and including its ancestor with height block.height - 1 - (block.height % 2016)),
it is possible to implement the mechanism above efficiently and safely by caching the resulting state of every multiple-of-2016
block, indexed by its parent.
===Warning mechanism===
To support upgrade warnings, an extra "unknown upgrade" is tracked, using the "implicit bit" mask = (block.nVersion & ~expectedVersion) != 0. Mask will be non-zero whenever an unexpected bit is set in nVersion. Whenever LOCKED_IN for the unknown upgrade is detected, the software should warn loudly about the upcoming soft fork. It should warn even more loudly after the next retarget period (when the unknown upgrade is in the ACTIVE state).
===getblocktemplate changes===
The template request Object is extended to include a new item:
{| class="wikitable"
!colspan=4| template request
|-
! Key !! Required !! Type !! Description
|-
| rules || No || Array of Strings || list of supported softfork deployments, by name
|}
The template Object is also extended:
{| class="wikitable"
!colspan=4| template
|-
! Key !! Required !! Type !! Description
|-
| rules || Yes || Array of Strings || list of softfork deployments, by name, that are active state
|-
| vbavailable || Yes || Object || set of pending, supported softfork deployments; each uses the softfork name as the key, and the softfork bit as its value
|-
| vbrequired || No || Number || bit mask of softfork deployment version bits the server requires enabled in submissions
|}
The "version" key of the template is retained, and used to indicate the server's preference of deployments.
If versionbits is being used, "version" MUST be within the versionbits range of [0x20000000...0x3FFFFFFF].
Miners MAY clear or set bits in the block version WITHOUT any special "mutable" key, provided they are listed among the template's "vbavailable" and (when clearing is desired) NOT included as a bit in "vbrequired".
Softfork deployment names listed in "rules" or as keys in "vbavailable" may be prefixed by a '!' character.
Without this prefix, GBT clients may assume the rule will not impact usage of the template as-is; typical examples of this would be when previously valid transactions cease to be valid, such as BIPs [[bip-0016.mediawiki|16]], [[bip-0065.mediawiki|65]], [[bip-0066.mediawiki|66]], [[bip-0068.mediawiki|68]], [[bip-0112.mediawiki|112]], and [[bip-0113.mediawiki|113]].
If a client does not understand a rule without the prefix, it may use it unmodified for mining.
On the other hand, when this prefix is used, it indicates a more subtle change to the block structure or generation transaction; examples of this would be [[bip-0034.mediawiki|BIP 34]] (because it modifies coinbase construction) and [[bip-0141.mediawiki|141]] (since it modifies the txid hashing and adds a commitment to the generation transaction).
A client that does not understand a rule prefixed by '!' must not attempt to process the template, and must not attempt to use it for mining even unmodified.
==Support for future changes==
The mechanism described above is very generic, and variations are possible for future soft forks. Here are some ideas that can be taken into account.
'''Modified thresholds'''
The 1916 threshold (based on BIP 34's 95%) does not have to be maintained for eternity, but changes should take the effect on the warning system into account. In particular, having a lock-in threshold that is incompatible with the one used for the warning system may have long-term effects, as the warning system cannot rely on a permanently detectable condition anymore.
'''Conflicting soft forks'''
At some point, two mutually exclusive soft forks may be proposed. The naive way to deal with this is to never create software that implements both, but that is making a bet that at least one side is guaranteed to lose. Better would be to encode "soft fork X cannot be locked-in" as consensus rule for the conflicting soft fork - allowing software that supports both, but can never trigger conflicting changes.
'''Multi-stage soft forks'''
Soft forks right now are typically treated as booleans: they go from an inactive to an active state in blocks. Perhaps at some point there is demand for a change that has a larger number of stages, with additional validation rules that get enabled one by one. The above mechanism can be adapted to support this, by interpreting a combination of bits as an integer, rather than as isolated bits. The warning system is compatible with this, as (nVersion & ~nExpectedVersion) will always be non-zero for increasing integers.
== Rationale ==
The failure timeout allows eventual reuse of bits even if a soft fork was
never activated, so it's clear that the new use of the bit refers to a
new BIP. It's deliberately very coarse-grained, to take into account
reasonable development and deployment delays. There are unlikely to be
enough failed proposals to cause a bit shortage.
The fallow period at the conclusion of a soft fork attempt allows some
detection of buggy clients, and allows time for warnings and software
upgrades for successful soft forks.
==Deployments==
A living list of deployment proposals can be found [[bip-0009/assignments.mediawiki|here]].
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0010.mediawiki
================================================
BIP: 10
Layer: Applications
Title: Multi-Sig Transaction Distribution
Authors: Alan Reiner
Status: Closed
Type: Informational
Assigned: 2011-10-28
A multi-signature transaction is one where a certain number of Bitcoins are "encumbered" with more than one recipient address. The subsequent transaction that spends these coins will require each party involved (or some subset, depending on the script), to see the proposed transaction and sign it with their private key. This necessarily requires collaboration between all parties -- to propose a distribution of encumbered funds, collect signatures from all necessary participants, and then broadcast the completed transaction.
This BIP describes a way standardize the encoding of proposal transactions, to assist with signature collection and broadcast (which includes regular, 1-of-1 transactions requiring signatures from an offline computer). The goal is to encourage a standard that guarantees interoperability of all programs that implement it.
==Motivation==
The enabling of multi-signature transactions in Bitcoin will introduce a great deal of extra functionality to the users of the network, but also a great deal of extra complexity. Executing a multi-signature tx will be a multi-step process, and will potentially get worse with multiple clients, each implementing this process differently. By providing an efficient, standardized technique, we can improve the chance that developers will adopt compatible protocols and not bifurcate the user-base based on client selection.
In addition to providing a general encoding scheme for transaction signing/collection, it does not require the signing device to hold any blockchain information (all information needed for verification and signing is part of the encoding). This enables the existence of very lightweight devices that can be used for signing since they do not need the blockchain -- only a minimal set of Bitcoin tools and an ECDSA module. Therefore, BIP 0010 has benefit beyond just multi-signature transactions.
==Specification==
This BIP proposes the following process, with terms in quotes referring to recommended terminology that should be encouraged across all implementations.
# One party will initiate this process by creating a "Distribution Proposal", which could be abbreviated DP, or TxDP
# The user creating the TxDP (the preparer) will create the transaction as they would like to see it spent, but with blank TxIn scripts (where the signatures scripts will eventually go).
# The proposed transaction will be spending a set of unspent TxOuts available in the blockchain. The full transactions containing these TxOuts will be serialized and included, as well. This so that the values of the TxIns can be verified before signing (the prev-tx-hash is part of the data being signed, but the value is not). By including the full tx, the signing party can verify that the tx matches the OutPoint hash, and then verify input values, all without any access to the blockchain.
# The TxDP will have an "DP ID" or "Unsigned ID" which is the hash of the proposed transaction with blanked scripts, in Base58. This is a specific naming convention to make sure it is not confused with the actual transaction ID that it will have after it is broadcast (the transaction ID cannot be determined until after all signatures are collected). The final Tx ID can be referred to as its "Broadcast ID", in order to distinguish it from the pre-signed ID.
# The TxDP will have a potentially-unordered list of sig-pubkey pairs which represent collected signatures. If you receive a TxDP missing only your signature, you can broadcast it as soon as you sign it.
# Identical TxDP objects with different signatures can be easily combined. This allows one party to send out all the requests for signatures at once, and combine them all when they are received (instead of having to "pass it around".
# For cases where the TxDP might be put into a file or sent via email, it should use .txdp or .btcdp suffix
Anyone adopting BIP 0010 for multi-sig transactions will use the following format (without indentation):
The following is an example TxDP from Armory, produced while running on the test network. Its DPID is 3fX59xPj:
-----BEGIN-TRANSACTION-3fX59xPj-------------------------------------------------
_TXDIST_fabfb5da_3fX59xPj_00a0
010000000292807c8e70a28c687daea2998d6273d074e56fa8a55a0b10556974cf2b526e61000000
0000ffffffffe3c1ee0711611b01af3dee55b1484f0d6b65d17dce4eff0e6e06242e6cf457e10000
000000ffffffff02b0feea0b000000001976a91457996661391fa4e95bed27d7e8fe47f47cb8e428
88ac00a0acb9030000001976a914dc504e07b1107110f601fb679dd3f56cee9ff71e88ac00000000
0100000001eb626e4f73d88f415a8e8cb32b8d73eed47aa1039d0ed2f013abdc741ce6828c010000
008c493046022100b0da540e4924518f8989a9da798ca2d9e761b69a173b8cc41a3e3e3c6d77cd50
022100ecfa61730e58005338420516744ef680428dcfc05022dec70a851365c8575b190141042dc5
be3afa5887aee4a377032ed014361b0b9b61eb3ea6b8a8821bfe13ee4b65cd25d9630e4f227a53e8
bf637f85452c9981bcbd64ef77e22ce97b0f547c783effffffff0200d6117e030000001976a914cf
f580fd243f64f0ad7bf69faf41c0bf42d86d8988ac00205fa0120000001976a9148d573ef6984fd9
f8847d420001f7ac49b222a24988ac000000000100000001f2782db40ae147398a31cff9c7cc3423
014a073a92e463741244330cc304168f000000008c493046022100c9311b9eef0cc69219cb96838f
dd621530a80c46269a00dccc66498bc03ccf7a0221003742ee652a0a76fd28ad81aa73bb7f7a0a6a
81850af58f62d9a184d10e5eec30014104f815e8ef4cad584e04974889d7636e8933803d2e72991d
b5288c9e953c2465533905f98b7b688898c7c1f0708f2e49f0dd0abc06859ffed5144e8a1018a4e8
63ffffffff02008c8647000000001976a914d4e211215967f8e3744693bf85f47eb4ee9567fc88ac
603d4e95010000001976a914e9a6b50901c1969d2b0fd43a3ccfa3fef3291efe88ac00000000
_TXINPUT_00_150.00000000
_SIG_mzUYGfqGpyXmppYpmWJ31Y4zTxR4ZCod22_00_008c
4930460221007699967c3ec09d072599558d2e7082fae0820206b63aa66afea124634ed11a080221
0003346f7e963e645ecae2855026dc7332eb7237012539b34cd441c3cef97fbd4d01410497d5e1a0
0e1db90e893d1f2e547e2ee83b5d6bf4ddaa3d514e6dc2d94b6bcb5a72be1fcec766b8c382502caa
9ec09fe478bad07d3f38ff47b2eb42e681c384cc
_TXINPUT_01_12.00000000
_SIG_mzvaN8JUhHLz3Gdec1zBRxs5rNaYLQnbD1_01_008c
49304602210081554f8b08a1ad8caa69e34f4794d54952dac7c5efcf2afe080985d6bd5b00770221
00dea20ca3dbae1d15ec61bec57b4b8062e7d7c47614aba032c5a32f651f471cfd014104c30936d2
456298a566aa76fefeab8a7cb7a91e8a936a11757c911b4c669f0434d12ab0936fc13986b156156f
9b389ed244bbb580112be07dbe23949a4764dffb
-------END-TRANSACTION-3fX59xPj-------------------------------------------------
In this transaction, there are two inputs, one of 150 BTC and the other of 12 BTC. This transaction combines 162 BTC to create two outputs, one of 160 BTC, one 1.9995 BTC, and a tx fee of 0.0005. In this TxDP, both inputs have been signed, and thus could broadcast immediately.
The style of communication is taken directly from PGP/GPG, which uses blocks of ASCII like this to communicate encrypted messages and signatures. This serialization is compact, and will be interpreted the same in all character encodings. It can be copied inline into an email, or saved in a text file. The advantage over the analogous PGP encoding is that there are some human readable elements to it, for users that wish to examine the TxDP packet manually, instead of requiring a program to parse the core elements of the TxDP.
A party receiving this TxDP can simply add their signature to the appropriate _TXINPUT_ line. If that is the last signature required, they can broadcast it themselves. Any software that implements this standard should be able to combine multiple TxDPs into a single TxDP. However, even without the programmatic support, a user could manually combine them by copying the appropriate _SIG_ lines between serializations, though it is not the recommended method for combining TxDPs.
== Reference Implementation ==
This proposal was implemented and tested in the older versions of ''Armory'' Bitcoin software for use in offline-wallet transaction signing (as a 1-of-1 transaction). Implementation can be found in https://github.com/etotheipi/BitcoinArmory/blob/v0.91-beta/armoryengine/Transaction.py under the class PyTxDistProposal. However, as of version 0.92 released in July 2014, Armory no longer uses this proposal for offline wallet transaction signing and has moved on to a new format.
================================================
FILE: bip-0011.mediawiki
================================================
==Abstract==
This BIP proposes M-of-N-signatures required transactions as a new 'standard' transaction type.
==Motivation==
Enable secured wallets, escrow transactions, and other use cases where redeeming funds requires more than a single signature.
A couple of motivating use cases:
* A wallet secured by a "wallet protection service" (WPS). 2-of-2 signatures required transactions will be used, with one signature coming from the (possibly compromised) computer with the wallet and the second signature coming from the WPS. When sending protected bitcoins, the user's bitcoin client will contact the WPS with the proposed transaction and it can then contact the user for confirmation that they initiated the transaction and that the transaction details are correct. Details for how clients and WPS's communicate are outside the scope of this BIP. Side note: customers should insist that their wallet protection service provide them with copies of the private key(s) used to secure their wallets that they can safely store off-line, so that their coins can be spent even if the WPS goes out of business.
* Three-party escrow (buyer, seller, and trusted dispute agent). 2-of-3 signatures required transactions will be used. The buyer and seller and agent will each provide a public key, and the buyer will then send coins into a 2-of-3 CHECKMULTISIG transaction and send the seller and the agent the transaction id. The seller will fulfill their obligation and then ask the buyer to co-sign a transaction ( already signed by seller ) that sends the tied-up coins to him (seller). If the buyer and seller cannot agree, then the agent can, with the cooperation of either buyer or seller, decide what happens to the tied-up coins. Details of how buyer, seller, and agent communicate to gather signatures or public keys are outside the scope of this BIP.
==Specification==
A new standard transaction type (scriptPubKey) that is relayed by clients and included in mined blocks:
m {pubkey}...{pubkey} n OP_CHECKMULTISIG
But only for n less than or equal to 3.
OP_CHECKMULTISIG transactions are redeemed using a standard scriptSig:
OP_0 ...signatures...
(OP_0 is required because of a bug in OP_CHECKMULTISIG; it pops one too many items off the execution stack, so a dummy value must be placed on the stack).
The current Satoshi bitcoin client does not relay or mine transactions with scriptSigs larger than 200 bytes; to accommodate 3-signature transactions, this will be increased to 500 bytes.
==Rationale==
OP_CHECKMULTISIG is already an enabled opcode, and is the most straightforward way to support several important use cases.
One argument against using OP_CHECKMULTISIG is that old clients and miners count it as "20 sigops" for purposes of computing how many signature operations are in a block, and there is a hard limit of 20,000 sigops per block-- meaning a maximum of 1,000 multisig transactions per block. Creating multisig transactions using multiple OP_CHECKSIG operations allows more of them per block.
The counter-argument is that these new multi-signature transactions will be used in combination with OP_EVAL (see the OP_EVAL BIP), and '''will''' be counted accurately. And in any case, as transaction volume rises the hard-coded maximum block size will have to be addressed, and the rules for counting number-of-signature-operations-in-a-block can be addressed at that time.
A weaker argument is OP_CHECKMULTISIG should not be used because it pops one too many items off the stack during validation. Adding an extra OP_0 placeholder to the scriptSig adds only 1 byte to the transaction, and any alternative that avoids OP_CHECKMULTISIG adds at least several bytes of opcodes.
==Implementation==
OP_CHECKMULTISIG is already supported by old clients and miners as a non-standard transaction type.
https://github.com/gavinandresen/bitcoin-git/tree/77f21f1583deb89bf3fffe80fe9b181fedb1dd60
== Post History ==
* [https://bitcointalk.org/index.php?topic=46538 OP_EVAL proposal]
================================================
FILE: bip-0012.mediawiki
================================================
==Abstract==
This BIP describes a new opcode (OP_EVAL) for the [https://en.bitcoin.it/wiki/Script Bitcoin scripting system], and a new 'standard' transaction type that uses it to enables the receiver of bitcoins to specify the transaction type needed to re-spend them.
==Motivation==
Enable "end-to-end" secure wallets and payments to fund escrow transactions or other complex transactions in a way that is backwards-compatible for old clients and miners.
==Specification==
OP_EVAL will re-define the existing OP_NOP1 opcode, and will function as follows:
* When executed during transaction verification, pops the item from the top of the stack, deserializes it, and executes the resulting script.
* If there is no item on the top of the stack or the item is not a valid script then transaction validation fails.
* If there are any OP_CODESEPARATORs in the deserialized script then transaction validation fails.
* If there are any OP_EVALs in the deserialized script they are also executed, but recursion is limited to a depth of 2.
* Transaction verification must fail if interpreting OP_EVAL as a no-op would cause the verification to fail.
A new standard transaction type (scriptPubKey) that is relayed by clients and included in mined blocks is also defined:
DUP HASH160 {20-byte-hash-value} EQUALVERIFY OP_EVAL
Which is redeemed by a standard scriptSig:
...signatures... {serialized script}
Transactions that redeem standard OP_EVAL scriptPubKeys are only considered standard if the ''serialized script'' is, itself, one of the standard transaction types.
==Rationale==
OP_EVAL allows the receiver of bitcoins to specify how they can be spent when they are spent, instead of requiring the sender of the bitcoins to know the details of how the bitcoins may be redeemed. The sender only needs to know the hash of the ''serialized script'', and one new type of bitcoin address can be used to fund arbitrarily complex transactions.
If ''serialized script'' is a large or complicated multi-signature script, then the burden of paying for it (in increased transaction fees due to more signature operations or transaction size) is shifted from the sender to the receiver.
The main objection to OP_EVAL is that it adds complexity, and complexity is the enemy of security. Also, evaluating data as code has a long record of being a source of security vulnerabilities.
That same argument can be applied to the existing Bitcoin 'scripting' system; scriptPubKeys are transmit as data across the network and are then interpreted by every bitcoin implementation. OP_EVAL just moves the data that will be interpreted. It is debatable whether or not the entire idea of putting a little interpreted expression evaluation language at the core of Bitcoin was brilliant or stupid, but the existence of OP_EVAL does not make the expression language less secure.
There is a 1-confirmation attack on old clients that interpret OP_EVAL as a no-op, but it is expensive and difficult in practice. The attack is:
# Attacker creates an OP_EVAL transaction that is valid as seen by old clients, but invalid for new clients.
# Attacker also creates a standard transaction that spends the OP_EVAL transaction, and pays the victim.
# Attacker manages to mine a block that contains both transactions. If the victim accepts the 1-confirmation payment, then the attacker wins because both transactions will be invalidated when the rest of the network overwrites the attacker's invalid block.
The attack is expensive because it requires the attacker create a block that they know will be invalidated. It is difficult because bitcoin businesses should not accept 1-confirmation transactions for higher-value transactions.
==Backwards Compatibility==
Surprisingly, because OP_EVAL redefines the OP_NOP1 opcode, standard OP_EVAL transactions will validate with old clients and miners. They will check only that the ''serialized script'' hashes to the correct value; the OP_EVAL will be interpreted as a no-op, and as long as the hash is correct the transaction will be considered valid (no signature checking will be done by old clients and miners).
Old clients will ignore OP_EVAL transactions and transactions that depend on them until they are put into a block by either an old miner that includes non-standard transactions in its blocks or by a new miner.
Avoiding a block-chain split by malicious OP_EVAL transactions requires careful handling of two cases:
# An OP_EVAL transaction that is invalid for new clients/miners but valid for old clients/miners.
# An OP_EVAL transaction that is valid for new clients/miners but invalid for old clients/miners.
For case (1), new clients and miners will be coded to interpret OP_EVAL as a no-op until February 1, 2012. Before then, miners will be asked to put the string "OP_EVAL" in blocks that they produce so that hashing power that supports the new opcode can be gauged. If less than 50% of miners accept the change as of January 15, 2012 the rollout will be postponed until more than 50% of hashing power supports OP_EVAL (the rollout will be rejected if it becomes clear that a majority of hashing power will not be achieved).
For case (2), new clients and miners will be written to make sure that transactions involving OP_EVAL are valid if OP_EVAL is interpreted as a no-op.
Example of a transaction that must fail for both old and new miners/clients:
scriptSig: {serialized OP_11}
scriptPubKey: OP_EVAL OP_11 OP_EQUAL
==Reference Implementation==
https://github.com/gavinandresen/bitcoin-git/tree/77f21f1583deb89bf3fffe80fe9b181fedb1dd60
==See Also==
https://bitcointalk.org/index.php?topic=46538
"Bitcoin Address 01" BIP
M-of-N Multisignature Transactions BIP 11
================================================
FILE: bip-0013.mediawiki
================================================
BIP: 13
Layer: Applications
Title: Address Format for pay-to-script-hash
Authors: Gavin Andresen
Status: Deployed
Type: Specification
Assigned: 2011-10-18
==Abstract==
This BIP describes a new type of Bitcoin address to support arbitrarily complex transactions. Complexity in this context is defined as what information is needed by the recipient to respend the received coins, in contrast to needing a single ECDSA private key as in current implementations of Bitcoin.
In essence, an address encoded under this proposal represents the encoded hash of a [https://en.bitcoin.it/wiki/Script script], rather than the encoded hash of an ECDSA public key.
==Motivation==
Enable "end-to-end" secure wallets and payments to fund escrow transactions or other complex transactions. Enable third-party wallet security services.
==Specification==
The new bitcoin address type is constructed in the same manner as existing bitcoin addresses (see [https://en.bitcoin.it/Base58Check_encoding Base58Check encoding]):
base58-encode: [one-byte version][20-byte hash][4-byte checksum]
Version byte is 5 for a main-network address, 196 for a testnet address.
The 20-byte hash is the hash of the script that will be used to redeem the coins.
And the 4-byte checksum is the first four bytes of the double SHA256 hash of the version and hash.
==Rationale==
One criticism is that bitcoin addresses should be deprecated in favor of a more user-friendly mechanism for payments, and that this will just encourage continued use of a poorly designed mechanism.
Another criticism is that bitcoin addresses are inherently insecure because there is no identity information tied to them; if you only have a bitcoin address, how can you be certain that you're paying who or what you think you're paying?
Furthermore, truncating SHA256 is not an optimal checksum; there are much better error-detecting algorithms. If we are introducing a new form of Bitcoin address, then perhaps a better algorithm should be used.
This is one piece of the simplest path to a more secure bitcoin infrastructure. It is not intended to solve all of bitcoin's usability or security issues, but to be an incremental improvement over what exists today. A future BIP or BIPs should propose more user-friendly mechanisms for making payments, or for verifying that you're sending a payment to the Free Software Foundation and not Joe Random Hacker.
Assuming that typing in bitcoin addresses manually will become increasingly rare in the future, and given that the existing checksum method for bitcoin addresses seems to work "well enough" in practice and has already been implemented multiple times, the Author believes no change to the checksum algorithm is necessary.
The leading version bytes are chosen so that, after base58 encoding, the leading character is consistent: for the main network, byte 5 becomes the character '3'. For the testnet, byte 196 is encoded into '2'.
==Backwards Compatibility==
This proposal is not backwards compatible, but it fails gracefully-- if an older implementation is given one of these new bitcoin addresses, it will report the address as invalid and will refuse to create a transaction.
==Reference Implementation==
See base58.cpp/base58.h at https://github.com/bitcoin/bitcoin/tree/master/src
==See Also==
* [[bip-0012.mediawiki|BIP 12: OP_EVAL, the original P2SH design]]
* [[bip-0016.mediawiki|BIP 16: Pay to Script Hash (aka "/P2SH/")]]
* [[bip-0017.mediawiki|BIP 17: OP_CHECKHASHVERIFY, another P2SH design]]
================================================
FILE: bip-0014.mediawiki
================================================
BIP: 14
Layer: Peer Services
Title: Protocol Version and User Agent
Authors: Amir Taaki
Patrick Strateman
Status: Deployed
Type: Specification
Assigned: 2011-11-10
Discussion: 2011-11-02: https://gnusha.org/pi/bitcoindev/1320268981.72296.YahooMailNeo@web121003.mail.ne1.yahoo.com/
2011-11-10: https://gnusha.org/pi/bitcoindev/1320959761.36702.YahooMailNeo@web121014.mail.ne1.yahoo.com/
In this document, bitcoin will be used to refer to the protocol while Satoshi will refer to the current client in order to prevent confusion.
== Past Situation ==
Bitcoin as a protocol began life with the Satoshi client. Now that the community is diversifying, a number of alternative clients with their own codebases written in a variety of languages (Java, Python, Javascript, C++) are rapidly developing their own feature-sets.
Embedded in the protocol is a version number. Primarily this version number is in the "version" and "getblocks" messages, but is also in the "block" message to indicate the software version that created that block. Currently this version number is the same version number as that of the client. This document is a proposal to separate the protocol version from the client version, together with a proposed method to do so.
== Rationale ==
With non-separated version numbers, every release of the Satoshi client will increase its internal version number. Primarily this holds every other client hostage to a game of catch-up with Satoshi version number schemes. This plays against the decentralised nature of bitcoin, by forcing every software release to remain in step with the release schedule of one group of bitcoin developers.
Version bumping can also introduce incompatibilities and fracture the network. In order that the health of the network is maintained, the development of the protocol as a shared common collaborative process requires being split off from the implementation of that protocol. Neutral third entities to guide the protocol with representatives from all groups, present the chance for bitcoin to grow in a positive manner with minimal risks.
By using a protocol version, we set all implementations on the network to a common standard. Everybody is able to agree within their confines what is protocol and what is implementation-dependent. A user agent string is offered as a 'vanity-plate' for clients to distinguish themselves in the network.
Separation of the network protocol from the implementation, and forming development of said protocol by means of a mutual consensus among participants, has the democratic disadvantage when agreement is hard to reach on contentious issues. To mitigate this issue, strong communication channels and fast release schedules are needed, and are outside the scope of this document (concerning a process-BIP type).
User agents provide extra tracking information that is useful for keeping tabs on network data such as client implementations used or common architectures/operating-systems. In the rare case they may even provide an emergency method of shunning faulty clients that threaten network health- although this is strongly unrecommended and extremely bad form. The user agent does not provide a method for clients to work around and behave differently to different implementations, as this will lead to protocol fracturing.
In short:
* Protocol version: way to distinguish between nodes and behave different accordingly.
* User agent: simple informational tool. Protocol should not be modified depending on user agent.
== Browser User-Agents ==
[http://tools.ietf.org/html/rfc1945 RFC 1945] vaguely specifies a user agent to be a string of the product with optional comments.
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.6) Gecko/20100127 Gentoo Shiretoko/3.5.6
User agents are most often parsed by computers more than humans. The space delimited format, does not provide an easy, fast or efficient way for parsing. The data contains no structure indicating hierarchy in this placement.
The most immediate pieces of information there are the browser product, rendering engine and the build (Gentoo Shiretoko) together with version number. Various other pieces of information as included as comments such as desktop environment, platform, language and revision number of the build.
== Proposal ==
The version field in "version" and "getblocks" packets will become the protocol version number. The version number in the "blocks" reflects the protocol version from when that block was created.
The currently unused sub_version_num field in "version" packets will become the new user-agent string.
Bitcoin user agents are a modified browser user agent with more structure to aid parsers and provide some coherence. In bitcoin, the software usually works like a stack starting from the core code-base up to the end graphical interface. Therefore the user agent strings codify this relationship.
Basic format:
/Name:Version/Name:Version/.../
Example:
/Satoshi:5.64/bitcoin-qt:0.4/
/Satoshi:5.12/Spesmilo:0.8/
Here bitcoin-qt and Spesmilo may use protocol version 5.0, however the internal codebase they use are different versions of the same software. The version numbers are not defined to any strict format, although this guide recommends:
* Version numbers in the form of Major.Minor.Revision (2.6.41)
* Repository builds using a date in the format of YYYYMMDD (20110128)
For git repository builds, implementations are free to use the git commitish. However the issue lies in that it is not immediately obvious without the repository which version precedes another. For this reason, we lightly recommend dates in the format specified above, although this is by no means a requirement.
Optional -r1, -r2, ... can be appended to user agent version numbers. This is another light recommendation, but not a requirement. Implementations are free to specify version numbers in whatever format needed insofar as it does not include (, ), : or / to interfere with the user agent syntax.
An optional comments field after the version number is also allowed. Comments should be delimited by brackets (...). The contents of comments is entirely implementation defined although this BIP recommends the use of semi-colons ; as a delimiter between pieces of information.
Example:
/BitcoinJ:0.2(iPad; U; CPU OS 3_2_1)/AndroidBuild:0.8/
Reserved symbols are therefore: / : ( )
They should not be misused beyond what is specified in this section.
* / separates the code-stack
* : specifies the implementation version of the particular stack
* ( and ) delimits a comment which optionally separates data using ;
== Timeline ==
When this document was published, the bitcoin protocol and Satoshi client versions were currently at 0.5 and undergoing changes. In order to minimise disruption and allow the undergoing changes to be completed, the next protocol version at 0.6 became peeled from the client version (also at 0.6). As of that time (January 2012), protocol and implementation version numbers are distinct from each other.
================================================
FILE: bip-0015.mediawiki
================================================
[[bip-0070.mediawiki|BIP 0070]] (payment protocol) may be seen as the alternative to Aliases.
Using vanilla bitcoin, to send funds to a destination, an address in the form 1Hd44nkJfNAcPJeZyrGC5sKJS1TzgmCTjjZ is needed. The problem with using addresses is that they are not easy to remember. An analogy can be thought if one were required to enter the IP address of their favourite websites if domain names did not exist.
This document aims to layout through careful argument, a bitcoin alias system. This is a big modification to the protocol that is not easily changed in the future and has big ramifications. There is impetus in getting it correct the first time. Aliases have to be robust and secure.
== Schemes ==
Here are a few different proposals and the properties of each system.
=== FirstBits ===
FirstBits is a proposal for using the blockchain as an address book.
When bitcoins are sent to an address, that address becomes recorded in the blockchain. It is therefore known that this address exists or did exist by simply seeing that there was a payment to that address. FirstBits is a method to have a memorable alias. One first converts the address to lower-case, then takes the first few unique characters. This is your FirstBits alias.
As an example, brmlab hackerspace in Prague has an address for purchasing food or drink, or making donations:
1BRMLAB7nryYgFGrG8x9SYaokb8r2ZwAsX
Their FirstBits alias becomes:
1brmlab
It is enough information to be given the FirstBits alias ''1brmlab''. When someone wishes to make a purchase, without FirstBits, they either have to type out their address laboriously by hand, scan their QR code (which requires a mobile handset that this author does not own) or find their address on the internet to copy and paste into the client to send bitcoins. FirstBits alleviates this impracticality by providing an easy method to make payments.
Together with Vanitygen (vanity generator), it becomes possible to create memorable unique named addresses. Addresses that are meaningful, rather than an odd assemblage of letters and numbers but add context to the destination.
However FirstBits has its own problems. One is that the possible aliases one is able to generate is limited by the available computing power available. It may not be feasible to generate a complete or precise alias that is wanted- only approximates may be possible. It is also computationally resource intensive which means a large expenditure of power for generating unique aliases in the future, and may not scale up to the level of individuals at home or participants with hand-held devices in an environment of ubiquitous computing.
FirstBits scales extremely poorly as the network grows. Each indexer or lookup node needs to keep track of every bitcoin address ever in existence and provide a fast lookup from the aliases to those addresses. As the network grows linearly, the number of addresses should grow exponentially (assuming a networked effect of (n-1)*(n-2)/2) rapidly making this scheme unfeasible.
Light clients of the partial merkle root types become dependent on a trusted third party for their alias lookups. The cost of storing every bitcoin address is too high considering their typical use-case on low-resource devices. This factor more than the others, means this scheme is sub-optimal and must be rejected.
=== DNS TXT Records ===
DNS allows TXT records to be created containing arbitrary data. In a bitcoin alias system, a custom format mutually agreed upon by a BIP standard would be used to store mappings to bitcoin addresses from domain names. How such a format would look is out of the scope of this document.
An issue is that it requires people who wish to create such mappings to be familiar with configuring DNS records, and be able to run the necessary toolsets to insert the correct data. Although not a huge concern, it is a usability issue.
Security wise, DNS is unsafe and insecure by design. It is possible to spoof records by being on the same network as another host. A number of revisions to mitigate the issue under the guise of DNSSEC have been in the works since the 1990s and are still being rolled out.
As of Dec 2011, DNSSEC is still not yet a defacto standard on the internet. Should a participant in the bitcoin network wish to use DNS TXT records, they would in addition to having to configure DNS, be able to setup DNSSEC. This may not be feasible, especially where some registrars provide access to DNS through a web interface only.
The disadvantage of DNS TXT records is that updating a record takes time. This encourages people to not use new addresses per transaction which has certain security issues.
=== Server Service ===
Aside from using DNS TXT records, another possibility is using the domain name system to lookup hosts and then contact a service running on a predefined port to get the bitcoin address.
# User wishes to send to foo@bar.net
# Client uses DNS to find the IP address of bar.net: 123.123.123.123
# Client connects to port 123.123.123.123:4567 and requests the bitcoin address for the user ''foo''
# Server responds with the address or error code and terminates the connection.
# Client sends the funds to the address
The service would be responsible for providing the mechanisms for changing and storing the mappings on their service. A front-end web interface could be provided to users wishing to use the service and customise their accounts on the server.
This approach has the positive aspect of providing the best flexibility for the implementer to store the records however they wish in a database or plaintext file, and then serve them up quickly using a small server side daemon typically written in C. This approach is highly scalable.
However this approach also suffers the problem of being reliant on DNS and hence also being vulnerable to spoofing. Hence DNSSEC is also required. This approach is slightly better than the DNS TXT records though since it makes inserting new users and modifying aliases very easy which allows people to run these server services more cheaply.
=== HTTPS Web Service ===
HTTPS provides an additional layer of security by encrypting the connection, providing much needed privacy for users. Together with using Certificate Authorities, it fixes the issue with using DNSSEC since an error would be thrown up were someone to try to spoof a domain name on the local network.
When trying to send to:
genjix@foo.org
The request is broken into the handle (genjix) and domain (foo.org) at the last occurrence of the @. The client then constructs a request that will query for the address.
https://foo.org/bitcoin-alias/?handle=genjix
bitcoin-alias has been chosen as the query suffix because it allows this system to co-exist easily within another web root without the fear of name clashes.
The query will then return an address which is used to make the payment.
1Hd44nkJfNAcPJeZyrGC5sKJS1TzgmCTjjZ
The details of whether a unique address is returned per query, whether an address is fetched from a pre-existing pool of addresses, and so on is an implementation detail unique to every server. How alias to address mappings are setup is dependent on the site which could have a web-interface and be providing a free service to users or be a private customised service serving pre-existing addresses. This is left up to sysop policy, and deliberately not defined here.
A web service is trivial to setup and the cost is low. There are many free out of the box providers on the net that allows anyone with the most basic knowledge of web technologies to create their own website. By providing users with a package, anybody can quickly set themselves up with a bitcoin alias. It could be something as simple as a PHP script that the user edits with their custom settings and uploads themselves to their website.
It also scales reasonably- anybody wishing to run a naming service can attach a backend with a variety of database technologies then provide a web frontend for users to customise and create their own aliases.
A naive implementation is provided below as an example.
// resolv.h
#ifndef NOMRESOLV_H__
#define NOMRESOLV_H__
#include
#include "curl/curl.h"
using std::string;
/*
This class resolves against a server to lookup addresses.
To not conflict with the bitcoin addresses, we refer here to people's handles.
A handle is of the form:
genjix@foo.org
Most characters are valid for the username + password (and handled accordingly), but the domain follows usual web standards. It is possible to affix a path if needed,
genjix@bar.com/path/to/
*/
class NameResolutionService
{
public:
NameResolutionService();
~NameResolutionService();
// Three main methods map to RPC actions.
string FetchAddress(const string& strHandle, string& strAddy);
private:
// A POST block
class PostVariables
{
public:
PostVariables();
~PostVariables();
// Add a new key, value pair
bool Add(const string& strKey, const string& strVal);
curl_httppost* operator()() const;
private:
// CURL stores POST blocks as linked lists.
curl_httppost *pBegin, *pEnd;
};
// Explodes user@domain => user, domain
static void ExplodeHandle(const string& strHandle, string& strNickname, string& strDomain);
// Perform the HTTP request. Returns true on success.
bool Perform();
// CURL error message
char pErrorBuffer[CURL_ERROR_SIZE];
// CURL response
string strBuffer;
// CURL handle
CURL *curl;
};
#endif
// resolv.cpp
#include "resolv.h"
#include
#include "access.h"
// callback used to write response from the server
static int writer(char *pData, size_t nSize, size_t nNmemb, std::string *pBuffer)
{
int nResult = 0;
if (pBuffer != NULL)
{
pBuffer->append(pData, nSize * nNmemb);
// How much did we write?
nResult = nSize * nNmemb;
}
return nResult;
}
NameResolutionService::NameResolutionService()
{
// Initialise CURL with our various options.
curl = curl_easy_init();
// This goes first in case of any problems below. We get an error message.
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, pErrorBuffer);
// fail when server sends >= 404
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_302);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
// server response goes in strBuffer
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strBuffer);
pErrorBuffer[0] = '\0';
}
NameResolutionService::~NameResolutionService()
{
curl_easy_cleanup(curl);
}
void NameResolutionService::ExplodeHandle(const string& strHandle, string& strNickname, string& strDomain)
{
// split address at @ furthest to the right
size_t nPosAtsym = strHandle.rfind('@');
strNickname = strHandle.substr(0, nPosAtsym);
strDomain = strHandle.substr(nPosAtsym + 1, strHandle.size());
}
bool NameResolutionService::Perform()
{
// Called after everything has been setup. This actually does the request.
CURLcode result = curl_easy_perform(curl);
return (result == CURLE_OK);
}
string NameResolutionService::FetchAddress(const string& strHandle, string& strAddy)
{
// GET is defined for 'getting' data, so we use GET for the low risk fetching of people's addresses
if (!curl)
// For some reason CURL didn't start...
return pErrorBuffer;
// Expand the handle
string strNickname, strDomain;
ExplodeHandle(strHandle, strNickname, strDomain);
// url encode the nickname for get request
const char* pszEncodedNick = curl_easy_escape(curl, strNickname.c_str(), strNickname.size());
if (!pszEncodedNick)
return "Unable to encode nickname.";
// construct url for GET request
string strRequestUrl = strDomain + "/bitcoin-alias/?handle=" + pszEncodedNick;
// Pass URL to CURL
curl_easy_setopt(curl, CURLOPT_URL, strRequestUrl.c_str());
if (!Perform())
return pErrorBuffer;
// Server should respond with a JSON that has the address in.
strAddy = strBuffer;
return ""; // no error
}
NameResolutionService::PostVariables::PostVariables()
{
// pBegin/pEnd *must* be null before calling curl_formadd
pBegin = NULL;
pEnd = NULL;
}
NameResolutionService::PostVariables::~PostVariables()
{
curl_formfree(pBegin);
}
bool NameResolutionService::PostVariables::Add(const string& strKey, const string& strVal)
{
// Copy strings to this block. Return true on success.
return curl_formadd(&pBegin, &pEnd, CURLFORM_COPYNAME, strKey.c_str(), CURLFORM_COPYCONTENTS, strVal.c_str(), CURLFORM_END) == CURL_FORMADD_OK;
}
curl_httppost* NameResolutionService::PostVariables::operator()() const
{
return pBegin;
}
// rpc.cpp
...
const Object CheckMaybeThrow(const string& strJsonIn)
{
// Parse input JSON
Value valRequest;
if (!read_string(strJsonIn, valRequest) || valRequest.type() != obj_type)
throw JSONRPCError(-32700, "Parse error");
const Object& request = valRequest.get_obj();
// Now check for a key called "error"
const Value& error = find_value(request, "error");
// It's an error JSON! so propagate the error.
if (error.type() != null_type)
throw JSONRPCError(-4, error.get_str());
// Return JSON object
return request;
}
const string CollectAddress(const string& strIn)
{
// If the handle does not have an @ in it, then it's a normal base58 bitcoin address
if (strIn.find('@') == (size_t)-1)
return strIn;
// Open the lookup service
NameResolutionService ns;
// We established that the input string is not a BTC address, so we use it as a handle now.
string strHandle = strIn, strAddy;
string strError = ns.FetchAddress(strHandle, strAddy);
if (!strError.empty())
throw JSONRPCError(-4, strError);
const Object& request(CheckMaybeThrow(strAddy));
// Get the BTC address from the JSON
const Value& address = find_value(request, "address");
if (address.type() != str_type)
throw JSONRPCError(-32600, "Server responded with malformed reply.");
return address.get_str();
}
// Named this way to prevent possible conflicts.
Value rpc_send(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 2)
throw runtime_error(
"send \n"
" is a real and is rounded to the nearest 0.01");
// Intelligent function which looks up address given handle, or returns address
string strAddy = CollectAddress(params[0].get_str());
int64 nAmount = AmountFromValue(params[1]);
// Do the send
CWalletTx wtx;
string strError = SendMoneyToBitcoinAddress(strAddy, nAmount, wtx);
if (!strError.empty())
throw JSONRPCError(-4, strError);
return wtx.GetHash().GetHex();
}
...
=== IP Transactions ===
An IP transaction is an old transaction format in bitcoin that is disabled and possibly could be deprecated. It involves being given an IP address to make payment to. Upon connecting to the node and requesting their public key using "checkorder", they will respond with a script in the form:
OP_CHECKSIG
Similar to coinbase output transactions. IP transactions have the advantage of being able to contain additional metadata which can be useful in many transactions. Currently no authentication is done making the scheme insecure against man in the middle (MITM) attacks.
This proposal seeks to enable DNS lookups for IP transactions.
The "checkorder" message would contain a destination account, which could map to different isolated sets of keypairs/wallets running under the same host. The exact mapping from the checkorder reference info to the local system is implementation defined.
By using DNS lookups, the MITM problem with IP transactions could be mitigated by storing a public key in a DNS TXT record. This public key would be used for all future "reply" messages originating from that host. First time use would require a confirmation for acceptance of that public key; like with SSH. Should the "reply" message not match the accepted public key, then the host will be given an error.
[[Category:BIP|E]]
=== Namecoin ID ===
This proposal uses the Namecoin blockchain to associate an alias with a bitcoin address. Bitcoin queries a namecoin node. This retrieves the structured data containing the bitcoin address(es) associated with this alias.
Using a decentralised domain name system like Namecoin, means no external server or entity needs to be trusted unlike the other proposals listed here. This indicates a system with the advantage of having a high availability and ease of entry (no restrictions for users to create aliases).
Two examples are presented below. The first shows a simpler format, while the second shows several Bitcoin addresses in a structured format.
$ namecoind name_show id/khal
{
"bitcoin" : "1KHAL8bUjnkMRMg9yd2dNrYnJgZGH8Nj6T"
}
$ namecoind name_show id/khal
{
"bitcoin" :
{
"default" : "1KHAL8bUjnkMRMg9yd2dNrYnJgZGH8Nj6T",
"donation": "1J3EKMfboca3SESWGrQKESsG1MA9yK6vN4"
}
}
'''More possibilities :'''
* Allow to securely use '''unsecured channels'''
You can put an url and a bitcoin address that will be used to sign the result. It means that a query to this url will return a bitcoin address and a signature. Bitcoin can then check (with the verify_message function) that the returned address has not been replaced by another one.
$ namecoind name_show id/khal
{
"bitcoin" :
{
"url" : "http://merchant.com/bitcoin/getnewaddres/",
"signedWith" : "1KHAL8bUjnkMRMg9yd2dNrYnJgZGH8Nj6T"
}
}
* Allow to get a different address each time, or per user, per order, etc
$ namecoind name_show id/khal
{
"bitcoin" :
{
"url" : "http://merchant.com/bitcoin/getaddres/{Your customer id}",
"signedWith" : "1KHAL8bUjnkMRMg9yd2dNrYnJgZGH8Nj6T",
"useOnce": false
}
}
In the above example, bitcoin will ask the user for "Your customer id" and replace that value in the url before making the http request. The merchant will receive the request and give the user a payment address associated with that customer.
Any text can be put into the brackets, allowing merchants to adapt it to all their needs.
* Specification is extensible
New features can be added later to support uncovered cases.
See the specification of [http://dot-bit.org/Namespace:Identity Namecoin ID] for more information.
================================================
FILE: bip-0016/qa.mediawiki
================================================
This page is a Quality Assurance test plan for [[../bip-0016.mediawiki|BIP 16]]. If you see a test missing, please add it.
If you can help test, please edit this page to sign-off on it.
{| class="wikitable"
|-
! Done !! Test Procedure !! Tested by
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 0.6 on testnet and main net
Send coins using GUI, RCP sendtoaddress, and RCP sendmany commands
Result: coins sent in all cases
| Gavin Andresen
|- style="color:green;"
| ✓
| Test multisig 1-of-1
Run 0.6 bitcoind, get a public key with: ./bitcoind -testnet validateaddress $(./bitcoind -testnet getnewaddress)
Generate a multisig 1-of-1 address: ./bitcoind addmultisigaddress 1 {public key from above}
Send-to-self some bitcoins using that address
Result: transaction is confirmed by network, displays properly in listtransactions.
Result: balance is unaffected
| Gavin Andresen; see transactions in [http://blockexplorer.com/testnet/block/000000001bdceba3936f2ea6a55311ac7b6030e327f1960e892620fcde6abf5f testnet block 44989]
|- style="color:green;"
| ✓
| Test multisig 1-of-2
Run 0.6 bitcoind, get 2 new bitcoin addresses
Generate a multisig 1-of-2 address: ./bitcoind addmultisigaddress 1 {address1} {address2}
Send-to-self some bitcoins using that address
Result: transaction is confirmed by network, displays properly in listtransactions.
Result: bitcoin balance is unaffected.
| Gavin Andresen; see transactions in [http://blockexplorer.com/testnet/block/000000001bdceba3936f2ea6a55311ac7b6030e327f1960e892620fcde6abf5f testnet block 44989]
|- style="color:green;"
| ✓
| Test multisig 1-of-3, 2-of-3, 3-of-3
Repeat test procedures above, with the other new multisignature transaction types
| Gavin Andresen; see transactions in [http://blockexplorer.com/testnet/block/000000001bdceba3936f2ea6a55311ac7b6030e327f1960e892620fcde6abf5f testnet block 44989]
|- style="color:green;"
| ✓
| Test multisig send-to-other
Repeat test procedures above, but use two bitcoinds, prepared as follows:
bitcoind 1 : Run getnewaddress and addmultisigaddress
bitcoind 2 : Just addmultisigaddress
Send coins from 2 to 1 using the address
Result: transaction is accepted/confirmed by network
Result: balance for 2 goes down, listtransactions for 2 displays correct result
Result: balance for 1 goes up, listtransactions for 1 displays correct result
| Gavin Andresen; see transactions in [http://blockexplorer.com/testnet/block/000000001bdceba3936f2ea6a55311ac7b6030e327f1960e892620fcde6abf5f testnet block 44989]
|- style="color:green;"
| ✓
| Test redeeming multisignature transactions
Fund a new, empty wallet entirely with multisig transactions
Wait for transactions to confirm
Use sendtoaddress and sendmany to generate spend-from-multisig transactions
Spend to both single-address and multisig address, and test send-to-other and send-to-self
Result: transactions are accepted/confirmed by network
Result: balance decreases, listtransactions displays correct information
| Gavin Andresen; see transactions in [http://blockexplorer.com/testnet/block/000000001bdceba3936f2ea6a55311ac7b6030e327f1960e892620fcde6abf5f testnet block 44989]
|- style="color:green;"
| ✓
| Run 0.6 Bitcoin-Qt GUI on one of the test wallets from above
Result: balance and transactions displayed correctly
| Gavin Andresen
|- style="color:orange;"
| ✓
| Run BIP-16-capable backport Bitcoin 0.3.19 through 0.5.1 on testnet and main net
Send coins using GUI, RCP sendtoaddress, and RCP sendmany commands
Result: coins sent in all cases
| Gavin Andresen (tested 0.3.19, 0.3.24 and 0.5.1)
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 0.6.0 on testnet
Mine coins using built-in miner
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gavin Andresen
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 0.6.0 on testnet
Mine coins using getwork interface
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gavin Andresen
|- style="color:green;"
|
| Run BIP-16-capable Bitcoin 0.6.0 on testnet
Mine coins using getmemorypool interface
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gregory Maxwell; Using p2pool see [https://blockexplorer.com/testnet/rawblock/00000000040367fcb750b6f064db6955b6c7c6218fb625e3dfed6b5c19c97107 testnet block 45400] (and many others, also tested on mainnet)
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 0.3.19 through 0.5.1 backports on testnet
Mine coins using built-in miner
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gavin Andresen (tested all on a testnet-in-a-box)
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 3.19 through 0.5.1 backports on testnet
Mine coins using getwork interface
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gavin Andresen (tested all on a testnet-in-a-box)
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 0.3.19 through 0.5.1 backports on testnet
Mine coins using built-in miner
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gavin Andresen (tested all on a testnet-in-a-box)
|- style="color:green;"
| ✓
| Run BIP-16-capable Bitcoin 3.19 through 0.5.1 backports on testnet
Mine coins using getwork interface
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
| Gavin Andresen (tested all on a testnet-in-a-box)
|- style="color:red;"
|- style="color:red;"
|
| Run BIP-16-capable Bitcoin 3.19 through 0.5.1 backports on testnet
Mine coins using getmemorypool interface
Result: blocks accepted, show up on blockexplorer.com/testnet
Result: mined blocks' coinbase contains /P2SH/ string
|
|- style="color:green;"
| ✓
| Create/run unit tests for:
multisignature signing/verification
multisignature invalid signature failure
multisignature IsStandard() success/failure
extraction of addresses from multisignature transactions
BIP 16 IsStandard() success/failure (including failure with OP_PUSHDATA1/2/4)
BIP 16 AreInputsStandard() success/failure
BIP 16 compatibility with other 3 standard transaction types
BIP 16 no-recursion test
BIP 16 switchover date logic
OP_CHECKMULTISIG counting of signature operations inside BIP 16 transactions
| Gavin Andresen (see test/multisig_tests.cpp, test/script_tests.cpp, test/script_P2SH_tests.cpp, test/sigopcount_tests.cpp in the bitcoin source tree; 'make test_bitcoin' in src/ directory to compile)
|- style="color:green;"
| ✓
| Create/run 'transaction fuzzer' to stress-test BIP 16 transactions
| Gavin Andresen (https://github.com/gavinandresen/bitcoin-git/tree/fuzzer , run twice on both testnet-in-a-box and testnet with 100,000 'fuzzed' transactions each test run) Valid fuzzed transactions appeared in (for example) [http://blockexplorer.com/testnet/block/000000001587c859649cea954e921ba4efd77707fb327dd53e122fd7b89636c4 testnet block 44987]
|- style="color:green;"
| ✓
| Run Bitcoin 0.6 on main net
Result: blocks created properly
Result: blocks include /P2SH/ string in their coinbase
| various mining pools
|- style="color:green;"
| ✓
| Run BIP 16 vinced_mergedmine backport on main net
Result: blocks created properly
Result: blocks include /P2SH/ string in their coinbase
| (Gavin for slush: after bug fixes, running with no issues)
|- style="color:green;"
| ✓
| Test chain-split handling on testnet-in-a-box
Create two valid hash, invalid signature transactions in two blocks separated in time on a testnet-in-a-box chain
Run a bitcoind to synchronize with the chain, with -paytoscripthashtime set in between the two blocks
Result: first transaction/block accepted, second causes a chain split
Re-run bitcoind with -paytoscripthashtime in the future
Result: entire chain accepted
| Gavin Andresen: testnet-in-a-box files at: http://www.skypaint.com/bitcoin/bip16chain.tar.gz first half-valid BIP16 transaction at block 2431 (time 1328202835) second at block 2436 (time 1328204241)
|}
================================================
FILE: bip-0016.mediawiki
================================================
==Abstract==
This BIP describes a new "standard" transaction type for the Bitcoin scripting system, and defines additional validation rules that apply only to the new transactions.
==Motivation==
The purpose of pay-to-script-hash is to move the responsibility for supplying the conditions to redeem a transaction from the sender of the funds to the redeemer.
The benefit is allowing a sender to fund any arbitrary transaction, no matter how complicated, using a fixed-length 20-byte hash that is short enough to scan from a QR code or easily copied and pasted.
==Specification==
A new standard transaction type that is relayed and included in mined blocks is defined:
OP_HASH160 [20-byte-hash-value] OP_EQUAL
[20-byte-hash-value] shall be the push-20-bytes-onto-the-stack opcode (0x14) followed by exactly 20 bytes.
This new transaction type is redeemed by a standard scriptSig:
...signatures... {serialized script}
Transactions that redeem these pay-to-script outpoints are only considered standard if the ''serialized script'' - also referred to as the ''redeemScript'' - is, itself, one of the other standard transaction types.
The rules for validating these outpoints when relaying transactions or considering them for inclusion in a new block are as follows:
# Validation fails if there are any operations other than "push data" operations in the scriptSig.
# Normal validation is done: an initial stack is created from the signatures and {serialized script}, and the hash of the script is computed and validation fails immediately if it does not match the hash in the outpoint.
# {serialized script} is popped off the initial stack, and the transaction is validated again using the popped stack and the deserialized script as the scriptPubKey.
These new rules should only be applied when validating transactions in blocks with timestamps >= 1333238400 (Apr 1 2012) [https://github.com/bitcoin/bitcoin/commit/8f188ece3c82c4cf5d52a3363e7643c23169c0ff Remove -bip16 and -paytoscripthashtime command-line arguments]. There are transactions earlier than 1333238400 in the block chain that fail these new validation rules. [https://web.archive.org/web/20141122040355/http://blockexplorer.com/tx/6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192 Transaction 6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192]. Older transactions must be validated under the old rules. (see the Backwards Compatibility section for details).
For example, the scriptPubKey and corresponding scriptSig for a one-signature-required transaction is:
scriptSig: [signature] {[pubkey] OP_CHECKSIG}
scriptPubKey: OP_HASH160 [20-byte-hash of {[pubkey] OP_CHECKSIG} ] OP_EQUAL
Signature operations in the {serialized script} shall contribute to the maximum number allowed per block (20,000) as follows:
# OP_CHECKSIG and OP_CHECKSIGVERIFY count as 1 signature operation, whether or not they are evaluated.
# OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY immediately preceded by OP_1 through OP_16 are counted as 1 to 16 signature operation, whether or not they are evaluated.
# All other OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY are counted as 20 signature operations.
Examples:
+3 signature operations:
{2 [pubkey1] [pubkey2] [pubkey3] 3 OP_CHECKMULTISIG}
+22 signature operations:
{OP_CHECKSIG OP_IF OP_CHECKSIGVERIFY OP_ELSE OP_CHECKMULTISIGVERIFY OP_ENDIF}
==Rationale==
This BIP replaces BIP 12, which proposed a new Script opcode ("OP_EVAL") to accomplish everything in this BIP and more.
The Motivation for this BIP (and BIP 13, the pay-to-script-hash address type) is somewhat controversial; several people feel that it is unnecessary, and complex/multisignature transaction types should be supported by simply giving the sender the complete {serialized script}. The author believes that this BIP will minimize the changes needed to all of the supporting infrastructure that has already been created to send funds to a base58-encoded-20-byte bitcoin addresses, allowing merchants and exchanges and other software to start supporting multisignature transactions sooner.
Recognizing one 'special' form of scriptPubKey and performing extra validation when it is detected is ugly. However, the consensus is that the alternatives are either uglier, are more complex to implement, and/or expand the power of the expression language in dangerous ways.
The signature operation counting rules are intended to be easy and quick to implement by statically scanning the {serialized script}. Bitcoin imposes a maximum-number-of-signature-operations per block to prevent denial-of-service attacks on miners. If there was no limit, a rogue miner might broadcast a block that required hundreds of thousands of ECDSA signature operations to validate, and it might be able to get a head start computing the next block while the rest of the network worked to validate the current one.
There is a 1-confirmation attack on old implementations, but it is expensive and difficult in practice. The attack is:
# Attacker creates a pay-to-script-hash transaction that is valid as seen by old software, but invalid for new implementation, and sends themselves some coins using it.
# Attacker also creates a standard transaction that spends the pay-to-script-hash transaction, and pays the victim who is running old software.
# Attacker mines a block that contains both transactions.
If the victim accepts the 1-confirmation payment, then the attacker wins because both transactions will be invalidated when the rest of the network overwrites the attacker's invalid block.
The attack is expensive because it requires the attacker create a block that they know will be invalidated by the rest of the network. It is difficult because creating blocks is difficult and users should not accept 1-confirmation transactions for higher-value transactions.
==Backwards Compatibility==
These transactions are non-standard to old implementations, which will (typically) not relay them or include them in blocks.
Old implementations will validate that the {serialize script}'s hash value matches when they validate blocks created by software that fully support this BIP, but will do no other validation.
Avoiding a block-chain split by malicious pay-to-script transactions requires careful handling of one case:
* A pay-to-script-hash transaction that is invalid for new clients/miners but valid for old clients/miners.
To gracefully upgrade and ensure no long-lasting block-chain split occurs, more than 50% of miners must support full validation of the new transaction type and must switch from the old validation rules to the new rules at the same time.
To judge whether or not more than 50% of hashing power supports this BIP, miners are asked to upgrade their software and put the string "/P2SH/" in the input of the coinbase transaction for blocks that they create.
On February 1, 2012, the block-chain will be examined to determine the number of blocks supporting pay-to-script-hash for the previous 7 days. If 550 or more contain "/P2SH/" in their coinbase, then all blocks with timestamps after 15 Feb 2012, 00:00:00 GMT shall have their pay-to-script-hash transactions fully validated. Approximately 1,000 blocks are created in a week; 550 should, therefore, be approximately 55% of the network supporting the new feature.
If a majority of hashing power does not support the new validation rules, then rollout will be postponed (or rejected if it becomes clear that a majority will never be achieved).
===520-byte limitation on serialized script size===
As a consequence of the requirement for backwards compatibility the serialized script is itself subject to the same rules as any other PUSHDATA operation, including the rule that no data greater than 520 bytes may be pushed to the stack. Thus it is not possible to spend a P2SH output if the redemption script it refers to is >520 bytes in length. For instance while the OP_CHECKMULTISIG opcode can itself accept up to 20 pubkeys, with 33-byte compressed pubkeys it is only possible to spend a P2SH output requiring a maximum of 15 pubkeys to redeem: 3 bytes + 15 pubkeys * 34 bytes/pubkey = 513 bytes.
==Reference Implementation==
https://gist.github.com/gavinandresen/3966071
==See Also==
* https://bitcointalk.org/index.php?topic=46538
* The [[bip-0013.mediawiki|Address format for Pay to Script Hash BIP]]
* M-of-N Multisignature Transactions [[bip-0011.mediawiki|BIP 11]]
* [[bip-0016/qa.mediawiki|Quality Assurance test checklist]]
== References ==
================================================
FILE: bip-0017.mediawiki
================================================
==Abstract==
This BIP describes a new opcode (OP_CHECKHASHVERIFY) for the Bitcoin scripting system, and a new 'standard' transaction type that uses it to enables the receiver of bitcoins to specify the transaction type needed to re-spend them.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
The purpose of pay-to-script-hash is to move the responsibility for supplying the conditions to redeem a transaction from the sender of the funds to the redeemer.
The benefit is allowing a sender to fund any arbitrary transaction, no matter how complicated, using a fixed-length 20-byte hash that is short enough to scan from a QR code or easily copied and pasted.
==Specification==
OP_CHECKHASHVERIFY will re-define the existing OP_NOP2 opcode, and will function as follows when executed:
* First, hash the end of the prior script (in the general case, scriptSig; if no prior script, a null string is hashed) beginning from the last evaluated OP_CODESEPARATOR onward (or from the beginning of the script, if no OP_CODESEPARATOR was present)
* Then, compare this with the item on the top of the stack (if there is none, the script fails immediately)
* If the hashes match, do nothing, proceed as if an OP_NOP; if they do not match, the script fails immediately.
* Note that in the case of a matched hash, the top stack item (the hash being compared with) is not popped off the stack. This is for backward compatibility.
This opcode reassignment shall be applied when validating transactions in blocks only with timestamps after February 23, 2012 (see the Backwards Compatibility section for details).
A new standard transaction type that is relayed and included in mined blocks is defined:
[20-byte-hash-value] OP_CHECKHASHVERIFY OP_DROP
[20-byte-hash-value] shall be the push-20-bytes-onto-the-stack opcode (0x14) followed by exactly 20 bytes.
This new transaction type is redeemed by a standard scriptSig:
...signatures... OP_CODESEPARATOR {script}
Transactions that redeem these pay-to-script outpoints are only considered standard if they contain exactly one OP_CODESEPARATOR and the appended ''script'' is, itself, one of the other standard transaction types.
==Example==
For example, the scriptPubKey and corresponding scriptSig for a one-signature-required transaction is:
scriptSig: [signature] OP_CODESEPARATOR [pubkey] OP_CHECKSIG
scriptPubKey: [20-byte-hash of {[pubkey] OP_CHECKSIG} ] OP_CHECKHASHVERIFY OP_DROP
2-of-3:
scriptSig: [signatures...] OP_CODESEPARATOR 2 [pubkey1] [pubkey2] [pubkey3] 3 OP_CHECKMULTISIG
scriptPubKey: [20-byte-hash of {2 [pubkey1] [pubkey2] [pubkey3] 3 OP_CHECKMULTISIG} ] OP_CHECKHASHVERIFY OP_DROP
==Rationale==
This BIP replaces BIP 12 and BIP 16, which propose evaluating a Script from the stack after verifying its hash.
The Motivation for this BIP (and BIP 13, the pay-to-script-hash address type) is somewhat controversial; several people feel that it is unnecessary, and complex/multisignature transaction types should be supported by simply giving the sender the complete {serialized script}. The author believes that this BIP will minimize the changes needed to all of the supporting infrastructure that has already been created to send funds to a base58-encoded-20-byte bitcoin addresses, allowing merchants and exchanges and other software to start supporting multisignature transactions sooner.
There is a 1-confirmation attack on old implementations, but it is expensive and difficult in practice. The attack is:
# Attacker creates a pay-to-script-hash transaction that is valid as seen by old software, but invalid for new implementation, and sends themselves some coins using it.
# Attacker also creates a standard transaction that spends the pay-to-script transaction, and pays the victim who is running old software.
# Attacker mines a block that contains both transactions.
If the victim accepts the 1-confirmation payment, then the attacker wins because both transactions will be invalidated when the rest of the network overwrites the attacker's invalid block.
The attack is expensive because it requires the attacker create a block that they know will be invalidated by the rest of the network. It is difficult because creating blocks is difficult and users should not accept 1-confirmation transactions for higher-value transactions.
==Backwards Compatibility==
These transactions are non-standard to old implementations, which will (typically) not relay them nor include them in blocks.
Old implementations will not validate that the {script}'s hash value matches when they validate blocks created by software that fully support this BIP.
Avoiding a block-chain split by malicious pay-to-script transactions requires careful handling of one case:
* A pay-to-script-hash transaction that is invalid for new clients/miners but valid for old clients/miners.
To gracefully upgrade and ensure no long-lasting block-chain split occurs, more than 50% of miners must support full validation of the new transaction type and must switch from the old validation rules to the new rules at the same time.
To judge whether or not more than 50% of hashing power supports this BIP, miners are asked to upgrade their software and put the string "p2sh/CHV" in the input of the coinbase transaction for blocks that they create.
On February 8, 2012, the block-chain will be examined to determine the number of blocks supporting pay-to-script-hash for the previous 7 days. If at least 60% contain "p2sh/CHV" in their coinbase, then all blocks with timestamps after 23 Feb 2012, 00:00:00 GMT shall have their pay-to-script-hash transactions validated.
If a majority of hashing power does not support the new validation rules, then rollout will be postponed (or rejected if it becomes clear that a majority will never be achieved).
OP_NOP2 is used, so existing OP_EVAL (BIP 12) transactions in the block chain can still be redeemed.
==Reference Implementation==
[https://gitorious.org/~Luke-Jr/bitcoin/luke-jr-bitcoin/commits/checkhashverify Validation, sending, and receiving for bitcoind git master]
[https://gitorious.org/~Luke-Jr/bitcoin/luke-jr-bitcoin/commits/checkhashverify_backport Validation only for 0.3.19+]
==See Also==
* The [[bip-0013.mediawiki|Address format for Pay to Script Hash BIP]]
* [[bip-0011.mediawiki|M-of-N Multisignature Transactions (BIP 11)]]
* Example BIP 17 transaction chain: [http://blockexplorer.com/tx/b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d a] [http://blockexplorer.com/tx/eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb b] [http://blockexplorer.com/tx/055707ce7fea7b9776fdc70413f65ceec413d46344424ab01acd5138767db137 c] [http://blockexplorer.com/tx/6d36bc17e947ce00bb6f12f8e7a56a1585c5a36188ffa2b05e10b4743273a74b d]
================================================
FILE: bip-0018.mediawiki
================================================
==Abstract==
This BIP modifies the basic format of transaction inputs and outputs, replacing the current scriptSig and scriptPubKey (scripts executed to validate a transaction) with new contents: dataSig, scriptCheck, and hashScriptCheck.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
The purpose of pay-to-script-hash is to move the responsibility for supplying the conditions to redeem a transaction from the sender of the funds to the redeemer.
The benefit is allowing a sender to fund any arbitrary transaction, no matter how complicated, using a fixed-length 20-byte hash that is short enough to scan from a QR code or easily copied and pasted.
==Specification==
scriptSig and scriptPubKey are hereby deemed to be deprecated.
Bitcoin-compatible clients MUST still continue to support them for compatibility, but it should not be used for any new transaction types.
Services and people which send Bitcoins SHOULD continue to support old pubkey-based addresses for the time being.
Services and people which receive Bitcoins MAY continue to generate and use old pubkey-based addresses.
To replace these, there are 3 new elements:
* dataSig is included in place of scriptSig in transaction inputs, and contains multiple serialized data elements
* scriptCheck is the final element of dataSig, and is executed with the preceding dataSig elements preloaded onto the stack (the element immediately before scriptCheck is the top of the stack)
* hashScriptCheck is included in place of scriptPubKey in transaction outputs, to specify the hash of the scriptCheck allowed to redeem it
dataSig is to be encoded the same as a push-only script.
hashScriptCheck must be encoded exactly so:
0xa9 0x14 (20-byte-hash-value) 0x87
This can be interpreted by legacy (pre-BIP 18) clients as the following script:
OP_HASH160 [20-byte-hash-value] OP_EQUAL
If this template is not matched exactly OR the transaction is in a block with a timestamp before the hashScriptCheck activation date, validation MUST proceed in backward-compatibility mode, using scriptSig+scriptPubKey rather than dataSig+scriptCheck+hashScriptCheck.
A hashScriptCheck-compliant input is valid only if:
* dataSig MUST NOT contain any operations other than "push data" (it is data, not a script; no mixing scriptSig with hashScriptCheck)
* scriptCheck MUST hash (using Bitcoin's Hash160 algorithm) to the output's hashScriptCheck.
* scriptCheck MUST be executed with the dataSig-based stack specified above (ie, not including scriptCheck itself) to perform validation (this does not imply clients are required to validate transactions).
* scriptCheck must not abort, and must leave a true value on the top of the stack. This is the current behaviour for scriptSig+scriptPubKey.
The new scriptCheck SHOULD be checked against "standard transaction" templates by miners.
For example, the hashScriptCheck and corresponding dataSig for a one-signature-required transaction is:
scriptCheck: [pubkey] OP_CHECKSIG
dataSig: [signature] {[pubkey] OP_CHECKSIG}
hashScriptCheck: [20-byte-hash of {[pubkey] OP_CHECKSIG}]
===Signature operation limits for scriptCheck===
Signature operations in scriptCheck do not follow the same rules previously applied to scriptSig and scriptPubKey.
Instead, they shall contribute to the maximum number allowed per block (20,000) as follows:
# OP_CHECKSIG and OP_CHECKSIGVERIFY count as 1 signature operation, whether or not they are evaluated.
# OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY immediately preceded by OP_1 through OP_16 are counted as 1 to 16 signature operation, whether or not they are evaluated.
# All other OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY are counted as 20 signature operations.
Examples:
+3 signature operations:
2 [pubkey1] [pubkey2] [pubkey3] 3 OP_CHECKMULTISIG
+22 signature operations
OP_CHECKSIG OP_IF OP_CHECKSIGVERIFY OP_ELSE OP_CHECKMULTISIGVERIFY OP_ENDIF
==Rationale==
This BIP replaces BIPs 12 and 17, which propose extensions to the Script system to allow scriptPubKey to outsource its verification.
It also replaces BIP 16, which is identical in terms of protocol, but suggests a specific implementation and does not deprecate scriptPubKey to maintain protocol consistency.
The Motivation for this BIP (and BIP 13, the pay-to-script-hash address type) is somewhat controversial; several people feel that it is unnecessary, and complex/multisignature transaction types should be supported by simply giving the sender the complete {serialized script}. The author believes that this BIP will minimize the changes needed to all of the supporting infrastructure that has already been created to send funds to a base58-encoded-20-byte bitcoin addresses, allowing merchants and exchanges and other software to start supporting multisignature transactions sooner.
The signature operation counting rules are intended to be easy and quick to implement by statically scanning scriptCheck.
Bitcoin imposes a maximum-number-of-signature-operations per block to prevent denial-of-service attacks on miners.
If there was no limit, a rogue miner might broadcast a block that required hundreds of thousands of ECDSA signature operations to validate, and it might be able to get a head start computing the next block while the rest of the network worked to validate the current one.
There is a 1-confirmation attack on old implementations, but it is expensive and difficult in practice. The attack is:
# Attacker creates a pay-to-script-hash transaction that is valid when interpreted as scriptPubKey, but contains an invalid scriptCheck, and sends themselves some coins using it.
# Attacker also creates a standard transaction that spends the pay-to-script transaction, and pays the victim who is running old software.
# Attacker mines a block that contains both transactions.
If the victim accepts the 1-confirmation payment, then the attacker wins because both transactions will be invalidated when the rest of the network overwrites the attacker's invalid block.
The attack is expensive because it requires the attacker create a block that they know will be invalidated by the rest of the network. It is difficult because creating blocks is difficult and users should not accept 1-confirmation transactions for higher-value transactions.
==Backwards Compatibility==
hashScriptCheck transactions are non-standard to old implementations, which will (typically) not relay them nor include them in blocks.
Old implementations will validate that scriptCheck's hash value matches when they validate blocks created by software that fully support this BIP, but will do no other validation.
Avoiding a block-chain split by malicious pay-to-script transactions requires careful handling of one case:
* A pay-to-script-hash transaction that is invalid for new clients/miners but valid for old clients/miners.
To gracefully upgrade and ensure no long-lasting block-chain split occurs, more than 50% of miners must support full validation of the new transaction type and must switch from the old validation rules to the new rules at the same time.
To judge whether or not more than 50% of hashing power supports this BIP, miners are asked to upgrade their software and put the string "/P2SH/" in the input of the coinbase transaction for blocks that they create.
At 00:00:00 UTC on 15 Mar 2012, the block-chain will be examined to determine the number of blocks supporting pay-to-script-hash for the previous 7 days. If 550 or more contain "/P2SH/" in their coinbase, then all blocks with timestamps after 00:00:00 UTC on 1 Apr 2012 shall have their pay-to-script-hash transactions fully validated. Approximately 1,000 blocks are created in a week; 550 should, therefore, be approximately 55% of the network supporting the new feature.
If a majority of hashing power does not support the new validation rules, then rollout will be postponed (or rejected if it becomes clear that a majority will never be achieved).
==Forwards Compatibility ==
The first two bytes of hashScriptCheck specify the hash algorithm and length used to verify scriptCheck.
This BIP only allows Bitcoin's Hash160 algorithm, but leaves open the possibility of a future BIP implementing others.
==Reference Implementation==
https://github.com/gavinandresen/bitcoin-git/tree/pay_to_script_hash
==See Also==
* The [[bip-0013.mediawiki|Address format for Pay to Script Hash BIP]]
* [[bip-0016.mediawiki|BIP 16 - Pay to Script Hash (aka "/P2SH/")]]
* M-of-N Multisignature Transactions [[bip-0011.mediawiki|BIP 11]]
================================================
FILE: bip-0019.mediawiki
================================================
==Abstract==
This BIP proposes M-of-N-signatures required transactions as a new 'standard' transaction type using the existing scripting system without significant modifications.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
Enable secured wallets, escrow transactions, and other use cases where redeeming funds requires more than a single signature.
A couple of motivating use cases:
* A wallet secured by a "wallet protection service" (WPS). 2-of-2 signatures required transactions will be used, with one signature coming from the (possibly compromised) computer with the wallet and the second signature coming from the WPS. When sending protected bitcoins, the user's bitcoin client will contact the WPS with the proposed transaction and it can then contact the user for confirmation that they initiated the transaction and that the transaction details are correct. Details for how clients and WPS's communicate are outside the scope of this BIP. Side note: customers should insist that their wallet protection service provide them with copies of the private key(s) used to secure their wallets that they can safely store off-line, so that their coins can be spent even if the WPS goes out of business.
* Three-party escrow (buyer, seller and trusted dispute agent). 2-of-3 signatures required transactions will be used. The buyer and seller and agent will each provide a public key, and the buyer will then send coins into a 2-of-3 CHECKMULTISIG transaction and send the seller and the agent the transaction id. The seller will fulfill their obligation and then ask the buyer to co-sign a transaction ( already signed by seller ) that sends the tied-up coins to him (seller). If the buyer and seller cannot agree, then the agent can, with the cooperation of either buyer or seller, decide what happens to the tied-up coins. Details of how buyer, seller, and agent communicate to gather signatures or public keys are outside the scope of this BIP.
==Specification==
Two new standard transaction types (scriptPubKey) that are relayed by clients and included in mined blocks.
N-of-N (all signatures required):
( {pubkey} OP_CHECKSIGVERIFY )*n
N-of-M (some signatures required):
{pubkey} OP_CHECKSIG ( OP_SWAP {pubkey} OP_CHECKSIG OP_ADD )*(n-1) n OP_EQUAL
But only for n less than or equal to 3.
These transactions are redeemed using a standard scriptSig:
...signatures...
The current Satoshi bitcoin client does not relay or mine transactions with scriptSigs larger than 200 bytes; to accommodate 3-signature transactions, this will be increased to 500 bytes.
===Templates===
scriptPubKey:
{pubkey} OP_CHECKSIGVERIFY {pubkey} OP_CHECKSIGVERIFY
{pubkey} OP_CHECKSIGVERIFY {pubkey} OP_CHECKSIGVERIFY {pubkey} OP_CHECKSIGVERIFY
{pubkey} OP_CHECKSIG OP_SWAP {pubkey} OP_CHECKSIG OP_ADD {n} OP_EQUAL
{pubkey} OP_CHECKSIG OP_SWAP {pubkey} OP_CHECKSIG OP_ADD OP_SWAP {pubkey} OP_CHECKSIG OP_ADD {n} OP_EQUAL
scriptSig:
...signatures... up to 500 bytes
==Rationale==
OP_CHECKMULTISIG is already an enabled opcode, and is the most straightforward way to support several important use cases.
This is already specified in [[bip-0011.mediawiki|BIP 0011]].
However, each OP_CHECKMULTISIG counts toward the block limit as 20 sigops, which only allows 1000 total multisig transactions in a block.
Using OP_CHECKSIG only counts as 1 per signature, so can scale better.
==Implementation==
All used operations are already supported by old clients and miners as a non-standard transaction type.
================================================
FILE: bip-0020.mediawiki
================================================
BIP: 20
Layer: Applications
Title: URI Scheme
Authors: Luke Dashjr
Status: Closed
Type: Specification
Assigned: 2011-01-10
License: BSD-2-Clause
Proposed-Replacement: 21
BIP 0020 is based off an earlier document by Nils Schneider. '''And has been replaced by BIP 0021'''
==Abstract==
This BIP proposes a URI scheme for making Bitcoin payments.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
The purpose of this URI scheme is to enable users to easily make payments by simply clicking links on webpages or scanning QR Codes.
==Specification==
=== General rules for handling (important!) ===
Bitcoin clients MUST NOT act on URIs without getting the user's authorization.
They SHOULD require the user to manually approve each payment individually, though in some cases they MAY allow the user to automatically make this decision.
=== Operating system integration ===
Graphical bitcoin clients SHOULD register themselves as the handler for the "bitcoin:" URI scheme by default, if no other handler is already registered. If there is already a registered handler, they MAY prompt the user to change it once when they first run the client.
=== BNF grammar ===
(See also [[#Simpler syntax|a simpler representation of syntax]])
bitcoinurn = "bitcoin:" bitcoinaddress [ ";version=" bitcoinversion ] [ "?" bitcoinparams ]
bitcoinaddress = base58 *base58
bitcoinversion = "1.0"
bitcoinparams = *bitcoinparam
bitcoinparam = amountparam | labelparam | messageparam | sendparam | otherparam
amountparam = "amount=" amount
amount = amountdecimal | amounthex
amountdecimal = *digit [ "." *digit ] [ "X" *digit ]
amounthex = "x" *hexdigit [ "." *hexdigit ] [ "X" *hexdigit ]
labelparam = "label=" *pchar
messageparam = "message=" *pchar
sendparam = "send=" *pchar
otherparam = pchar *pchar "=" *pchar
=== Query Keys ===
*label: Label for that address (e.g. name of receiver)
*address: bitcoin address
*message: message that is shown to the user after scanning the QR code
*size: amount of base bitcoin units ([[#Transfer amount/size|see below]])
*send: used to send bitcoin, rather than to request them
*(others): optional, for future extensions
==== Transfer amount/size ====
If an amount is provided, it may be specified either in decimal or, when prefixed with a single "x" character, hexadecimal.
The number SHOULD be followed by "X" <digits> to signify an exponent to the base multiplier.
Thus, "X8" multiplies your number by 100,000,000.
For decimal values, this means the standard BTC unit.
For hexadecimal values, this means ᵇTBC units (which are equivalent to 42.94967296 BTC).
If exponent is omitted, implementations SHOULD assume X8 for decimal numbers, and X4 for hexadecimal numbers.
I.e. amount=50.00 is treated as 50 BTC, and amount=x40 is treated as 40 TBC.
When specifying bitcoin base units, "X0" SHOULD be used.
Bitcoin clients MAY display the amount in any format that is not intended to deceive the user.
They SHOULD choose a format that is foremost least confusing, and only after that most reasonable given the amount requested.
For example, so long as the majority of users work in BTC units, values should always be displayed in BTC by default, even if mBTC or TBC would otherwise be a more logical interpretation of the amount.
== Rationale ==
===Payment identifiers, not person identifiers===
Current best practices are that a unique address should be used for every transaction.
Therefore, a URI scheme should not represent an exchange of personal information, but a one-time payment.
===Accessibility (URI scheme name)===
Should someone from the outside happen to see such a URI, the URI scheme name already gives a description.
A quick search should then do the rest to help them find the resources needed to make their payment.
Other proposed names sound much more cryptic; the chance that someone googles that out of curiosity are much slimmer.
Also, very likely, what he will find are mostly technical specifications - not the best introduction to bitcoin.
==Forward compatibility==
We want URIs generated in 2011 to still work in 2036: think about extensibility.
Of course we can make only educated guesses about the future, but don't act as if there is none.
This should be the best we can do, but it should not be seen as set in stone.
Make it possible for later generations to improve our work, to mend our errors, without breaking the URIs created now.
== Appendix ==
=== Simpler syntax ===
This section is non-normative and does not cover all possible syntax.
Please see the [[#BNF grammar|BNF grammar]] above for the normative syntax.
[foo] means optional, <bar> are placeholders
bitcoin:[;version=1.0][?amount=][?label=
=== Examples ===
Just the address:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L
Address with name:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?label=Luke-Jr
Request 20.30 BTC to "Luke-Jr":
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=20.3X8&label=Luke-Jr
Request 400 TBC:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=x400X4
Request 4000 TBC:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=x4X7
Request 5 uBTC:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=5X2
Request 50 BTC with message:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=50X8&label=Luke-Jr&message=Donation%20for%20project%20xyz
Send 1 BTC:
bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJED9L?amount=1X8&send=S4b3N3oGqDqR5jNuxEvDwf
Characters must be URI encoded properly.
===Sending money via private key===
To send a payment to someone else first construct a new keypair. You may want to use a [[mini private key format]], or you may also use a full private key for more security depending on the amount being sent and how long you expect to pass before a claim. Now create and publish a transaction with an output of the amount you wish to send. Use this script in that output:
OP_CHECKSIG
Construct an address from the public key. Encode the URI as below:
bitcoin:?send=
You may optionally include amount or message fields as well. In a wallet to claim money sent this way search for an incoming transaction with the output script form above, where <address> matches the public key in the script. When you find the transaction create a claim transaction with an input script of this form:
This claims the money you were sent. Until your claim transaction has confirmed the sender may take their money back.
== Reference Implementations ==
=== Bitcoin clients ===
* [[Spesmilo]] supports all valid Bitcoin URIs, with Windows and KDE integration
=== Parsing amount ===
==== ECMAScript ====
BIP: 21
Layer: Applications
Title: URI Scheme
Authors: Nils Schneider
Matt Corallo
Status: Closed
Type: Specification
Assigned: 2012-01-29
Replaces: 20
Proposed-Replacement: 321
=Superseded by BIP 321=
This BIP has been superseded and replaced with BIP 321. Please see [[bip-0321.mediawiki|BIP 321]] instead.
=Original BIP=
This BIP is a modification of an earlier [[bip-0020.mediawiki|BIP 0020]] by Luke Dashjr. BIP 0020 was based off an earlier document by Nils Schneider. The alternative payment amounts in BIP 0020 have been removed.
==Abstract==
This BIP proposes a URI scheme for making Bitcoin payments.
==Motivation==
The purpose of this URI scheme is to enable users to easily make payments by simply clicking links on webpages or scanning QR Codes.
==Specification==
=== General rules for handling (important!) ===
Bitcoin clients MUST NOT act on URIs without getting the user's authorization.
They SHOULD require the user to manually approve each payment individually, though in some cases they MAY allow the user to automatically make this decision.
=== Operating system integration ===
Graphical bitcoin clients SHOULD register themselves as the handler for the "bitcoin:" URI scheme by default, if no other handler is already registered. If there is already a registered handler, they MAY prompt the user to change it once when they first run the client.
=== General Format ===
Bitcoin URIs follow the general format for URIs as set forth in RFC 3986. The path component consists of a bitcoin address, and the query component provides additional payment options.
Elements of the query component may contain characters outside the valid range. These must first be encoded according to UTF-8, and then each octet of the corresponding UTF-8 sequence must be percent-encoded as described in RFC 3986.
=== ABNF grammar ===
(See also [[#simpler-syntax|a simpler representation of syntax]])
bitcoinurn = "bitcoin:" bitcoinaddress [ "?" bitcoinparams ]
bitcoinaddress = *base58
bitcoinparams = bitcoinparam [ "&" bitcoinparams ]
bitcoinparam = [ amountparam / labelparam / messageparam / otherparam / reqparam ]
amountparam = "amount=" *digit [ "." *digit ]
labelparam = "label=" *qchar
messageparam = "message=" *qchar
otherparam = qchar *qchar [ "=" *qchar ]
reqparam = "req-" qchar *qchar [ "=" *qchar ]
Here, "qchar" corresponds to valid characters of an RFC 3986 URI query component, excluding the "=" and "&" characters, which this BIP takes as separators.
The scheme component ("bitcoin:") is case-insensitive, and implementations must accept any combination of uppercase and lowercase letters. The rest of the URI is case-sensitive, including the query parameter keys.
=== Query Keys ===
*label: Label for that address (e.g. name of receiver)
*address: bitcoin address
*message: message that describes the transaction to the user ([[#Examples|see examples below]])
*(others): optional, for future extensions
==== Transfer amount ====
If an amount is provided, it MUST be specified in decimal BTC.
All amounts MUST contain no commas and use a period (.) as the separating character to separate whole numbers and decimal fractions.
I.e. amount=50.00 or amount=50 is treated as 50 BTC, and amount=50,000.00 is invalid.
Bitcoin clients MAY display the amount in any format that is not intended to deceive the user.
They SHOULD choose a format that is foremost least confusing, and only after that most reasonable given the amount requested.
For example, so long as the majority of users work in BTC units, values should always be displayed in BTC by default, even if mBTC or TBC would otherwise be a more logical interpretation of the amount.
== Rationale ==
===Payment identifiers, not person identifiers===
Current best practices are that a unique address should be used for every transaction.
Therefore, a URI scheme should not represent an exchange of personal information, but a one-time payment.
===Accessibility (URI scheme name)===
Should someone from the outside happen to see such a URI, the URI scheme name already gives a description.
A quick search should then do the rest to help them find the resources needed to make their payment.
Other proposed names sound much more cryptic; the chance that someone googles that out of curiosity are much slimmer.
Also, very likely, what he will find are mostly technical specifications - not the best introduction to bitcoin.
==Forward compatibility==
Variables which are prefixed with a req- are considered required. If a client does not implement any variables which are prefixed with req-, it MUST consider the entire URI invalid. Any other variables which are not implemented, but which are not prefixed with a req-, can be safely ignored.
==Backward compatibility==
As this BIP is written, several clients already implement a bitcoin: URI scheme similar to this one, however usually without the additional "req-" prefix requirement. Thus, it is recommended that additional variables prefixed with req- not be used in a mission-critical way until a grace period of 6 months from the finalization of this BIP has passed in order to allow client developers to release new versions, and users of old clients to upgrade.
== Appendix ==
=== Simpler syntax ===
This section is non-normative and does not cover all possible syntax.
Please see the BNF grammar above for the normative syntax.
[foo] means optional, <bar> are placeholders
bitcoin:[?amount=][?label=
=== Examples ===
Note: The addresses used in these examples are intentionally invalid to prevent accidental transactions.
Just the address:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W
Address with name:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Luke-Jr
Request 20.30 BTC to "Luke-Jr":
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=20.3&label=Luke-Jr
Request 50 BTC with message:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz
Some future version that has variables which are (currently) not understood and required and thus invalid:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-somethingyoudontunderstand=50&req-somethingelseyoudontget=999
Some future version that has variables which are (currently) not understood but not required and thus valid:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?somethingyoudontunderstand=50&somethingelseyoudontget=999
Characters must be URI encoded properly.
== Reference Implementation ==
Bitcoin-Qt supports the old version of Bitcoin URIs (ie without the req- prefix), with Windows and KDE integration as of commit 70f55355e29c8e45b607e782c5d76609d23cc858.
================================================
FILE: bip-0022.mediawiki
================================================
==Abstract==
This BIP describes a new JSON-RPC method for "smart" Bitcoin miners and proxies.
Instead of sending a simple block header for hashing, the entire block structure is sent, and left to the miner to (optionally) customize and assemble.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Specification==
===Block Template Request===
A JSON-RPC method is defined, called "getblocktemplate".
It accepts exactly one argument, which MUST be an Object of request parameters.
If the request parameters include a "mode" key, that is used to explicitly select between the default "template" request or a [[bip-0023.mediawiki#Block Proposal|"proposal"]].
Block template creation can be influenced by various parameters:
{| class="wikitable"
!colspan=4|template request
|-
! Key !! Required !! Type !! Description
|-
| capabilities || No || Array of Strings || SHOULD contain a list of the following, to indicate client-side support: [[#Optional: Long Polling|"longpoll"]], "coinbasetxn", "coinbasevalue", [[bip-0023.mediawiki#Block Proposal|"proposal"]], [[bip-0023.mediawiki#Logical Services|"serverlist"]], "workid", and any of the [[bip-0023.mediawiki#Mutations|mutations]]
|-
| mode || No || String || MUST be "template" or omitted
|}
getblocktemplate MUST return a JSON Object containing the following keys:
{| class="wikitable"
!colspan=4| template
|-
! Key !! Required !! Type !! Description
|-
| bits || Yes || String || the compressed difficulty in hexadecimal
|-
| curtime || Yes || Number || the current time as seen by the server (recommended for block time) - note this is not necessarily the system clock, and must fall within the mintime/maxtime rules
|-
| height || Yes || Number || the height of the block we are looking for
|-
| previousblockhash || Yes || String || the hash of the previous block, in big-endian hexadecimal
|-
| sigoplimit || No || Number || number of sigops allowed in blocks
|-
| sizelimit || No || Number || number of bytes allowed in blocks
|-
| transactions || Should || Array of Objects || Objects containing [[#Transactions Object Format|information for Bitcoin transactions]] (excluding coinbase)
|-
| version || Yes || Number || always 1 or 2 (at least for bitcoin) - clients MUST understand the implications of the version they use (eg, comply with [[bip-0034.mediawiki|BIP 0034]] for version 2)
|-
| coinbaseaux || No || Object || data that SHOULD be included in the coinbase's scriptSig content. Only the values (hexadecimal byte-for-byte) in this Object should be included, not the keys. This does not include the block height, which is required to be included in the scriptSig by [[bip-0034.mediawiki|BIP 0034]]. It is advisable to encode values inside "PUSH" opcodes, so as to not inadvertently expend SIGOPs (which are counted toward limits, despite not being executed).
|-
| coinbasetxn || this or ↓ || Object || [[#Transactions Object Format|information for coinbase transaction]]
|-
| coinbasevalue || this or ↑ || Number || total funds available for the coinbase (in Satoshis)
|-
| workid || No || String || if provided, this value must be returned with results (see [[#Block Submission|Block Submission]])
|}
==== Transactions Object Format ====
The Objects listed in the response's "transactions" key contains these keys:
{| class="wikitable"
!colspan=3|template "transactions" element
|-
! Key !! Type !! Description
|-
| data || String || transaction data encoded in hexadecimal (byte-for-byte)
|-
| depends || Array of Numbers || other transactions before this one (by 1-based index in "transactions" list) that must be present in the final block if this one is; if key is not present, dependencies are unknown and clients MUST NOT assume there aren't any
|-
| fee || Number || difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one
|-
| hash || String || hash/id encoded in little-endian hexadecimal
|-
| required || Boolean || if provided and true, this transaction must be in the final block
|-
| sigops || Number || total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any
|}
Only the "data" key is required, but servers should provide the others if they are known.
===Block Submission===
A JSON-RPC method is defined, called "submitblock", to submit potential blocks (or shares).
It accepts two arguments:
the first is always a String of the hex-encoded block data to submit;
the second is an Object of parameters, and is optional if parameters are not needed.
{| class="wikitable"
!colspan=3|submitblock parameters (2nd argument)
|-
! Key !! Type !! Description
|-
| workid || String || if the server provided a workid, it MUST be included with submissions
|}
This method MUST return either null (when a share is accepted), a String describing briefly the reason the share was rejected, or an Object of these with a key for each merged-mining chain the share was submitted to.
===Optional: Long Polling===
{| class="wikitable"
! colspan="3" | template request
|-
! Key !! Type !! Description
|-
| capabilities || Array of Strings || miners which support long polling SHOULD provide a list including the String "longpoll"
|-
| longpollid || String || "longpollid" of job to monitor for expiration; required and valid only for long poll requests
|}
{| class="wikitable"
! colspan="3" | template
|-
! Key !! Type !! Description
|-
| longpollid || String || identifier for long poll request; MUST be omitted if the server does not support long polling
|-
| longpolluri || String || if provided, an alternate URI to use for long poll requests
|-
| submitold || Boolean || only relevant for long poll responses: indicates if work received prior to this response remains potentially valid (default) and should have its shares submitted; if false, the miner may wish to discard its share queue
|}
If the server supports long polling, it MUST include a "longpollid" key in block templates, and it MUST be unique for each event:
any given "longpollid" should check for only one condition and not be reused.
For example, a server which has a long poll wakeup only for new blocks might use the previous block hash.
However, clients should not assume the "longpollid" has any specific meaning.
It MAY supply the "longpolluri" key with a relative or absolute URI, which MAY specify a completely different resource than the original connection, including port number.
If "longpolluri" is provided by the server, clients MUST only attempt to use that URI for longpoll requests.
Clients MAY start a longpoll request with a standard JSON-RPC request (in the case of HTTP transport, POST with data) and same authorization, setting the "longpollid" parameter in the request to the value provided by the server.
This request SHOULD NOT be processed nor answered by the server until it wishes to replace the current block data as identified by the "longpollid".
Clients SHOULD make this request with a very long request timeout and MUST accept servers sending a partial response in advance (such as HTTP headers with "chunked" Transfer-Encoding), and only delaying the completion of the final JSON response until processing.
Upon receiving a completed response:
* Only if "submitold" is provided and false, the client MAY discard the results of past operations and MUST begin working on the new work immediately.
* The client SHOULD begin working on the new work received as soon as possible, if not immediately.
* The client SHOULD make a new request to the same long polling URI.
If a client receives an incomplete or invalid response, it SHOULD retry the request with an exponential backoff.
Clients MAY implement this backoff with limitations (such as maximum backoff time) or any algorithm as deemed suitable.
It is, however, forbidden to simply retry immediately with no delay after more than one failure.
In the case of a "Forbidden" response (for example, HTTP 403), a client SHOULD NOT attempt to retry without user intervention.
===Optional: Template Tweaking===
{| class="wikitable"
! colspan="3" | template request
|-
! Key !! Type !! Description
|-
| sigoplimit || Number or Boolean || maximum number of sigops to include in template
|-
| sizelimit || Number or Boolean || maximum number of bytes to use for the entire block
|-
| maxversion || Number || highest block version number supported
|}
For "sigoplimit" and "sizelimit", negative values and zero are offset from the server-determined block maximum.
If a Boolean is provided and true, the default limit is used; if false, the server is instructed not to use any limits on returned template.
Servers SHOULD respect these desired maximums, but are NOT required to:
clients SHOULD check that the returned template satisfies their requirements appropriately.
===Appendix: Example Rejection Reasons===
Possible reasons a share may be rejected include, but are not limited to:
{| class="wikitable"
!colspan=2| share rejection reasons
|-
! Reason !! Description
|-
| bad-cb-flag || the server detected a feature-signifying flag that it does not allow
|-
| bad-cb-length || the coinbase was too long (bitcoin limit is 100 bytes)
|-
| bad-cb-prefix || the server only allows appending to the coinbase, but it was modified beyond that
|-
| bad-diffbits || "bits" were changed
|-
| bad-prevblk || the previous-block is not the one the server intends to build on
|-
| bad-txnmrklroot || the block header's merkle root did not match the transaction merkle tree
|-
| bad-txns || the server didn't like something about the transactions in the block
|-
| bad-version || the version was wrong
|-
| duplicate || the server already processed this block data
|-
| high-hash || the block header did not hash to a value lower than the specified target
|-
| rejected || a generic rejection without details
|-
| stale-prevblk || the previous-block is no longer the one the server intends to build on
|-
| stale-work || the work this block was based on is no longer accepted
|-
| time-invalid || the time was not acceptable
|-
| time-too-new || the time was too far in the future
|-
| time-too-old || the time was too far in the past
|-
| unknown-user || the user submitting the block was not recognized
|-
| unknown-work || the template or workid could not be identified
|}
==Motivation==
bitcoind's JSON-RPC server can no longer support the load of generating the work required to productively mine Bitcoin, and external software specializing in work generation has become necessary.
At the same time, new independent node implementations are maturing to the point where they will also be able to support miners.
A common standard for communicating block construction details is necessary to ensure compatibility between the full nodes and work generation software.
==Rationale==
Why not just deal with transactions as hashes (txids)?
* Servers might not have access to the transaction database, or miners may wish to include transactions not broadcast to the network as a whole.
* Miners may opt not to do full transaction verification, and may not have access to the transaction database on their end.
What is the purpose of "workid"?
* If servers allow all mutations, it may be hard to identify which job it is based on. While it may be possible to verify the submission by its content, it is much easier to compare it to the job issued. It is very easy for the miner to keep track of this. Therefore, using a "workid" is a very cheap solution to enable more mutations.
Why should "sigops" be provided for transactions?
* Due to the [[bip-0016.mediawiki|BIP 0016]] changes regarding rules on block sigops, it is impossible to count sigops from the transactions themselves (the sigops in the scriptCheck must also be included in the count).
==Reference Implementation==
* [https://gitorious.org/bitcoin/eloipool Eloipool (server)]
* [http://gitorious.org/bitcoin/libblkmaker libblkmaker (client)]
* [https://github.com/bitcoin/bitcoin/pull/936/files bitcoind (minimal server)]
==See Also==
* [[bip-0023.mediawiki|BIP 23: getblocktemplate - Pooled Mining]]
================================================
FILE: bip-0023.mediawiki
================================================
BIP: 23
Layer: API/RPC
Title: getblocktemplate - Pooled Mining
Authors: Luke Dashjr
Status: Deployed
Type: Specification
Assigned: 2012-02-28
License: BSD-2-Clause
==Abstract==
This BIP describes extensions to the getblocktemplate JSON-RPC call to enhance pooled mining.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Specification==
Note that all sections of this specification are optional extensions on top of [[bip-0022.mediawiki|BIP 22]].
===Summary Support Levels===
Something can be said to have BIP 23 Level 1 support if it implements at least:
* [http://www.ietf.org/rfc/rfc1945.txt RFC 1945]
* [http://json-rpc.org/wiki/specification JSON-RPC 1.0]
* [[bip-0022.mediawiki|BIP 22 (non-optional sections)]]
* [[bip-0022.mediawiki#Optional: Long Polling|BIP 22 Long Polling]]
* [[#Basic Pool Extensions|BIP 23 Basic Pool Extensions]]
* [[#Mutations|BIP 23 Mutation "coinbase/append"]]
* [[#Submission Abbreviation|BIP 23 Submission Abbreviation "submit/coinbase"]]
* [[#Mutations|BIP 23 Mutation "time/increment"]] (only required for servers)
It can be said to have BIP 23 Level 2 support if it also implements:
* [[#Mutations|BIP 23 Mutation "transactions/add"]]
* [[#Block Proposals|BIP 23 Block Proposals]]
===Basic Pool Extensions===
{| class="wikitable"
! colspan="3" | template request
|-
! Key !! Type !! Description
|-
| target || String || desired target for block template (may be ignored)
|}
{| class="wikitable"
!colspan="3"| template
|-
! Key !! Type !! Description
|-
| expires || Number || how many seconds (beginning from when the server sent the response) this work is valid for, at most
|-
| target || String || the number which valid results must be less than, in big-endian hexadecimal
|}
===Block Proposal===
Servers may indicate support for proposing blocks by including a capability string in their original template:
{| class="wikitable"
!colspan="3"| template
|-
! Key !! Type !! Description
|-
| capabilities || Array of Strings || MAY contain "proposal" to indicate support for block proposal
|-
| reject-reason || String || Reason the proposal was invalid as-is (only applicable in response to proposals)
|}
If supported, a miner MAY propose a block to the server for general validation at any point before the job expires.
This is accomplished by calling getblocktemplate with two keys:
{| class="wikitable"
!colspan=3| getblocktemplate parameters
|-
! Key !! Type !! Description
|-
| data || String || MUST be hex-encoded block data
|-
| mode || String || MUST be "proposal"
|-
| workid || String || if the server provided a workid, it MUST be included with proposals
|}
The block data MUST be validated and checked against the server's usual acceptance rules (excluding the check for a valid proof-of-work).
If it is found to be in violation of any of these rules, the server MUST return one of the following:
* Null if it is acceptable as-is, with the same workid (if any) as provided. Note that this SHOULD NOT invalidate the old template's claim to the same workid.
* A String giving the reason for the rejection (see [[bip-0022.mediawiki#appendix-example-rejection-reasons|example rejection reasons]]).
* A "delta" block template (with changes needed); in this case, any missing keys are assumed to default to those in the proposed block or, if not applicable, the original block template it was based on. This template MAY also include a "reject-reason" key with a String of the reason for rejection.
It is RECOMMENDED that servers which merely need to track the proposed block for later share/* submissions, return a simple Object of the form:
{"workid":"new workid"}
Clients SHOULD assume their proposed block will remain valid if the only changes they make are to the portion of the coinbase scriptSig they themselves provided (if any) and the time header.
Servers SHOULD NOT break this assumption without good cause.
===Mutations===
{| class="wikitable"
! colspan="3" | template request
|-
! Key !! Type !! Description
|-
| nonces || Number || size of nonce range the miner needs; if not provided, the server SHOULD assume the client requires 232
|}
{| class="wikitable"
!colspan=3| template
|-
! Key !! Type !! Description
|-
| maxtime || Number || the maximum time allowed
|-
| maxtimeoff || Number || the maximum time allowed (as a moving offset from "curtime" - every second, the actual maxtime is incremented by 1; for example, "maxtimeoff":0 means "time" may be incremented by 1 every second)
|-
| mintime || Number || the minimum time allowed
|-
| mintimeoff || Number || the minimum time allowed (as a moving offset from "curtime")
|-
| mutable || Array of Strings || different manipulations that the server explicitly allows to be made
|-
| noncerange || String || two 32-bit integers, concatenated in big-endian hexadecimal, which represent the valid ranges of nonces the miner may scan
|}
If the block template contains a "mutable" key, it is a list of these to signify modifications the miner is allowed to make:
{| class="wikitable"
!colspan=2| mutations
|-
! Value !! Significance
|-
| coinbase/append
| append the provided coinbase scriptSig
|-
| coinbase
| provide their own coinbase; if one is provided, it may be replaced or modified (implied if "coinbasetxn" omitted)
|-
| generation
| add or remove outputs from the coinbase/generation transaction (implied if "coinbasetxn" omitted)
|-
| time/increment
| change the time header to a value after "time" (implied if "maxtime" or "maxtimeoff" are provided)
|-
| time/decrement
| change the time header to a value before "time" (implied if "mintime" is provided)
|-
| time
| modify the time header of the block
|-
| transactions/add (or "transactions")
| add other valid transactions to the block (implied if "transactions" omitted from result)
|-
| prevblock
| use the work with other previous-blocks; this implicitly allows removing transactions that are no longer valid (but clients SHOULD attempt to propose removal of any required transactions); it also implies adjusting "height" as necessary
|-
| version/force
| encode the provide block version, even if the miner doesn't understand it
|-
| version/reduce
| use an older block version than the one provided (for example, if the client does not support the version provided)
|}
===Submission Abbreviation===
{| class="wikitable"
!colspan=3| template
|-
! Key !! Type !! Description
|-
| fulltarget || String || the number which full results should be less than, in big-endian hexadecimal (see "share/*" mutations)
|-
| mutable || Array of Strings || different manipulations that the server explicitly allows to be made, including abbreviations
|}
If the block template contains a "mutable" key, it is a list of these to signify modifications the miner is allowed to make:
{| class="wikitable"
!colspan=2| abbreviation mutations
|-
! Value !! Significance
|-
| submit/hash
| each transaction being sent in a request, that the client is certain the server knows about, may be replaced by its hash in little-endian hexadecimal, prepended by a ":" character
|-
| submit/coinbase
| if the "transactions" provided by the server are used as-is with no changes, submissions may omit transactions after the coinbase (transaction count varint remains included with the full number of transactions)
|-
| submit/truncate
| if the "coinbasetxn" and "transactions" provided by the server are used as-is with no changes, submissions may contain only the block header; if only the scriptSig of "coinbasetxn" is modified, the params Object MUST contain a "coinbasesig" key with the content, or a "coinbaseadd" with appended data (if only appending)
|-
| share/coinbase
| same as "submit/coinbase", but only if the block hash is greater than "fulltarget"
|-
| share/merkle
| if the block hash is greater than "fulltarget", the non-coinbase transactions may be replaced with a merkle chain connecting it to the root
|-
| share/truncate
| same as "submit/truncate", but only if the block hash is greater than "fulltarget"
|}
==== Format of Data for Merkle-Only Shares ====
The format used for submitting shares with the "share/merkle" mutation shall be the 80-byte block header, the total number of transactions encoded in Bitcoin variable length number format, the coinbase transaction, and then finally the little-endian SHA256 hashes of each link in the merkle chain connecting it to the merkle root.
===Logical Services===
{| class="wikitable"
! colspan="3" | template request
|-
! Key !! Type !! Description
|-
| capabilities || Array of Strings || miners which support this SHOULD provide a list including the String "serverlist"
|}
{| class="wikitable"
!colspan=3| template
|-
! Key !! Type !! Description
|-
| serverlist || Array of Objects || list of servers in this single logical service
|}
If the "serverlist" parameter is provided, clients MAY choose to intelligently treat the server as part of a larger single logical service.
Each host Object in the Array is comprised of the following fields:
{| class="wikitable"
!colspan=3| serverlist element
|-
! Key !! Type !! Description
|-
| uri || String || URI of the individual server; if authentication information is omitted, the same authentication used for this request MUST be assumed
|-
| avoid || Number || number of seconds to avoid using this server
|-
| priority || Number || an integer priority of this host (default: 0)
|-
| sticky || Number || number of seconds to stick to this server when used
|-
| update || Boolean || whether this server may update the serverlist (default: true)
|-
| weight || Number || a relative weight for hosts with the same priority (default: 1)
|}
When choosing which actual server to get the next job from, URIs MUST be tried in order of their "priority" key, lowest Number first.
Where the priority of URIs is the same, they should be chosen from in random order, weighed by their "weight" key.
Work proposals and submissions MUST be made to the same server that issued the job.
Clients MAY attempt to submit to other servers if, and only if, the original server cannot be reached.
If cross-server share submissions are desired, services SHOULD instead use the equivalent domain name system (DNS) features (RFCs [http://tools.ietf.org/html/rfc1794 1794] and [http://tools.ietf.org/html/rfc2782 2782]).
Updates to the Logical Service server list may only be made by the original server, or servers listed with the "update" key missing or true.
Clients MAY choose to advertise serverlist capability to servers with a false "update" key, but if so, MUST treat the server list provided as a subset of the current one, only considered in the context of this server.
At least one server with "update" privilege MUST be attempted at least once daily.
If the "sticky" key is provided, then when that server is used, it should be used consistently for at least that many seconds, if possible.
A permanent change in server URI MAY be indicated with a simple "serverlist" parameter:
"serverlist":[{"uri": "http://newserver"}]
A temporary delegation to another server for 5 minutes MAY be indicated likewise:
"serverlist":[{"uri": "", avoid: 300}, {"uri": "http://newserver", "update": false}]
==Motivation==
There is reasonable concerns about mining currently being too centralized on pools, and the amount of control these pools hold.
By exposing the details of the block proposals to the miners, they are enabled to audit and possibly modify the block before hashing it.
To encourage widespread adoption, this BIP should be a complete superset of the existing centralized getwork protocol, so pools are not required to make substantial changes to adopt it.
==Rationale==
Why allow servers to restrict the complete coinbase and nonce range?
* This is necessary to provide a complete superset of JSON-RPC getwork functionality, so that pools may opt to enable auditing without significantly changing or increasing the complexity of their share validation or mining policies.
* Since noncerange is optional (both for getwork and this BIP), neither clients nor servers are required to support it.
Why specify "time/*" mutations at all?
* In most cases, these are implied by the mintime/mintimecur/maxtime/maxtimecur keys, but there may be cases that there are no applicable minimums/maximums.
What is the purpose of the "prevblock" mutation?
* There are often cases where a miner has processed a new block before the server. If the server allows "prevblock" mutation, the miner may begin mining on the new block immediately, without waiting for a new template.
Why must both "mintime"/"maxtime" and "mintimeoff"/"maxtimeoff" keys be defined?
* In some cases, the limits may be unrelated to the current time (such as the Bitcoin network itself; the minimum is always a fixed median time)
* In other cases, the limits may be bounded by other rules (many pools limit the time header to within 5 minutes of when the share is submitted to them).
Is "target" really needed?
* Some pools work with lower targets, and should not be expected to waste bandwidth ignoring shares that don't meet it.
* Required to be a proper superset of getwork.
* As mining hashrates grow, some miners may need the ability to request a lower target from their pools to be able to manage their bandwidth use.
What is the purpose of the "hash" transaction list format?
* Non-mining tools may wish to simply get a list of memory pool transactions.
* Humans may wish to view their current memory pool.
==Reference Implementation==
* [http://gitorious.org/bitcoin/libblkmaker libblkmaker]
* [https://gitorious.org/bitcoin/eloipool Eloipool]
* [https://github.com/bitcoin/bitcoin/pull/936/files bitcoind]
==See Also==
* [[bip-0022.mediawiki|BIP 22: getblocktemplate - Fundamentals]]
================================================
FILE: bip-0030.mediawiki
================================================
==Abstract==
This document gives a specification for dealing with duplicate transactions in the block chain, in an attempt to solve certain problems the reference implementation has with them.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
So far, the Bitcoin reference implementation always assumed duplicate transactions (transactions with the same identifier) didn't exist. This is not true; in particular coinbases are easy to duplicate, and by building on duplicate coinbases, duplicate normal transactions are possible as well. Recently, an attack that exploits the reference implementation's dealing with duplicate transactions was described and demonstrated. It allows reverting fully-confirmed transactions to a single confirmation, making them vulnerable to become unspendable entirely. Another attack is possible that allows forking the block chain for a subset of the network.
==Specification==
To counter this problem, the following network rule is introduced:
*Blocks are not allowed to contain a transaction whose identifier matches that of an earlier, not-fully-spent transaction in the same chain.
This rule initially applied to all blocks whose timestamp is after March 15, 2012, 00:00 UTC (testnet: February 20, 2012 00:00 UTC). It was later extended by Commit [https://github.com/bitcoin/bitcoin/commit/ab91bf39b7c11e9c86bb2043c24f0f377f1cf514 Apply BIP30 checks to all blocks except the two historic violations.] to apply to all blocks except the two historic blocks at heights 91842 and 91880 on the main chain that had to be grandfathered in.
==Rationale==
Whatever solution is used, the following law must be obeyed to guarantee sane behaviour: the set of usable
transactions outputs must not be modified by adding blocks to the chain and removing them again. This happens during
a reorganisation, and the current Bitcoin reference implementation does not obey this law in case the temporarily
added blocks contain a duplicate transaction.
There are several potential solutions to this problem:
#Guarantee that all coinbases are unique, making duplicate transactions very hard to create.
#Remember previous remaining outputs of a given transaction identifier, in case a new transaction with the same identifier is added.
#Only allow duplicate transactions in case the previous instance of the transaction had no spendable outputs left. Removing a block from the chain can then safely reset the removed transaction's outputs to nothing.
The first option is probably the most complete one, as it also guarantees transaction identifiers are unique. However, implementing it requires several changes that need to be accepted throughout the network. Furthermore, it does not prevent duplicate transactions based on earlier duplicate coinbases. The second option is impossible to implement in a forward-compatible way, as it potentially renders currently-invalid blocks valid. In this document we choose for the third option, because it only requires a trivial change.
Fully-spent transactions are allowed to be duplicated in order not to hinder pruning at some point in the future. Not allowing any transaction to be duplicated would require evidence to be kept for each transaction ever made.
==Backward compatibility==
The addition of this rule only makes some previously-valid blocks invalid. This implies that if the rule is implemented by a supermajority of miners, it is not possible to fork the block chain in a permanent way between nodes with and without the new rule.
==Implementation==
A patch for the reference client can be found on https://github.com/sipa/bitcoin/tree/nooverwritetx
This BIP was implemented in Commit [https://github.com/bitcoin/bitcoin/commit/a206b0ea12eb4606b93323268fc81a4f1f952531 Do not allow overwriting unspent transactions (BIP 30)]
There have been additional commits to refine the implementation of this BIP.
==Acknowledgements==
Thanks to Russell O'Connor for finding and demonstrating this problem, and helping test the patch.
================================================
FILE: bip-0031.mediawiki
================================================
==Abstract==
This document describes a trivial protocol extension that makes it easier for clients to detect dead peer connections.
==Motivation==
Today there are a few network related problems that can degrade the Bitcoin user experience:
1) Some Bitcoin clients run on platforms that can go to sleep and essentially stop running at any time without warning. Notably, this is very common on both mobiles and laptops (shut the lid). When the system comes back, TCP connections that existed before the sleep still exist but may no longer function correctly, eg, because the IP address has changed, or because the remote peer went away or the connection was timed out by some other system. Currently it can often take a while to notice this has happened.
2) The reference Satoshi client is largely single threaded and when placed under heavy load (e.g., because it is downloading the block chain) becomes very slow to respond to network messages. There's no easy way to detect this has occurred, especially if you are just passively waiting for broadcasts from that peer. A way to detect overloaded remote peers and avoid them would both help balance load and provide a better, more responsive system.
3) When downloading large data structures like the block chain it is efficient to choose a peer that is near to you network-wise, in order to reduce load on often congested trans-national links and ensure lower latency. Currently it is difficult to measure the latency to a remote peer so clients don't bother, and instead just select a random peer to download from.
All of these can be solved by a backwards compatible protocol modification.
==Specification==
When the protocol version as negotiated in the "ver" message is greater than 60000, the "ping" message must contain a uint64 field called "nonce". A peer sending "ping" should set the nonce to a random value, and it is then echoed back by the recipient in a new "pong" message that also contains a single uint64 field.
In this way, the client can send a ping and measure the time taken to receive the corresponding pong. If a client sends two pings before hearing back the first pong, the responses can be distinguished using the nonce. If the client chooses to never overlap pings in this way it should simply set the nonce value to zero.
==Backward compatibility==
Clients must opt-in to the new feature by advertising a protocol version > 60000. Clients with older protocol versions are not expected to provide a nonce in the ping message and will not be sent a pong.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/932/files
================================================
FILE: bip-0032.mediawiki
================================================
RECENT CHANGES:
* (16 Apr 2013) Added private derivation for i ≥ 0x80000000 (less risk of parent private key leakage)
* (30 Apr 2013) Switched from multiplication by IL to addition of IL (faster, easier implementation)
* (25 May 2013) Added test vectors
* (15 Jan 2014) Rename keys with index ≥ 0x80000000 to hardened keys, and add explicit conversion functions.
* (24 Feb 2017) Added test vectors for hardened derivation with leading zeros
* (4 Nov 2020) Added new test vectors for hardened derivation with leading zeros
==Abstract==
This document describes hierarchical deterministic wallets (or "HD Wallets"): wallets which can be shared partially or entirely with different systems, each with or without the ability to spend coins.
The specification is intended to set a standard for deterministic wallets that can be interchanged between different clients. Although the wallets described here have many features, not all are required by supporting clients.
The specification consists of two parts. In the first part, a system for deriving a tree of keypairs from a single seed is presented. The second part demonstrates how to build a wallet structure on top of such a tree.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
The Bitcoin reference client uses randomly generated keys. In order to avoid the necessity for a backup after every transaction, (by default) 100 keys are cached in a pool of reserve keys. Still, these wallets are not intended to be shared and used on several systems simultaneously. They support hiding their private keys by using the wallet encrypt feature and not sharing the password, but such "neutered" wallets lose the power to generate public keys as well.
Deterministic wallets do not require such frequent backups, and elliptic curve mathematics permit schemes where one can calculate the public keys without revealing the private keys. This permits for example a webshop business to let its webserver generate fresh addresses (public key hashes) for each order or for each customer, without giving the webserver access to the corresponding private keys (which are required for spending the received funds).
However, deterministic wallets typically consist of a single "chain" of keypairs. The fact that there is only one chain means that sharing a wallet happens on an all-or-nothing basis. However, in some cases one only wants some (public) keys to be shared and recoverable. In the example of a webshop, the webserver does not need access to all public keys of the merchant's wallet; only to those addresses which are used to receive customers' payments, and not for example the change addresses that are generated when the merchant spends money. Hierarchical deterministic wallets allow such selective sharing by supporting multiple keypair chains, derived from a single root.
==Specification: Key derivation==
===Conventions===
In the rest of this text we will assume the public key cryptography used in Bitcoin, namely elliptic curve cryptography using the field and curve parameters defined by secp256k1 (http://www.secg.org/sec2-v2.pdf). Variables below are either:
* Integers modulo the order of the curve (referred to as n).
* Coordinates of points on the curve.
* Byte sequences.
Addition (+) of two coordinate pair is defined as application of the EC group operation.
Concatenation (||) is the operation of appending one byte sequence onto another.
As standard conversion functions, we assume:
* point(p): returns the coordinate pair resulting from EC point multiplication (repeated application of the EC group operation) of the secp256k1 base point with the integer p (i.e., the operation used to compute a public key from a private key).
* ser32(i): serialize a 32-bit unsigned integer i as a 4-byte sequence, most significant byte first.
* ser256(p): serializes the integer p as a 32-byte sequence, most significant byte first.
* serP(P): serializes the coordinate pair P = (x,y) (i.e., the public key) as a byte sequence using [https://www.secg.org/sec1-v2.pdf SEC1]'s compressed form: (0x02 or 0x03) || ser256(x), where the header byte depends on the parity of the omitted y coordinate.
* parse256(p): interprets a 32-byte sequence as a 256-bit number, most significant byte first.
===Extended keys===
In what follows, we will define a function that derives a number of child keys from a parent key. In order to prevent these from depending solely on the key itself, we extend both private and public keys first with an extra 256 bits of entropy. This extension, called the chain code, is identical for corresponding private and public keys, and consists of 32 bytes.
We represent an extended private key as (k, c), with k the normal private key, and c the chain code. An extended public key is represented as (K, c), with K = point(k) and c the chain code.
Each extended key has 231 normal child keys, and 231 hardened child keys. Each of these child keys has an index. The normal child keys use indices 0 through 231-1. The hardened child keys use indices 231 through 232-1. To ease notation for hardened key indices, a number iH represents i+231.
===Child key derivation (CKD) functions===
Given a parent extended key and an index i, it is possible to compute the corresponding child extended key. The algorithm to do so depends on whether the child is a hardened key or not (or, equivalently, whether i ≥ 231), and whether we're talking about private or public keys.
====Private parent key → private child key====
The function CKDpriv((kpar, cpar), i) → (ki, ci) computes a child extended private key from the parent extended private key:
* Check whether i ≥ 231 (whether the child is a hardened key).
** If so (hardened child): let I = HMAC-SHA512(Key = cpar, Data = 0x00 || ser256(kpar) || ser32(i)). (Note: The 0x00 pads the private key to make it 33 bytes long.)
** If not (normal child): let I = HMAC-SHA512(Key = cpar, Data = serP(point(kpar)) || ser32(i)).
* Split I into two 32-byte sequences, IL and IR.
* The returned child key ki is parse256(IL) + kpar (mod n).
* The returned chain code ci is IR.
* In case parse256(IL) ≥ n or ki = 0, the resulting key is invalid, and one should proceed with the next value for i. (Note: this has probability lower than 1 in 2127.)
The HMAC-SHA512 function is specified in [http://tools.ietf.org/html/rfc4231 RFC 4231].
====Public parent key → public child key====
The function CKDpub((Kpar, cpar), i) → (Ki, ci) computes a child extended public key from the parent extended public key. It is only defined for non-hardened child keys.
* Check whether i ≥ 231 (whether the child is a hardened key).
** If so (hardened child): return failure
** If not (normal child): let I = HMAC-SHA512(Key = cpar, Data = serP(Kpar) || ser32(i)).
* Split I into two 32-byte sequences, IL and IR.
* The returned child key Ki is point(parse256(IL)) + Kpar.
* The returned chain code ci is IR.
* In case parse256(IL) ≥ n or Ki is the point at infinity, the resulting key is invalid, and one should proceed with the next value for i.
====Private parent key → public child key====
The function N((k, c)) → (K, c) computes the extended public key corresponding to an extended private key (the "neutered" version, as it removes the ability to sign transactions).
* The returned key K is point(k).
* The returned chain code c is just the passed chain code.
To compute the public child key of a parent private key:
* N(CKDpriv((kpar, cpar), i)) (works always).
* CKDpub(N(kpar, cpar), i) (works only for non-hardened child keys).
The fact that they are equivalent is what makes non-hardened keys useful (one can derive child public keys of a given parent key without knowing any private key), and also what distinguishes them from hardened keys. The reason for not always using non-hardened keys (which are more useful) is security; see further below for more information.
====Public parent key → private child key====
This is not possible.
===The key tree===
The next step is cascading several CKD constructions to build a tree. We start with one root, the master extended key m. By evaluating CKDpriv(m,i) for several values of i, we get a number of level-1 derived nodes. As each of these is again an extended key, CKDpriv can be applied to those as well.
To shorten notation, we will write CKDpriv(CKDpriv(CKDpriv(m,3H),2),5) as m/3H/2/5. Equivalently for public keys, we write CKDpub(CKDpub(CKDpub(M,3),2),5) as M/3/2/5. This results in the following identities:
* N(m/a/b/c) = N(m/a/b)/c = N(m/a)/b/c = N(m)/a/b/c = M/a/b/c.
* N(m/aH/b/c) = N(m/aH/b)/c = N(m/aH)/b/c.
However, N(m/aH) cannot be rewritten as N(m)/aH, as the latter is not possible.
Each leaf node in the tree corresponds to an actual key, while the internal nodes correspond to the collections of keys that descend from them. The chain codes of the leaf nodes are ignored, and only their embedded private or public key is relevant. Because of this construction, knowing an extended private key allows reconstruction of all descendant private keys and public keys, and knowing an extended public key allows reconstruction of all descendant non-hardened public keys.
===Key identifiers===
Extended keys can be identified by the Hash160 (RIPEMD160 after SHA256) of the serialized ECDSA public key K, ignoring the chain code. This corresponds exactly to the data used in traditional Bitcoin addresses. It is not advised to represent this data in base58 format though, as it may be interpreted as an address that way (and wallet software is not required to accept payment to the chain key itself).
The first 32 bits of the identifier are called the key fingerprint.
===Serialization format===
Extended public and private keys are serialized as follows:
* 4 bytes: version bytes (mainnet: 0x0488B21E public, 0x0488ADE4 private; testnet: 0x043587CF public, 0x04358394 private)
* 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 derived keys, ....
* 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
* 4 bytes: child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. (0x00000000 if master key)
* 32 bytes: the chain code
* 33 bytes: the public key or private key data (serP(K) for public keys, 0x00 || ser256(k) for private keys)
This 78 byte structure can be encoded like other Bitcoin data in Base58, by first adding 32 checksum bits (derived from the double SHA-256 checksum), and then converting to the Base58 representation. This results in a Base58-encoded string of exactly 111 characters. Because of the choice of the version bytes, the Base58 representation will start with "xprv" or "xpub" on mainnet, "tprv" or "tpub" on testnet.
Note that the fingerprint of the parent only serves as a fast way to detect parent and child nodes in software, and software must be willing to deal with collisions. Internally, the full 160-bit identifier could be used.
When importing a serialized extended public key, implementations must verify whether the X coordinate in the public key data corresponds to a point on the curve. If not, the extended public key is invalid.
===Master key generation===
The total number of possible extended keypairs is almost 2512, but the produced keys are only 256 bits long, and offer about half of that in terms of security. Therefore, master keys are not generated directly, but instead from a potentially short seed value.
* Generate a seed byte sequence S of a chosen length (between 128 and 512 bits; 256 bits is advised) from a (P)RNG.
* Calculate I = HMAC-SHA512(Key = "Bitcoin seed", Data = S)
* Split I into two 32-byte sequences, IL and IR.
* Use parse256(IL) as master secret key, and IR as master chain code.
In case parse256(IL) is 0 or parse256(IL) ≥ n, the master key is invalid.
==Specification: Wallet structure==
The previous sections specified key trees and their nodes. The next step is imposing a wallet structure on this tree. The layout defined in this section is a default only, though clients are encouraged to mimic it for compatibility, even if not all features are supported.
===The default wallet layout===
An HDW is organized as several 'accounts'. Accounts are numbered, the default account ("") being number 0. Clients are not required to support more than one account - if not, they only use the default account.
Each account is composed of two keypair chains: an internal and an external one. The external keychain is used to generate new public addresses, while the internal keychain is used for all other operations (change addresses, generation addresses, ..., anything that doesn't need to be communicated). Clients that do not support separate keychains for these should use the external one for everything.
* m/iH/0/k corresponds to the k'th keypair of the external chain of account number i of the HDW derived from master m.
* m/iH/1/k corresponds to the k'th keypair of the internal chain of account number i of the HDW derived from master m.
===Use cases===
====Full wallet sharing: m====
In cases where two systems need to access a single shared wallet, and both need to be able to perform spendings, one needs to share the master private extended key. Nodes can keep a pool of N look-ahead keys cached for external chains, to watch for incoming payments. The look-ahead for internal chains can be very small, as no gaps are to be expected here. An extra look-ahead could be active for the first unused account's chains - triggering the creation of a new account when used. Note that the name of the account will still need to be entered manually and cannot be synchronized via the block chain.
====Audits: N(m/*)====
In case an auditor needs full access to the list of incoming and outgoing payments, one can share all account public extended keys. This will allow the auditor to see all transactions from and to the wallet, in all accounts, but not a single secret key.
====Per-office balances: m/iH====
When a business has several independent offices, they can all use wallets derived from a single master. This will allow the headquarters to maintain a super-wallet that sees all incoming and outgoing transactions of all offices, and even permit moving money between the offices.
====Recurrent business-to-business transactions: N(m/iH/0)====
In case two business partners often transfer money, one can use the extended public key for the external chain of a specific account (M/i h/0) as a sort of "super address", allowing frequent transactions that cannot (easily) be associated, but without needing to request a new address for each payment.
Such a mechanism could also be used by mining pool operators as a variable payout address.
====Unsecure money receiver: N(m/iH/0)====
When an unsecure webserver is used to run an e-commerce site, it needs to know public addresses that are used to receive payments. The webserver only needs to know the public extended key of the external chain of a single account. This means someone illegally obtaining access to the webserver can at most see all incoming payments but will not be able to steal the money, will not (trivially) be able to distinguish outgoing transactions, nor be able to see payments received by other webservers if there are several.
==Compatibility==
To comply with this standard, a client must at least be able to import an extended public or private key, to give access to its direct descendants as wallet keys. The wallet structure (master/account/chain/subchain) presented in the second part of the specification is advisory only, but is suggested as a minimal structure for easy compatibility - even when no separate accounts or distinction between internal and external chains is made. However, implementations may deviate from it for specific needs; more complex applications may call for a more complex tree structure.
==Security==
In addition to the expectations from the EC public-key cryptography itself:
* Given a public key K, an attacker cannot find the corresponding private key more efficiently than by solving the EC discrete logarithm problem (assumed to require 2128 group operations).
the intended security properties of this standard are:
* Given a child extended private key (ki,ci) and the integer i, an attacker cannot find the parent private key kpar more efficiently than a 2256 brute force of HMAC-SHA512.
* Given any number (2 ≤ N ≤ 232-1) of (index, extended private key) tuples (ij,(kij,cij)), with distinct ij's, determining whether they are derived from a common parent extended private key (i.e., whether there exists a (kpar,cpar) such that for each j in (0..N-1) CKDpriv((kpar,cpar),ij)=(kij,cij)), cannot be done more efficiently than a 2256 brute force of HMAC-SHA512.
Note however that the following properties do not exist:
* Given a parent extended public key (Kpar,cpar) and a child public key (Ki), it is hard to find i.
* Given a parent extended public key (Kpar,cpar) and a non-hardened child private key (ki), it is hard to find kpar.
===Implications===
Private and public keys must be kept safe as usual. Leaking a private key means access to coins - leaking a public key can mean loss of privacy.
Somewhat more care must be taken regarding extended keys, as these correspond to an entire (sub)tree of keys.
One weakness that may not be immediately obvious, is that knowledge of a parent extended public key plus any non-hardened private key descending from it is equivalent to knowing the parent extended private key (and thus every private and public key descending from it). This means that extended public keys must be treated more carefully than regular public keys.
It is also the reason for the existence of hardened keys, and why they are used for the account level in the tree. This way, a leak of account-specific (or below) private keys never risks compromising the master or other accounts.
==Test Vectors==
===Test vector 1===
Seed (hex): 000102030405060708090a0b0c0d0e0f
* Chain m
** ext pub: xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8
** ext prv: xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi
* Chain m/0H
** ext pub: xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw
** ext prv: xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
* Chain m/0H/1
** ext pub: xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ
** ext prv: xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
* Chain m/0H/1/2H
** ext pub: xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5
** ext prv: xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM
* Chain m/0H/1/2H/2
** ext pub: xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV
** ext prv: xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334
* Chain m/0H/1/2H/2/1000000000
** ext pub: xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy
** ext prv: xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76
===Test vector 2===
Seed (hex): fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542
* Chain m
** ext pub: xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB
** ext prv: xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U
* Chain m/0
** ext pub: xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH
** ext prv: xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt
* Chain m/0/2147483647H
** ext pub: xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a
** ext prv: xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9
* Chain m/0/2147483647H/1
** ext pub: xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon
** ext prv: xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef
* Chain m/0/2147483647H/1/2147483646H
** ext pub: xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL
** ext prv: xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc
* Chain m/0/2147483647H/1/2147483646H/2
** ext pub: xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt
** ext prv: xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j
===Test vector 3===
These vectors test for the retention of leading zeros. See [https://github.com/bitpay/bitcore-lib/issues/47 bitpay/bitcore-lib#47] and [https://github.com/iancoleman/bip39/issues/58 iancoleman/bip39#58] for more information.
Seed (hex): 4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be
* Chain m
** ext pub: xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13
** ext prv: xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6
* Chain m/0H
** ext pub: xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y
** ext prv: xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L
===Test vector 4===
These vectors test for the retention of leading zeros. See [https://github.com/btcsuite/btcutil/issues/172 btcsuite/btcutil#172] for more information.
Seed (hex): 3ddd5602285899a946114506157c7997e5444528f3003f6134712147db19b678
* Chain m
** ext pub: xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa
** ext prv: xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv
* Chain m/0H
** ext pub: xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m
** ext prv: xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G
* Chain m/0H/1H
** ext pub: xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt
** ext prv: xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1
===Test vector 5===
These vectors test that invalid extended keys are recognized as invalid.
* xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm (pubkey version / prvkey mismatch)
* xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH (prvkey version / pubkey mismatch)
* xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn (invalid pubkey prefix 04)
* xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ (invalid prvkey prefix 04)
* xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4 (invalid pubkey prefix 01)
* xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J (invalid prvkey prefix 01)
* xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv (zero depth with non-zero parent fingerprint)
* xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ (zero depth with non-zero parent fingerprint)
* xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN (zero depth with non-zero index)
* xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8 (zero depth with non-zero index)
* DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4 (unknown extended key version)
* DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9 (unknown extended key version)
* xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx (private key 0 not in 1..n-1)
* xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G (private key n not in 1..n-1)
* xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY (invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007)
* xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL (invalid checksum)
==Acknowledgements==
* Gregory Maxwell for the original idea of type-2 deterministic wallets, and many discussions about it.
* Alan Reiner for the implementation of this scheme in Armory, and the suggestions that followed from that.
* Eric Lombrozo for reviewing and revising this BIP.
* Mike Caldwell for the version bytes to obtain human-recognizable Base58 strings.
================================================
FILE: bip-0033.mediawiki
================================================
== Abstract ==
As the Bitcoin network scales, roles are fast becoming specialised. In the beginning, a single Bitcoin user would perform the synonymous roles of miner, merchant and end-user. With the growth however of this system, these functions are being abstracted away to specialised services as a natural part of Bitcoin's growth.
Bitcoin's blockchain becomes more unwieldy for end users over time, negatively affecting the usability of Bitcoin clients. As it grows, it becomes ever more impractical to deal with on portable devices or low end machines. Several proposals have been put forward to deal with this such as lightweight (headers-only) clients and skipping validation for blocks before the last checkpoint. However these measures are at best stop-gap workarounds to stave off a growing problem.
This document will examine a proposal which will be termed ''stratized nodes'', a modification of an earlier concept termed ''blockchain service''.
== History ==
Jan Moller created BCCAPI in 2011. BCCAPI allowed a user's client to delegate blockchain interaction to a remote server. This server would store and manage the blockchain while the user client would run queries against that server.
ThomasV later created Electrum server. BCCAPI's server backend was proprietary, and Electrum required a full Free Software stack. Electrum's server was an adhoc temporary replacement. As it grew and became used, issues started to appear in its design.
Marek Palatinus (slush) drafted a new standard called Stratum to replace Electrum's server. Stratum has multiple transports and is usable as a blockchain server by merchants, miners and user-clients. Electrum moved to using a Stratum implementation first relying on ABE/bitcoind and more recently libbitcoin.
Stratum is unmaintained by Marek Palatinus, suffers from easy resource starvation and denial of service attacks, and is insecure. The proposal specified here is intended to replace the Stratum's role as a blockchain for user-clients. The proposal here is solely concerned with removing the onus of blockchain validation and lookups from user-clients to specialised services in a secure manner. Any secondary benefits or uses are purely incidental.
== Overview ==
During the initial handshake between Bitcoin nodes, a version packet is sent. version packets have a bitfield called services. Nodes can fill this field to tell the network how they behave and which services they support. NODE_NETWORK (1) means a node can be asked for full blocks for example.
We propose two more values of NODE_SERVICE (2) and NODE_STRATIZED (4).
=== NODE_SERVICE ===
* A blockchain service which supports the additional messages "getoutputs" and "getspends".
* Does not respond to "getdata" messages by itself (unless NODE_NETWORK is specified)
* If NODE_NETWORK is specified, then "getdata" for transactions will retrieve them not only from the memory pool but also check the blockchain if necessary.
=== NODE_STRATIZED ===
* A node which uses the stratized strategy specified in this document.
* NODE_STRATIZED will relay inventories for accepted transactions.
* Does not support "getblocks" as stratized nodes do not contain the entire blockchain.
Apart from the differences noted above, the nodes are otherwise unchanged in their behaviour from NODE_NETWORK.
== Specification ==
=== Initialisation ===
Four new messages are defined which are represented below in C-like pseudocode.
"getoutputs"
These four messages allow a node to discover the history of a Bitcoin address without needing direct access to the blockchain.
A typical use case might look like:
# Send "getoutputs" for a decoded Bitcoin address.
# Receive "outputs", and loop through each contained output point:
## Send "getdata" to download the transaction for that point.
## Send "getspend" for each output point.
# Receive "spend":
## Send "getdata" to download the transaction for that input point.
This sequence allows the gradual but fast build up of history for an address.
=== Updates ===
Nodes receive "inv" messages as normal from service nodes, issuing "getdata" to download the block or transaction data. From this they check for newly sent (in the input points) or received (in the output points) payments in the transaction data.
Note that blocks must at minimum have their merkle root validated and transactions must be checked for uniqueness by stratized nodes.
== Security ==
The concern here is that stratized nodes are at the mercy of blockchain services. This proposal deals with that issue by designing this protocol in such a way that the implementation can resolve the common history between multiple services.
A stratized node will typically connect to 8 blockchain services. It will only accept an output, spend or inventory vector that has been sent by a common subset of all those services (6 in our example). This spreads the risk between all services, and does not make a node vulnerable to any one rogue blockchain service.
== Privacy ==
The other strategy for thin clients termed ''headers-only'' or ''Simplified. Payment. Verification.'' have the same privacy issues as this proposal. SPV resolves this problem by sending out fake requests for transaction data which obfuscates the client data. By sending out a sufficient number of fake requests, privacy can be kept to a sufficient level.
== Rationale ==
NODE_SERVICE does not respond to "getdata" requests by itself (unless used in conjunction with NODE_NETWORK) to prevent starvation attacks. This allows a single trusted NODE_SERVICE architecture (possibly acting as a front-end to multiple backends) to service very many nodes while externalising the costs to the Bitcoin network.
NODE_STRATIZED tries its best to maintain the facade and help upkeep the Bitcoin network (see relaying), but cannot support "getblocks" as it does not have the entire blockchain.
== Backwards Compatibility ==
This proposal is an addon to the current Bitcoin network, and is completely backwards compatible.
================================================
FILE: bip-0034.mediawiki
================================================
==Abstract==
Bitcoin blocks and transactions are versioned binary structures. Both currently use version 1. This BIP introduces an upgrade path for versioned transactions and blocks. A unique value is added to newly produced coinbase transactions, and blocks are updated to version 2.
==Motivation==
# Clarify and exercise the mechanism whereby the bitcoin network collectively consents to upgrade transaction or block binary structures, rules and behaviors.
# Enforce block and transaction uniqueness, and assist unconnected block validation.
==Specification==
# Treat transactions with a version greater than 1 as non-standard (official Satoshi client will not mine or relay them).
# Add height as the first item in the coinbase transaction's scriptSig, and increase block version to 2. The format of the height is "minimally encoded serialized CScript" -- first byte is number of bytes in the number (will be 0x03 on main net for the next 150 or so years with 223-1 blocks), following bytes are little-endian representation of the number (including a sign bit). Height is the height of the mined block in the block chain, where the genesis block is height zero (0).
# 75% rule: If 750 of the last 1,000 blocks are version 2 or greater, reject invalid version 2 blocks. (testnet3: 51 of last 100)
# 95% rule ("Point of no return"): If 950 of the last 1,000 blocks are version 2 or greater, reject all version 1 blocks. (testnet3: 75 of last 100)
==Backward compatibility==
All older clients are compatible with this change. Users and merchants should not be impacted. Miners are strongly recommended to upgrade to version 2 blocks. Once 95% of the miners have upgraded to version 2, the remainder will be orphaned if they fail to upgrade.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/1526
==Result==
Block number 227,835 (timestamp 2013-03-24 15:49:13 GMT) was the last version 1 block.
================================================
FILE: bip-0035.mediawiki
================================================
==Abstract==
Make a network node's transaction memory pool accessible via a new "mempool" message. Extend the existing "getdata" message behavior to permit accessing the transaction memory pool.
==Motivation==
Several use cases make it desirable to expose a network node's transaction memory pool:
# SPV clients, wishing to obtain zero-confirmation transactions sent or received.
# Miners, to avoid missing lucrative fees, downloading existing network transactions after a restart.
# Remote network diagnostics.
==Specification==
# The mempool message is defined as an empty message where pchCommand == "mempool"
# Upon receipt of a "mempool" message, the node will respond with an "inv" message containing MSG_TX hashes of all the transactions in the node's transaction memory pool, if any.
# The typical node behavior in response to an "inv" is "getdata". However, the reference Satoshi implementation ignores requests for transaction hashes outside that which is recently relayed. To support "mempool", an implementation must extend its "getdata" message support to querying the memory pool.
# Feature discovery is enabled by checking two "version" message attributes:
## Protocol version >= 60002
## NODE_NETWORK bit set in nServices
Note that existing implementations drop "inv" messages with a vector size > 50000.
==Backward compatibility==
Older clients remain 100% compatible and interoperable after this change.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/1641
================================================
FILE: bip-0036.mediawiki
================================================
BIP: 36
Layer: Peer Services
Title: Custom Services
Authors: Stefan Thomas
Status: Closed
Type: Specification
Assigned: 2012-08-03
License: PD
==Abstract==
This BIP adds new fields to the version message which clients can use to announce custom services without polluting the limited 64-bit services field. It also makes some non-binding recommendations regarding the implementation of custom services.
==Motivation==
We would like to encourage experimentation with custom services that extend the Bitcoin protocol with useful functionality. Examples include Distributed Hash Tables (DHT), distributed pools, lightweight client support protocols, directed message routing and support for custom transports. However, without a general framework for protocol extensions, these custom services are likely to collide in various ways. This BIP provides such a framework.
==Specification==
Two new fields are added to the version command, after extra_height:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 1+ || service_count || [[Protocol_specification#Variable_length_integer|var_int]] || Number of extra services
|-
| ? || service_list || service[] || List of service definitions
|}
The service definitions service[] are given in the following format:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| ? || service_name || [[#Variable length string|var_str]] || Unique service identifier
|-
| 4 || service_version || uint32_t || Identifies service version being used by the node
|-
| ? || service_data || [[#Variable length string|var_str]] || Additional service-specific data
|}
A node MUST NOT announce two services with the same service_name. If a remote node sends such a version message the client MAY disconnect.
The service_version is service-specific and can be any integer. Higher versions SHOULD be higher integers. When a service is standardized, it is assigned a NODE_* constant for use with the services field and future iterations of the protocol depend on the Bitcoin protocol version. Both the NODE_* flag and the custom service entry MAY be provided for the duration of a transitional period.
Services SHOULD pass an empty string (0x00) as service_data and use a custom handshake to initialize their protocol, exchange information about capabilities etc. Note that to become a standardized service, a service MUST NOT rely on service_data since there is no corresponding mechanism for the standard services defined in the services field.
However, services MAY use service_data if they do not intend to become standard services and need a simple way to transmit a small amount of initialization data. For example, a node offering a custom transport like UDP or WebSocket, may choose to announce this as a service and include the port number in service_data. The format for service_data is service-specific and may be any binary or ASCII data. For ease of debugging, a human-readable (ASCII) format is generally recommended.
===Service identifier===
Each service SHOULD choose a new identifier that is not used by any other service. To register a new identifier, add it to the [[Service identifiers]] wiki page along with the name of the maintainer and a way to contact them. Please do not register identifiers unless you are actually using them.
Service identifiers that are reserved or used by an accepted BIP MUST NOT be used except in the way specified by that BIP.
Service identifiers MUST be between five (5) and eleven (11) characters long. Service identifiers MUST use only ASCII characters, excluding: / * _ :
Valid examples:
* MySampleSvc
* smartserv
* P-Pool
Valid, but discouraged examples:
* MySVC 1.0 (use service_version to differentiate versions)
* @@---. (identifiers should be pronounceable)
* lightweight (avoid too generic names)
Invalid examples:
* Pppc (too short)
* SuperService (too long)
* Cool_Svc (invalid character)
===Optional: Custom commands===
Bitcoin command names are limited to 12 characters. That doesn't leave a lot of space for both the service identifier and the service command. Therefore we recommend that all service commands SHOULD be represented by a single "command" on the Bitcoin network. This command SHOULD consist of the exact service identifier to avoid collisions with other services, prefixed by an underscore to avoid collisions with current or future Bitcoin protocol messages. For example: _MySampleSvc
The service-specific command name SHOULD then be specified in an extra header in the payload:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 12 || subcommand || char[12] || ASCII string identifying the service command, NULL padded (non-NULL padding results in packet rejected)
|-
| ? || subpayload || uchar[] || The actual data
|}
The length of subpayload is derived from the length of the total payload minus twelve (12) bytes for the subcommand. Implementations MUST NOT rely on this format to be used by unknown services. Clients SHOULD ignore any services or subcommands they don't explicitly understand.
The recommended way to refer to messages following this format in documentation is by the service identifier, followed by a colon, followed by the subcommand. For example, the subcommand search for the MySampleSvc service would be referred to as: MySampleSvc:search
Full hexdump of an example MySampleSvc:search message:
==Standardization==
Custom services may become standard parts of the protocol. Services which wish to become part of the Bitcoin protocol MUST fulfill the following criteria:
* MUST NOT use service_data; Standard services have no corresponding field
* MUST use a peer discovery mechanism which specifies one bit per node, same as the services field in addr messages
* MUST NOT use any subcommands that conflict with current or planned Bitcoin protocol commands
The standardization process will usually take place as follows:
# The service is implemented and tested.
# Once the API is known to be relatively stable it is formalized and submitted as a BIP.
# Once the BIP is accepted, the service is assigned a NODE_* constant and the transitional period starts:
#* Clients MUST understand both the announcement of the service via the services field and via service_list and include both methods in their own version message.
#* Clients MUST accept both the wrapped form messages like MySampleSvc:search as well as the corresponding non-namespaced messages like search. Clients MUST only send wrapped messages.
#* During the transitional period the API of the service MUST NOT change.
# After the transitional period:
#* Clients MUST only announce the service via the services field.
#* Clients MUST only send unwrapped messages.
# Future changes to the service API now require a BIP and an increase in the Bitcoin protocol version.
This process of adding a service to the Bitcoin protocol should only be undertaken for services where there is a strong rationale for doing so. Services MAY also be standardized as custom services via a BIP while maintaining the custom service format.
==Rationale==
This BIP aims to fulfill the following goals:
* Minimize the risk of namespace collisions, ambiguities or other issues arising from conflicting custom services
* Provide an easy upgrade path for custom services to become standardized services with their own NODE_* flag
* Place minimum restrictions on custom service authors
* Allow custom services to be created with minimum effort
* Allow clients to support multiple/many custom services at once
To achieve these goals this BIP adds two new fields to the version message. It would have been possible to avoid changes to version by adding a new message instead. However, it makes sense to keep both types of service announcements in the same message so that the life cycle of standardized services and custom services remains exactly the same. This also simplifies detecting a service which is in the transition from a custom to a standardized service (and being announced using both methods.)
Finally, this BIP defines both explicitly and implicitly some useful common nomenclature that can be used when discussing custom services, e.g. "subcommand", "subpayload", "service identifier" and the colon format for referring to subcommands.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0037.mediawiki
================================================
BIP: 37
Layer: Peer Services
Title: Connection Bloom filtering
Authors: Mike Hearn
Matt Corallo
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0037
Status: Deployed
Type: Specification
Assigned: 2012-10-24
License: PD
==Abstract==
This BIP adds new support to the peer-to-peer protocol that allows peers to reduce the amount of transaction data they are sent. Peers have the option of setting ''filters'' on each connection they make after the version handshake has completed. A filter is defined as a [http://en.wikipedia.org/wiki/Bloom_filter Bloom filter] on data derived from transactions. A Bloom filter is a probabilistic data structure which allows for testing set membership - they can have false positives but not false negatives.
This document will not go into the details of how Bloom filters work and the reader is referred to Wikipedia for an introduction to the topic.
==Motivation==
As Bitcoin grows in usage the amount of bandwidth needed to download blocks and transaction broadcasts increases. Clients implementing ''simplified payment verification'' do not attempt to fully verify the block chain, instead just checking that block headers connect together correctly and trusting that the transactions in a chain of high difficulty are in fact valid. See the Bitcoin paper for more detail on this mode.
Today, [[https://bitcoin.org/en/developer-guide#simplified-payment-verification-spv|SPV]] clients have to download the entire contents of blocks and all broadcast transactions, only to throw away the vast majority of the transactions that are not relevant to their wallets. This slows down their synchronization process, wastes users bandwidth (which on phones is often metered) and increases memory usage. All three problems are triggering real user complaints for the Android "Bitcoin Wallet" app which implements SPV mode. In order to make chain synchronization fast, cheap and able to run on older phones with limited memory we want to have remote peers throw away irrelevant transactions before sending them across the network.
==Design rationale==
The most obvious way to implement the stated goal would be for clients to upload lists of their keys to the remote node. We take a more complex approach for the following reasons:
* Privacy: Because Bloom filters are probabilistic, with the false positive rate chosen by the client, nodes can trade off precision vs bandwidth usage. A node with access to lots of bandwidth may choose to have a high FP rate, meaning the remote peer cannot accurately know which transactions belong to the client and which don't. A node with very little bandwidth may choose to use a very accurate filter meaning that they only get sent transactions actually relevant to their wallet, but remote peers may be able to correlate transactions with IP addresses (and each other).
* Bloom filters are compact and testing membership in them is fast. This results in satisfying performance characteristics with minimal risk of opening up potential for DoS attacks.
==Specification==
===New messages===
We start by adding three new messages to the protocol:
* filterload, which sets the current Bloom filter on the connection
* filteradd, which adds the given data element to the connections current filter without requiring a completely new one to be set
* filterclear, which deletes the current filter and goes back to regular pre-BIP37 usage.
Note that there is no filterremove command because by their nature, Bloom filters are append-only data structures. Once an element is added it cannot be removed again without rebuilding the entire structure from scratch.
The filterload command is defined as follows:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| ? || filter || uint8_t[] || The filter itself is simply a bit field of arbitrary byte-aligned size. The maximum size is 36,000 bytes.
|-
| 4 || nHashFuncs || uint32_t || The number of hash functions to use in this filter. The maximum value allowed in this field is 50.
|-
| 4 || nTweak || uint32_t || A random value to add to the seed value in the hash function used by the bloom filter.
|-
| 1 || nFlags || uint8_t || A set of flags that control how matched items are added to the filter.
|}
See below for a description of the Bloom filter algorithm and how to select nHashFuncs and filter size for a desired false positive rate.
Upon receiving a filterload command, the remote peer will immediately restrict the broadcast transactions it announces (in inv packets) to transactions matching the filter, where the matching algorithm is specified below. The flags control the update behaviour of the matching algorithm.
The filteradd command is defined as follows:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| ? || data || uint8_t[] || The data element to add to the current filter.
|}
The data field must be smaller than or equal to 520 bytes in size (the maximum size of any potentially matched object).
The given data element will be added to the Bloom filter. A filter must have been previously provided using filterload. This command is useful if a new key or script is added to a clients wallet whilst it has connections to the network open, it avoids the need to re-calculate and send an entirely new filter to every peer (though doing so is usually advisable to maintain anonymity).
The filterclear command has no arguments at all.
After a filter has been set, nodes don't merely stop announcing non-matching transactions, they can also serve filtered blocks. A filtered block is defined by the merkleblock message and is defined like this:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 4 || version || uint32_t || Block version information, based upon the software version creating this block
|-
| 32 || prev_block || char[32] || The hash value of the previous block this particular block references
|-
| 32 || merkle_root || char[32] || The reference to a Merkle tree collection which is a hash of all transactions related to this block
|-
| 4 || timestamp || uint32_t || A timestamp recording when this block was created (Limited to 2106!)
|-
| 4 || bits || uint32_t || The calculated difficulty target being used for this block
|-
| 4 || nonce || uint32_t || The nonce used to generate this block… to allow variations of the header and compute different hashes
|-
| 4 || total_transactions || uint32_t || Number of transactions in the block (including unmatched ones)
|-
| ? || hashes || uint256[] || hashes in depth-first order (including standard varint size prefix)
|-
| ? || flags || byte[] || flag bits, packed per 8 in a byte, least significant bit first (including standard varint size prefix)
|}
See below for the format of the partial merkle tree hashes and flags.
Thus, a merkleblock message is a block header, plus a part of a merkle tree which can be used to extract identifying information for transactions that matched the filter and prove that the matching transaction data really did appear in the solved block. Clients can use this data to be sure that the remote node is not feeding them fake transactions that never appeared in a real block, although lying through omission is still possible.
===Extensions to existing messages===
The version command is extended with a new field:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 1 byte || fRelay || bool || If false then broadcast transactions will not be announced until a filter{load,add,clear} command is received. If missing or true, no change in protocol behaviour occurs.
|}
SPV clients that wish to use Bloom filtering would normally set fRelay to false in the version message, then set a filter based on their wallet (or a subset of it, if they are overlapping different peers). Being able to opt-out of inv messages until the filter is set prevents a client being flooded with traffic in the brief window of time between finishing version handshaking and setting the filter.
The getdata command is extended to allow a new type in the inv submessage. The type field can now be MSG_FILTERED_BLOCK (== 3) rather than MSG_BLOCK. If no filter has been set on the connection, a request for filtered blocks is ignored. If a filter has been set, a merkleblock message is returned for the requested block hash. In addition, because a merkleblock message contains only a list of transaction hashes, transactions matching the filter should also be sent in separate tx messages after the merkleblock is sent. This avoids a slow roundtrip that would otherwise be required (receive hashes, didn't see some of these transactions yet, ask for them). Note that because there is currently no way to request transactions which are already in a block from a node (aside from requesting the full block), the set of matching transactions that the requesting node hasn't either received or announced with an inv must be sent and any additional transactions which match the filter may also be sent. This allows for clients (such as the reference client) to limit the number of invs it must remember a given node to have announced while still providing nodes with, at a minimum, all the transactions it needs.
===Filter matching algorithm===
The filter can be tested against arbitrary pieces of data, to see if that data was inserted by the client. Therefore the question arises of what pieces of data should be inserted/tested.
To determine if a transaction matches the filter, the following algorithm is used. Once a match is found the algorithm aborts.
# Test the hash of the transaction itself.
# For each output, test each data element of the output script. This means each hash and key in the output script is tested independently. '''Important:''' if an output matches whilst testing a transaction, the node might need to update the filter by inserting the serialized COutPoint structure. See below for more details.
# For each input, test the serialized COutPoint structure.
# For each input, test each data element of the input script (note: input scripts only ever contain data elements).
# Otherwise there is no match.
In this way addresses, keys and script hashes (for P2SH outputs) can all be added to the filter. You can also match against classes of transactions that are marked with well known data elements in either inputs or outputs, for example, to implement various forms of [[https://en.bitcoin.it/wiki/Smart_Property|Smart property]].
The test for outpoints is there to ensure you can find transactions spending outputs in your wallet, even though you don't know anything about their form. As you can see, once set on a connection the filter is '''not static''' and can change throughout the connections lifetime. This is done to avoid the following race condition:
# A client sets a filter matching a key in their wallet. They then start downloading the block chain. The part of the chain that the client is missing is requested using getblocks.
# The first block is read from disk by the serving peer. It contains TX 1 which sends money to the clients key. It matches the filter and is thus sent to the client.
# The second block is read from disk by the serving peer. It contains TX 2 which spends TX 1. However TX 2 does not contain any of the clients keys and is thus not sent. The client does not know the money they received was already spent.
By updating the bloom filter atomically in step 2 with the discovered outpoint, the filter will match against TX 2 in step 3 and the client will learn about all relevant transactions, despite that there is no pause between the node processing the first and second blocks.
The nFlags field of the filter controls the nodes precise update behaviour and is a bit field.
* BLOOM_UPDATE_NONE (0) means the filter is not adjusted when a match is found.
* BLOOM_UPDATE_ALL (1) means if the filter matches any data element in a scriptPubKey the outpoint is serialized and inserted into the filter.
* BLOOM_UPDATE_P2PUBKEY_ONLY (2) means the outpoint is inserted into the filter only if a data element in the scriptPubKey is matched, and that script is of the standard "pay to pubkey" or "pay to multisig" forms.
These distinctions are useful to avoid too-rapid degradation of the filter due to an increasing false positive rate. We can observe that a wallet which expects to receive only payments of the standard pay-to-address form doesn't need automatic filter updates because any transaction that spends one of its own outputs has a predictable data element in the input (the pubkey that hashes to the address). If a wallet might receive pay-to-address outputs and also pay-to-pubkey or pay-to-multisig outputs then BLOOM_UPDATE_P2PUBKEY_ONLY is appropriate, as it avoids unnecessary expansions of the filter for the most common types of output but still ensures correct behaviour with payments that explicitly specify keys.
Obviously, nFlags == 1 or nFlags == 2 mean that the filter will get dirtier as more of the chain is scanned. Clients should monitor the observed false positive rate and periodically refresh the filter with a clean one.
===Partial Merkle branch format===
A ''Merkle tree'' is a way of arranging a set of items as leaf nodes of tree in which the interior nodes are hashes of the concatenations of their child hashes. The root node is called the ''Merkle root''. Every Bitcoin block contains a Merkle root of the tree formed from the blocks transactions. By providing some elements of the trees interior nodes (called a ''Merkle branch'') a proof is formed that the given transaction was indeed in the block when it was being mined, but the size of the proof is much smaller than the size of the original block.
====Constructing a partial merkle tree object====
* Traverse the merkle tree from the root down, and for each encountered node:
** Check whether this node corresponds to a leaf node (transaction) that is to be included OR any parent thereof:
*** If so, append a '1' bit to the flag bits
*** Otherwise, append a '0' bit.
** Check whether this node is an internal node (non-leaf) AND is the parent of an included leaf node:
*** If so:
**** Descend into its left child node, and process the subtree beneath it entirely (depth-first).
**** If this node has a right child node too, descend into it as well.
*** Otherwise: append this node's hash to the hash list.
====Parsing a partial merkle tree object====
As the partial block message contains the number of transactions in the entire block, the shape of the merkle tree is known before hand. Again, traverse this tree, computing traversed node's hashes along the way:
* Read a bit from the flag bit list:
** If it is '0':
*** Read a hash from the hashes list, and return it as this node's hash.
** If it is '1' and this is a leaf node:
*** Read a hash from the hashes list, store it as a matched txid, and return it as this node's hash.
** If it is '1' and this is an internal node:
*** Descend into its left child tree, and store its computed hash as L.
*** If this node has a right child as well:
**** Descend into its right child, and store its computed hash as R.
**** If L == R, the partial merkle tree object is invalid.
**** Return Hash(L || R).
*** If this node has no right child, return Hash(L || L).
The partial merkle tree object is only valid if:
* All hashes in the hash list were consumed and no more.
* All bits in the flag bits list were consumed (except padding to make it into a full byte), and no more.
* The hash computed for the root node matches the block header's merkle root.
* The block header is valid, and matches its claimed proof of work.
* In two-child nodes, the hash of the left and right branches was never equal.
===Bloom filter format===
A Bloom filter is a bit-field in which bits are set based on feeding the data element to a set of different hash functions. The number of hash functions used is a parameter of the filter. In Bitcoin we use version 3 of the 32-bit Murmur hash function. To get N "different" hash functions we simply initialize the Murmur algorithm with the following formula:
nHashNum * 0xFBA4C795 + nTweak
i.e. if the filter is initialized with 4 hash functions and a tweak of 0x00000005, when the second function (index 1) is needed h1 would be equal to 4221880218.
When loading a filter with the filterload command, there are two parameters that can be chosen. One is the size of the filter in bytes. The other is the number of hash functions to use. To select the parameters you can use the following formulas:
Let N be the number of elements you wish to insert into the set and P be the probability of a false positive, where 1.0 is "match everything" and zero is unachievable.
The size S of the filter in bytes is given by (-1 / pow(log(2), 2) * N * log(P)) / 8. Of course you must ensure it does not go over the maximum size (36,000: selected as it represents a filter of 20,000 items with false positive rate of < 0.1% or 10,000 items and a false positive rate of < 0.0001%).
The number of hash functions required is given by S * 8 / N * log(2).
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0038.mediawiki
================================================
BIP: 38
Layer: Applications
Title: Passphrase-protected private key
Authors: Mike Caldwell
Aaron Voisine
Comments-Summary: Unanimously Discourage for implementation
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0038
Status: Draft (Some confusion applies: The announcements for this never made it to the list, so it hasn't had public discussion)
Type: Specification
Assigned: 2012-11-20
License: PD
==Abstract==
A method is proposed for encrypting and encoding a passphrase-protected Bitcoin private key record in the form of a 58-character Base58Check-encoded printable string. Encrypted private key records are intended for use on paper wallets and physical Bitcoins. Each record string contains all the information needed to reconstitute the private key except for a passphrase, and the methodology uses salting and ''scrypt'' to resist brute-force attacks.
The method provides two encoding methodologies - one permitting any known private key to be encrypted with any passphrase, and another permitting a shared private key generation scheme where the party generating the final key string and its associated Bitcoin address (such as a physical bitcoin manufacturer) knows only a string derived from the original passphrase, and where the original passphrase is needed in order to actually redeem funds sent to the associated Bitcoin address.
A 32-bit hash of the resulting Bitcoin address is encoded in plaintext within each encrypted key, so it can be correlated to a Bitcoin address with reasonable probability by someone not knowing the passphrase. The complete Bitcoin address can be derived through successful decryption of the key record.
==Motivation==
The motivation to make this proposal stems from observations of the way physical bitcoins and paper wallets are used.
An issuer of physical bitcoins must be trustworthy and trusted. Even if trustworthy, users are rightful to be skeptical about a third party with theoretical access to take their funds. A physical bitcoin that cannot be compromised by its issuer is always more intrinsically valuable than one that can.
A two-factor physical bitcoin solution is highly useful to individuals and organizations wishing to securely own bitcoins without any risk of electronic theft and without the responsibility of climbing the technological learning curve necessary to produce such an environment themselves. Two-factor physical bitcoins allow a secure storage solution to be put in a box and sold on the open market, greatly enlarging the number of people who are able to securely store bitcoins.
Existing methodologies for creating two-factor physical bitcoins are limited and cumbersome. At the time of this proposal, a user could create their own private key, submit the public key to the physical bitcoin issuer, and then receive a physical bitcoin that must be kept together with some sort of record of the user-generated private key, and finally, must be redeemed through a tool. The fact that the physical bitcoin must be kept together with a user-produced private key negates much of the benefit of the physical bitcoin - the user may as well just print and maintain a private key.
A standardized password-protected private key format makes acquiring and redeeming two-factor physical bitcoins simpler for the user. Instead of maintaining a private key that cannot be memorized, the user may choose a passphrase of their choice. The passphrase may be much shorter than the length of a typical private key, short enough that they could use a label or engraver to permanently commit their passphrase to their physical Bitcoin piece once they have received it. By adopting a standard way to encrypt a private key, we maximize the possibility that they'll be able to redeem their funds in the venue of their choice, rather than relying on an executable redemption tool they may not wish to download.
Password and passphrase-protected private keys enable new practical use cases for sending bitcoins from person to person. Someone wanting to send bitcoins through postal mail could send a password-protected paper wallet and give the recipient the passphrase over the phone or e-mail, making the transfer safe from interception of either channel. A user of paper wallets or Bitcoin banknote-style vouchers ("cash") could carry funded encrypted private keys while leaving a copy at home as an element of protection against accidental loss or theft. A user of paper wallets who leaves bitcoins in a bank vault or safety deposit box could keep the password at home or share it with trusted associates as protection against someone at the bank gaining access to the paper wallets and spending from them. The foreseeable and unforeseeable use cases for password-protected private keys are numerous.
==Copyright==
This proposal is hereby placed in the public domain.
==Rationale==
:'' '''User story:''' As a Bitcoin user who uses paper wallets, I would like the ability to add encryption, so that my Bitcoin paper storage can be two factor: something I have plus something I know.''
:'' '''User story:''' As a Bitcoin user who would like to pay a person or a company with a private key, I do not want to worry that any part of the communication path may result in the interception of the key and theft of my funds. I would prefer to offer an encrypted private key, and then follow it up with the password using a different communication channel (e.g. a phone call or SMS).''
:'' '''User story:''' (EC-multiplied keys) As a user of physical bitcoins, I would like a third party to be able to create password-protected Bitcoin private keys for me, without them knowing the password, so I can benefit from the physical bitcoin without the issuer having access to the private key. I would like to be able to choose a password whose minimum length and required format does not preclude me from memorizing it or engraving it on my physical bitcoin, without exposing me to an undue risk of password cracking and/or theft by the manufacturer of the item.''
:'' '''User story:''' (EC-multiplied keys) As a user of paper wallets, I would like the ability to generate a large number of Bitcoin addresses protected by the same password, while enjoying a high degree of security (highly expensive scrypt parameters), but without having to incur the scrypt delay for each address I generate.''
==Specification==
This proposal makes use of the following functions and definitions:
*'''AES256Encrypt, AES256Decrypt''': the simple form of the well-known AES block cipher without consideration for initialization vectors or block chaining. Each of these functions takes a 256-bit key and 16 bytes of input, and deterministically yields 16 bytes of output.
*'''SHA256''', a well-known hashing algorithm that takes an arbitrary number of bytes as input and deterministically yields a 32-byte hash.
*'''scrypt''': A well-known key derivation algorithm. It takes the following parameters: (string) password, (string) salt, (int) n, (int) r, (int) p, (int) length, and deterministically yields an array of bytes whose length is equal to the length parameter.
*'''ECMultiply''': Multiplication of an elliptic curve point by a scalar integer with respect to the secp256k1 elliptic curve.
*'''G, N''': Constants defined as part of the secp256k1 elliptic curve. G is an elliptic curve point, and N is a large positive integer.
*'''Base58Check''': a method for encoding arrays of bytes using 58 alphanumeric characters commonly used in the Bitcoin ecosystem.
===Prefix===
It is proposed that the resulting Base58Check-encoded string start with a '6'. The number '6' is intended to represent, from the perspective of the user, "a private key that needs something else to be usable" - an umbrella definition that could be understood in the future to include keys participating in multisig transactions, and was chosen with deference to the existing prefix '5' most commonly observed in Wallet Import Format which denotes an unencrypted private key.
It is proposed that the second character ought to give a hint as to what is needed as a second factor, and for an encrypted key requiring a passphrase, the uppercase letter P is proposed.
To keep the size of the encrypted key down, no initialization vectors (IVs) are used in the AES encryption. Rather, suitable values for IV-like use are derived using scrypt from the passphrase and from using a 32-bit hash of the resulting Bitcoin address as salt.
===Proposed specification===
* Object identifier prefix: 0x0142 (non-EC-multiplied) or 0x0143 (EC-multiplied). These are constant bytes that appear at the beginning of the Base58Check-encoded record, and their presence causes the resulting string to have a predictable prefix.
* How the user sees it: 58 characters always starting with '6P'
** Visual cues are present in the third character for visually identifying the EC-multiply and compress flag.
* Count of payload bytes (beyond prefix): 37
** 1 byte (''flagbyte''):
*** the most significant two bits are set as follows to preserve the visibility of the compression flag in the prefix, as well as to keep the payload within the range of allowable values that keep the "6P" prefix intact. For non-EC-multiplied keys, the bits are 11. For EC-multiplied keys, the bits are 00.
*** the bit with value 0x20 when set indicates the key should be converted to a base58check encoded P2PKH bitcoin address using the DER compressed public key format. When not set, it should be a base58check encoded P2PKH bitcoin address using the DER uncompressed public key format.
*** the bits with values 0x10 and 0x08 are reserved for a future specification that contemplates using multisig as a way to combine the factors such that parties in possession of the separate factors can independently sign a proposed transaction without requiring that any party possess both factors. These bits must be 0 to comply with this version of the specification.
*** the bit with value 0x04 indicates whether a lot and sequence number are encoded into the first factor, and activates special behavior for including them in the decryption process. This applies to EC-multiplied keys only. Must be 0 for non-EC-multiplied keys.
*** remaining bits are reserved for future use and must all be 0 to comply with this version of the specification.
** 4 bytes: SHA256(SHA256(expected_bitcoin_address))[0...3], used both for typo checking and as salt
**16 bytes: Contents depend on whether EC multiplication is used.
**16 bytes: lasthalf: An AES-encrypted key material record (contents depend on whether EC multiplication is used)
* Range in base58check encoding for non-EC-multiplied keys without compression (prefix 6PR):
** Minimum value: 6PRHv1jg1ytiE4kT2QtrUz8gEjMQghZDWg1FuxjdYDzjUkcJeGdFj9q9Vi (based on 01 42 C0 plus thirty-six 00's)
** Maximum value: 6PRWdmoT1ZursVcr5NiD14p5bHrKVGPG7yeEoEeRb8FVaqYSHnZTLEbYsU (based on 01 42 C0 plus thirty-six FF's)
* Range in base58check encoding for non-EC-multiplied keys with compression (prefix 6PY):
** Minimum value: 6PYJxKpVnkXUsnZAfD2B5ZsZafJYNp4ezQQeCjs39494qUUXLnXijLx6LG (based on 01 42 E0 plus thirty-six 00's)
** Maximum value: 6PYXg5tGnLYdXDRZiAqXbeYxwDoTBNthbi3d61mqBxPpwZQezJTvQHsCnk (based on 01 42 E0 plus thirty-six FF's)
* Range in base58check encoding for EC-multiplied keys without compression (prefix 6Pf):
** Minimum value: 6PfKzduKZXAFXWMtJ19Vg9cSvbFg4va6U8p2VWzSjtHQCCLk3JSBpUvfpf (based on 01 43 00 plus thirty-six 00's)
** Maximum value: 6PfYiPy6Z7BQAwEHLxxrCEHrH9kasVQ95ST1NnuEnnYAJHGsgpNPQ9dTHc (based on 01 43 00 plus thirty-six FF's)
* Range in base58check encoding for EC-multiplied keys with compression (prefix 6Pn):
** Minimum value: 6PnM2wz9LHo2BEAbvoGpGjMLGXCom35XwsDQnJ7rLiRjYvCxjpLenmoBsR (based on 01 43 20 plus thirty-six 00's)
** Maximum value: 6PnZki3vKspApf2zym6Anp2jd5hiZbuaZArPfa2ePcgVf196PLGrQNyVUh (based on 01 43 20 plus thirty-six FF's)
====Encryption when EC multiply flag is not used====
Encrypting a private key without the EC multiplication offers the advantage that any known private key can be encrypted. The party performing the encryption must know the passphrase.
Encryption steps:
# Compute the Bitcoin address (ASCII), and take the first four bytes of SHA256(SHA256()) of it. Let's call this "addresshash".
# Derive a key from the passphrase using scrypt
#*Parameters: ''passphrase'' is the passphrase itself encoded in UTF-8 and normalized using Unicode Normalization Form C (NFC). salt is ''addresshash'' from the earlier step, n=16384, r=8, p=8, length=64 (n, r, p are provisional and subject to consensus)
#*Let's split the resulting 64 bytes in half, and call them ''derivedhalf1'' and ''derivedhalf2''.
# Do AES256Encrypt(block = bitcoinprivkey[0...15] xor derivedhalf1[0...15], key = derivedhalf2), call the 16-byte result ''encryptedhalf1''
# Do AES256Encrypt(block = bitcoinprivkey[16...31] xor derivedhalf1[16...31], key = derivedhalf2), call the 16-byte result ''encryptedhalf2''
The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum:
* 0x01 0x42 + ''flagbyte'' + ''salt'' + ''encryptedhalf1'' + ''encryptedhalf2''
Decryption steps:
# Collect encrypted private key and passphrase from user.
# Derive ''derivedhalf1'' and ''derivedhalf2'' by passing the passphrase and ''addresshash'' into scrypt function.
# Decrypt ''encryptedhalf1'' and ''encryptedhalf2'' using AES256Decrypt, merge them to form the encrypted private key.
# Convert that private key into a Bitcoin address, honoring the compression preference specified in ''flagbyte'' of the encrypted key record.
# Hash the Bitcoin address, and verify that ''addresshash'' from the encrypted private key record matches the hash. If not, report that the passphrase entry was incorrect.
====Encryption when EC multiply mode is used====
Encrypting a private key with EC multiplication offers the ability for someone to generate encrypted keys knowing only an EC point derived from the original passphrase and some salt generated by the passphrase's owner, and without knowing the passphrase itself. Only the person who knows the original passphrase can decrypt the private key. A code known as an ''intermediate code'' conveys the information needed to generate such a key without knowledge of the passphrase.
This methodology does not offer the ability to encrypt a known private key - this means that the process of creating encrypted keys is also the process of generating new addresses. On the other hand, this serves a security benefit for someone possessing an address generated this way: if the address can be recreated by decrypting its private key with a passphrase, and it's a strong passphrase one can be certain only he knows himself, then he can safely conclude that nobody could know the private key to that address.
The person who knows the passphrase and who is the intended beneficiary of the private keys is called the ''owner''. He will generate one or more "intermediate codes", which are the first factor of a two-factor redemption system, and will give them to someone else we'll call ''printer'', who generates a key pair with an intermediate code can know the address and encrypted private key, but cannot decrypt the private key without the original passphrase.
An intermediate code should, but is not required to, embed a printable "lot" and "sequence" number for the benefit of the user. The proposal forces these lot and sequence numbers to be included in any valid private keys generated from them. An owner who has requested multiple private keys to be generated for him will be advised by applications to ensure that each private key has a unique lot and sequence number consistent with the intermediate codes he generated. These mainly help protect ''owner'' from potential mistakes and/or attacks that could be made by ''printer''.
The "lot" and "sequence" number are combined into a single 32 bit number. 20 bits are used for the lot number and 12 bits are used for the sequence number, such that the lot number can be any decimal number between 0 and 1048575, and the sequence number can be any decimal number between 0 and 4095. For programs that generate batches of intermediate codes for an ''owner'', it is recommended that lot numbers be chosen at random within the range 100000-999999 and that sequence numbers are assigned starting with 1.
Steps performed by ''owner'' to generate a single intermediate code, if lot and sequence numbers are being included:
# Generate 4 random bytes, call them ''ownersalt''.
# Encode the lot and sequence numbers as a 4 byte quantity (big-endian): lotnumber * 4096 + sequencenumber. Call these four bytes ''lotsequence''.
# Concatenate ''ownersalt'' + ''lotsequence'' and call this ''ownerentropy''.
# Derive a key from the passphrase using scrypt
#* Parameters: ''passphrase'' is the passphrase itself encoded in UTF-8 and normalized using Unicode Normalization Form C (NFC). salt is ''ownersalt''. n=16384, r=8, p=8, length=32.
#* Call the resulting 32 bytes ''prefactor''.
#* Take SHA256(SHA256(''prefactor'' + ''ownerentropy'')) and call this ''passfactor''. The "+" operator is concatenation.
# Compute the elliptic curve point G * ''passfactor'', and convert the result to compressed notation (33 bytes). Call this ''passpoint''. Compressed notation is used for this purpose regardless of whether the intent is to create Bitcoin addresses with or without compressed public keys.
# Convey ''ownersalt'' and ''passpoint'' to the party generating the keys, along with a checksum to ensure integrity.
#* The following Base58Check-encoded format is recommended for this purpose: magic bytes "2C E9 B3 E1 FF 39 E2 51" followed by ''ownerentropy'', and then ''passpoint''. The resulting string will start with the word "passphrase" due to the constant bytes, will be 72 characters in length, and encodes 49 bytes (8 bytes constant + 8 bytes ''ownerentropy'' + 33 bytes ''passpoint''). The checksum is handled in the Base58Check encoding. The resulting string is called ''intermediate_passphrase_string''.
If lot and sequence numbers are not being included, then follow the same procedure with the following changes:
* ''ownersalt'' is 8 random bytes instead of 4, and ''lotsequence'' is omitted. ''ownerentropy'' becomes an alias for ''ownersalt''.
* The SHA256 conversion of ''prefactor'' to ''passfactor'' is omitted. Instead, the output of scrypt is used directly as ''passfactor''.
* The magic bytes are "2C E9 B3 E1 FF 39 E2 53" instead (the last byte is 0x53 instead of 0x51).
Steps to create new encrypted private keys given ''intermediate_passphrase_string'' from ''owner'' (so we have ''ownerentropy'', and ''passpoint'', but we do not have ''passfactor'' or the passphrase):
# Set ''flagbyte''.
#* Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key (optional, saves space, but many Bitcoin implementations aren't compatible with it)
#* Turn on bit 0x04 if ''ownerentropy'' contains a value for ''lotsequence''. (While it has no effect on the keypair generation process, the decryption process needs this flag to know how to process ''ownerentropy'')
# Generate 24 random bytes, call this ''seedb''. Take SHA256(SHA256(''seedb'')) to yield 32 bytes, call this ''factorb''.
# ECMultiply ''passpoint'' by ''factorb''. Use the resulting EC point as a public key and hash it into a Bitcoin address using either compressed or uncompressed public key methodology (specify which methodology is used inside ''flagbyte''). This is the generated Bitcoin address, call it ''generatedaddress''.
# Take the first four bytes of SHA256(SHA256(''generatedaddress'')) and call it ''addresshash''.
# Now we will encrypt ''seedb''. Derive a second key from ''passpoint'' using scrypt
#*Parameters: ''passphrase'' is ''passpoint'' provided from the first party (expressed in binary as 33 bytes). ''salt'' is ''addresshash'' + ''ownerentropy'', n=1024, r=1, p=1, length=64. The "+" operator is concatenation.
#*Split the result into two 32-byte halves and call them ''derivedhalf1'' and ''derivedhalf2''.
# Do AES256Encrypt(block = (seedb[0...15] xor derivedhalf1[0...15]), key = derivedhalf2), call the 16-byte result ''encryptedpart1''
# Do AES256Encrypt(block = ((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31]), key = derivedhalf2), call the 16-byte result ''encryptedpart2''. The "+" operator is concatenation.
The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum:
* 0x01 0x43 + ''flagbyte'' + ''addresshash'' + ''ownerentropy'' + ''encryptedpart1''[0...7] + ''encryptedpart2''
=====Confirmation code=====
The party generating the Bitcoin address has the option to return a ''confirmation code'' back to ''owner'' which allows ''owner'' to independently verify that he has been given a Bitcoin address that actually depends on his passphrase, and to confirm the lot and sequence numbers (if applicable). This protects ''owner'' from being given a Bitcoin address by the second party that is unrelated to the key derivation and possibly spendable by the second party. If a Bitcoin address given to ''owner'' can be successfully regenerated through the confirmation process, ''owner'' can be reasonably assured that any spending without the passphrase is infeasible. This confirmation code is 75 characters starting with "cfrm38".
To generate it, we need ''flagbyte'', ''ownerentropy'', ''factorb'', ''derivedhalf1'' and ''derivedhalf2'' from the original encryption operation.
# ECMultiply ''factorb'' by G, call the result ''pointb''. The result is 33 bytes.
# The first byte is 0x02 or 0x03. XOR it by (derivedhalf2[31] & 0x01), call the resulting byte ''pointbprefix''.
# Do AES256Encrypt(block = (pointb[1...16] xor derivedhalf1[0...15]), key = derivedhalf2) and call the result ''pointbx1''.
# Do AES256Encrypt(block = (pointb[17...32] xor derivedhalf1[16...31]), key = derivedhalf2) and call the result ''pointbx2''.
# Concatenate ''pointbprefix'' + ''pointbx1'' + ''pointbx2'' (total 33 bytes) and call the result ''encryptedpointb''.
The result is a Base58Check-encoded concatenation of the following:
* 0x64 0x3B 0xF6 0xA8 0x9A + ''flagbyte'' + ''addresshash'' + ''ownerentropy'' + ''encryptedpointb''
A confirmation tool, given a passphrase and a confirmation code, can recalculate the address, verify the address hash, and then assert the following: "It is confirmed that Bitcoin address ''address'' depends on this passphrase". If applicable: "The lot number is ''lotnumber'' and the sequence number is ''sequencenumber''."
To recalculate the address:
# Derive ''passfactor'' using scrypt with ''ownerentropy'' and the user's passphrase and use it to recompute ''passpoint''
# Derive decryption key for ''pointb'' using scrypt with ''passpoint'', ''addresshash'', and ''ownerentropy''
# Decrypt ''encryptedpointb'' to yield ''pointb''
# ECMultiply ''pointb'' by ''passfactor''. Use the resulting EC point as a public key and hash it into ''address'' using either compressed or uncompressed public key methodology as specified in ''flagbyte''.
=====Decryption=====
# Collect encrypted private key and passphrase from user.
# Derive ''passfactor'' using scrypt with ''ownersalt'' and the user's passphrase and use it to recompute ''passpoint''
# Derive decryption key for ''seedb'' using scrypt with ''passpoint'', ''addresshash'', and ''ownerentropy''
# Decrypt ''encryptedpart2'' using AES256Decrypt to yield the last 8 bytes of ''seedb'' and the last 8 bytes of ''encryptedpart1''.
# Decrypt ''encryptedpart1'' to yield the remainder of ''seedb''.
# Use ''seedb'' to compute ''factorb''.
# Multiply ''passfactor'' by ''factorb'' mod N to yield the private key associated with ''generatedaddress''.
# Convert that private key into a Bitcoin address, honoring the compression preference specified in the encrypted key.
# Hash the Bitcoin address, and verify that ''addresshash'' from the encrypted private key record matches the hash. If not, report that the passphrase entry was incorrect.
==Backwards compatibility==
Backwards compatibility is minimally applicable since this is a new standard that at most extends Wallet Import Format. It is assumed that an entry point for private key data may also accept existing formats of private keys (such as hexadecimal and Wallet Import Format); this draft uses a key format that cannot be mistaken for any existing one and preserves auto-detection capabilities.
==Suggestions for implementers of proposal with alt-chains==
If this proposal is accepted into alt-chains, it is requested that the unused flag bytes not be used for denoting that the key belongs to an alt-chain.
Alt-chain implementers should exploit the address hash for this purpose. Since each operation in this proposal involves hashing a text representation of a coin address which (for Bitcoin) includes the leading '1', an alt-chain can easily be denoted simply by using the alt-chain's preferred format for representing an address. Alt-chain implementers may also change the prefix such that encrypted addresses do not start with "6P".
==Discussion item: scrypt parameters==
This proposal leaves the scrypt parameters up in the air. The following items are proposed for consideration:
The main goal of scrypt is to reduce the feasibility of brute force attacks. It must be assumed that an attacker will be able to use an efficient implementation of scrypt. The parameters should force a highly efficient implementation of scrypt to wait a decent amount of time to slow attacks.
On the other hand, an unavoidably likely place where scrypt will be implemented is using slow interpreted languages such as javascript. What might take milliseconds on an efficient scrypt implementation may take seconds in javascript.
It is believed, however, that someone using a javascript implementation is probably dealing with codes by hand, one at a time, rather than generating or processing large batches of codes. Thus, a wait time of several seconds is acceptable to a user.
A private key redemption process that forces a server to consume several seconds of CPU time would discourage implementation by the server owner, because they would be opening up a denial of service avenue by inviting users to make numerous attempts to invoke the redemption process. However, it's also feasible for the server owner to implement his redemption process in such a way that the decryption is done by the user's browser, offloading the task from his own server (and providing another reason why the chosen scrypt parameters should be tolerant of javascript-based decryptors).
The preliminary values of 16384, 8, and 8 are hoped to offer the following properties:
* Encryption/decryption in javascript requiring several seconds per operation
* Use of the parallelization parameter provides a modest opportunity for speedups in environments where concurrent threading is available - such environments would be selected for processes that must handle bulk quantities of encryption/decryption operations. Estimated time for an operation is in the tens or hundreds of milliseconds.
==Reference implementation==
Added to alpha version of Casascius Bitcoin Address Utility for Windows available at:
* https://github.com/casascius/Bitcoin-Address-Utility
Click "Tools" then "PPEC Keygen" (provisional name)
==Test vectors==
===No compression, no EC multiply===
Test 1:
*Passphrase: TestingOneTwoThree
*Encrypted: 6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg
*Unencrypted (WIF): 5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR
*Unencrypted (hex): CBF4B9F70470856BB4F40F80B87EDB90865997FFEE6DF315AB166D713AF433A5
Test 2:
*Passphrase: Satoshi
*Encrypted: 6PRNFFkZc2NZ6dJqFfhRoFNMR9Lnyj7dYGrzdgXXVMXcxoKTePPX1dWByq
*Unencrypted (WIF): 5HtasZ6ofTHP6HCwTqTkLDuLQisYPah7aUnSKfC7h4hMUVw2gi5
*Unencrypted (hex): 09C2686880095B1A4C249EE3AC4EEA8A014F11E6F986D0B5025AC1F39AFBD9AE
Test 3:
*Passphrase ϓ␀𐐀💩 (\u03D2\u0301\u0000\U00010400\U0001F4A9; [http://codepoints.net/U+03D2 GREEK UPSILON WITH HOOK], [http://codepoints.net/U+0301 COMBINING ACUTE ACCENT], [http://codepoints.net/U+0000 NULL], [http://codepoints.net/U+10400 DESERET CAPITAL LETTER LONG I], [http://codepoints.net/U+1F4A9 PILE OF POO])
*Encrypted key: 6PRW5o9FLp4gJDDVqJQKJFTpMvdsSGJxMYHtHaQBF3ooa8mwD69bapcDQn
*Bitcoin Address: 16ktGzmfrurhbhi6JGqsMWf7TyqK9HNAeF
*Unencrypted private key (WIF): 5Jajm8eQ22H3pGWLEVCXyvND8dQZhiQhoLJNKjYXk9roUFTMSZ4
* ''Note:'' The non-standard UTF-8 characters in this passphrase should be NFC normalized to result in a passphrase of 0xcf9300f0909080f09f92a9 before further processing
===Compression, no EC multiply===
Test 1:
*Passphrase: TestingOneTwoThree
*Encrypted: 6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo
*Unencrypted (WIF): L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP
*Unencrypted (hex): CBF4B9F70470856BB4F40F80B87EDB90865997FFEE6DF315AB166D713AF433A5
Test 2:
*Passphrase: Satoshi
*Encrypted: 6PYLtMnXvfG3oJde97zRyLYFZCYizPU5T3LwgdYJz1fRhh16bU7u6PPmY7
*Unencrypted (WIF): KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7
*Unencrypted (hex): 09C2686880095B1A4C249EE3AC4EEA8A014F11E6F986D0B5025AC1F39AFBD9AE
===EC multiply, no compression, no lot/sequence numbers===
Test 1:
*Passphrase: TestingOneTwoThree
*Passphrase code: passphrasepxFy57B9v8HtUsszJYKReoNDV6VHjUSGt8EVJmux9n1J3Ltf1gRxyDGXqnf9qm
*Encrypted key: 6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX
*Bitcoin address: 1PE6TQi6HTVNz5DLwB1LcpMBALubfuN2z2
*Unencrypted private key (WIF): 5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2
*Unencrypted private key (hex): A43A940577F4E97F5C4D39EB14FF083A98187C64EA7C99EF7CE460833959A519
Test 2:
*Passphrase: Satoshi
*Passphrase code: passphraseoRDGAXTWzbp72eVbtUDdn1rwpgPUGjNZEc6CGBo8i5EC1FPW8wcnLdq4ThKzAS
*Encrypted key: 6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd
*Bitcoin address: 1CqzrtZC6mXSAhoxtFwVjz8LtwLJjDYU3V
*Unencrypted private key (WIF): 5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH
*Unencrypted private key (hex): C2C8036DF268F498099350718C4A3EF3984D2BE84618C2650F5171DCC5EB660A
===EC multiply, no compression, lot/sequence numbers===
Test 1:
*Passphrase: MOLON LABE
*Passphrase code: passphraseaB8feaLQDENqCgr4gKZpmf4VoaT6qdjJNJiv7fsKvjqavcJxvuR1hy25aTu5sX
*Encrypted key: 6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j
*Bitcoin address: 1Jscj8ALrYu2y9TD8NrpvDBugPedmbj4Yh
*Unencrypted private key (WIF): 5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8
*Unencrypted private key (hex): 44EA95AFBF138356A05EA32110DFD627232D0F2991AD221187BE356F19FA8190
*Confirmation code: cfrm38V8aXBn7JWA1ESmFMUn6erxeBGZGAxJPY4e36S9QWkzZKtaVqLNMgnifETYw7BPwWC9aPD
*Lot/Sequence: 263183/1
Test 2:
*Passphrase (all letters are Greek - test UTF-8 compatibility with this): ΜΟΛΩΝ ΛΑΒΕ
*Passphrase code: passphrased3z9rQJHSyBkNBwTRPkUGNVEVrUAcfAXDyRU1V28ie6hNFbqDwbFBvsTK7yWVK
*Encrypted private key: 6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH
*Bitcoin address: 1Lurmih3KruL4xDB5FmHof38yawNtP9oGf
*Unencrypted private key (WIF): 5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D
*Unencrypted private key (hex): CA2759AA4ADB0F96C414F36ABEB8DB59342985BE9FA50FAAC228C8E7D90E3006
*Confirmation code: cfrm38V8G4qq2ywYEFfWLD5Cc6msj9UwsG2Mj4Z6QdGJAFQpdatZLavkgRd1i4iBMdRngDqDs51
*Lot/Sequence: 806938/1
================================================
FILE: bip-0039/bip-0039-wordlists.md
================================================
# Wordlists
* [English](english.txt)
* [Japanese](japanese.txt)
* [Korean](korean.txt)
* [Spanish](spanish.txt)
* [Chinese (Simplified)](chinese_simplified.txt)
* [Chinese (Traditional)](chinese_traditional.txt)
* [French](french.txt)
* [Italian](italian.txt)
* [Czech](czech.txt)
* [Portuguese](portuguese.txt)
## Wordlists (Special Considerations)
### Japanese
1. **Developers implementing phrase generation or checksum verification must separate words using ideographic spaces / accommodate users inputting ideographic spaces.**
(UTF-8 bytes: **0xE38080**; C/C+/Java: **"\u3000"**; Python: **u"\u3000"**)
However, code that only accepts Japanese phrases but does not generate or verify them should be fine as is.
This is because when generating the seed, normalization as per the spec will
automatically change the ideographic spaces into normal ASCII spaces, so as long as your code never shows the user an ASCII space
separated phrase or tries to split the phrase input by the user, dealing with ASCII or Ideographic space is the same.
2. Word-wrapping doesn't work well, so making sure that words only word-wrap at one of the
ideographic spaces may be a necessary step. As a long word split in two could be mistaken easily
for two smaller words (This would be a problem with any of the 3 character sets in Japanese)
### Spanish
1. Words can be uniquely determined by typing the first 4 characters (sometimes less).
2. Special Spanish characters like 'ñ', 'ü', 'á', etc... are considered equal to 'n', 'u', 'a', etc... in terms of identifying a word. Therefore, there is no need to use a Spanish keyboard to introduce the passphrase, an application with the Spanish wordlist will be able to identify the words after the first 4 chars have been typed even if the chars with accents have been replaced with the equivalent without accents.
3. There are no words in common between the Spanish wordlist and any other language wordlist, therefore it is possible to detect the language with just one word.
### Chinese
1. Chinese text typically does not use any spaces as word separators. For the sake of
uniformity, we propose to use normal ASCII spaces (0x20) to separate words as per standard.
### French
Credits: @Kirvx @NicolasDorier @ecdsa @EricLarch
([The pull request](https://github.com/bitcoin/bips/issues/152))
1. High priority on simple and common French words.
2. Only words with 5-8 letters.
3. A word is fully recognizable by typing the first 4 letters (special French characters "é-è" are considered equal to "e", for example "museau" and "musée" can not be together).
4. Only infinitive verbs, adjectives and nouns.
5. No pronouns, no adverbs, no prepositions, no conjunctions, no interjections (unless a noun/adjective is also popular than its interjection like "mince;chouette").
6. No numeral adjectives.
7. No words in the plural (except invariable words like "univers", or same spelling as singular like "heureux").
8. No female adjectives (except words with same spelling for male and female adjectives like "magique").
9. No words with several senses AND different spelling in speaking like "verre-vert", unless a word has a meaning much more popular than another like "perle" and "pairle".
10. No very similar words with only 1 letter of difference.
11. No essentially reflexive verbs (unless a verb is also a noun like "souvenir").
12. No words with "ô;â;ç;ê;œ;æ;î;ï;û;ù;à;ë;ÿ".
13. No words ending by "é;ée;è;et;ai;ait".
14. No demonyms.
15. No words in conflict with the spelling corrections of 1990 (http://goo.gl/Y8DU4z).
16. No embarrassing words (in a very, very large scope) or belonging to a particular religion.
17. No identical words with the Spanish wordlist (as Y75QMO wants).
### Italian
Credits: @paoloaga @Polve
Words chosen using the following rules:
1. Simple and common Italian words.
2. Length between 4 and 8 characters.
3. First 4 letters must be unique between all words.
4. No accents or special characters.
5. No complex verb forms.
6. No plural words.
7. No words that remind negative/sad/bad things.
8. If both female/male words are available, choose male version.
9. No words with double vowels (like: lineetta).
10. No words already used in other language mnemonic sets.
11. If 3 of the first 4 letters are already used in the same sequence in another mnemonic word, there must be at least other 3 different letters.
12. If 3 of the first 4 letters are already used in the same sequence in another mnemonic word, there must not be the same sequence of 3 or more letters.
Rules 11 and 12 prevent the selection words that are not different enough. This makes each word more recognizable among others and less error prone. For example: the wordlist contains "atono", then "atomo" is rejected, but "atomico" is good.
All the words have been manually selected and automatically checked against the rules.
### Czech
Credits: @zizelevak (Jan Lansky zizelevak@gmail.com)
Words chosen using the following rules:
1. Words are 4-8 letters long.
2. Words can be uniquely determined by typing the first 4 letters.
3. Only words containing all letters without diacritical marks. (It was the hardest task, because one third of all Czech letters has diacritical marks.)
4. Only nouns, verbs and adverbs, no other word types. All words are in basic form.
5. No personal names or geographical names.
6. No very similar words with 1 letter of difference.
7. Words are sorted according to English alphabet (Czech sorting has difference in "ch").
8. No words already used in other language mnemonic sets (english, italian, french, spanish). Letters with diacritical marks from these sets are counted as analogous letters without diacritical marks.
### Portuguese
Credits: @alegotardo @bitmover-studio @brenorb @kuthullu @ninjastic @sabotag3x @Trimegistus
1. Words can be uniquely determined by typing the first 4 characters.
2. No accents or special characters.
3. No complex verb forms.
4. No plural words, unless there's no singular form.
5. No words with double spelling.
6. No words with the exact sound as another word with different spelling.
7. No offensive words.
8. No words already used in other language mnemonic sets.
9. The words which have not the same spelling in Brazil and in Portugal are excluded.
10. No words that remind one of negative/sad/bad things.
11. No very similar words with only 1 letter of difference.
================================================
FILE: bip-0039/chinese_simplified.txt
================================================
的
一
是
在
不
了
有
和
人
这
中
大
为
上
个
国
我
以
要
他
时
来
用
们
生
到
作
地
于
出
就
分
对
成
会
可
主
发
年
动
同
工
也
能
下
过
子
说
产
种
面
而
方
后
多
定
行
学
法
所
民
得
经
十
三
之
进
着
等
部
度
家
电
力
里
如
水
化
高
自
二
理
起
小
物
现
实
加
量
都
两
体
制
机
当
使
点
从
业
本
去
把
性
好
应
开
它
合
还
因
由
其
些
然
前
外
天
政
四
日
那
社
义
事
平
形
相
全
表
间
样
与
关
各
重
新
线
内
数
正
心
反
你
明
看
原
又
么
利
比
或
但
质
气
第
向
道
命
此
变
条
只
没
结
解
问
意
建
月
公
无
系
军
很
情
者
最
立
代
想
已
通
并
提
直
题
党
程
展
五
果
料
象
员
革
位
入
常
文
总
次
品
式
活
设
及
管
特
件
长
求
老
头
基
资
边
流
路
级
少
图
山
统
接
知
较
将
组
见
计
别
她
手
角
期
根
论
运
农
指
几
九
区
强
放
决
西
被
干
做
必
战
先
回
则
任
取
据
处
队
南
给
色
光
门
即
保
治
北
造
百
规
热
领
七
海
口
东
导
器
压
志
世
金
增
争
济
阶
油
思
术
极
交
受
联
什
认
六
共
权
收
证
改
清
美
再
采
转
更
单
风
切
打
白
教
速
花
带
安
场
身
车
例
真
务
具
万
每
目
至
达
走
积
示
议
声
报
斗
完
类
八
离
华
名
确
才
科
张
信
马
节
话
米
整
空
元
况
今
集
温
传
土
许
步
群
广
石
记
需
段
研
界
拉
林
律
叫
且
究
观
越
织
装
影
算
低
持
音
众
书
布
复
容
儿
须
际
商
非
验
连
断
深
难
近
矿
千
周
委
素
技
备
半
办
青
省
列
习
响
约
支
般
史
感
劳
便
团
往
酸
历
市
克
何
除
消
构
府
称
太
准
精
值
号
率
族
维
划
选
标
写
存
候
毛
亲
快
效
斯
院
查
江
型
眼
王
按
格
养
易
置
派
层
片
始
却
专
状
育
厂
京
识
适
属
圆
包
火
住
调
满
县
局
照
参
红
细
引
听
该
铁
价
严
首
底
液
官
德
随
病
苏
失
尔
死
讲
配
女
黄
推
显
谈
罪
神
艺
呢
席
含
企
望
密
批
营
项
防
举
球
英
氧
势
告
李
台
落
木
帮
轮
破
亚
师
围
注
远
字
材
排
供
河
态
封
另
施
减
树
溶
怎
止
案
言
士
均
武
固
叶
鱼
波
视
仅
费
紧
爱
左
章
早
朝
害
续
轻
服
试
食
充
兵
源
判
护
司
足
某
练
差
致
板
田
降
黑
犯
负
击
范
继
兴
似
余
坚
曲
输
修
故
城
夫
够
送
笔
船
占
右
财
吃
富
春
职
觉
汉
画
功
巴
跟
虽
杂
飞
检
吸
助
升
阳
互
初
创
抗
考
投
坏
策
古
径
换
未
跑
留
钢
曾
端
责
站
简
述
钱
副
尽
帝
射
草
冲
承
独
令
限
阿
宣
环
双
请
超
微
让
控
州
良
轴
找
否
纪
益
依
优
顶
础
载
倒
房
突
坐
粉
敌
略
客
袁
冷
胜
绝
析
块
剂
测
丝
协
诉
念
陈
仍
罗
盐
友
洋
错
苦
夜
刑
移
频
逐
靠
混
母
短
皮
终
聚
汽
村
云
哪
既
距
卫
停
烈
央
察
烧
迅
境
若
印
洲
刻
括
激
孔
搞
甚
室
待
核
校
散
侵
吧
甲
游
久
菜
味
旧
模
湖
货
损
预
阻
毫
普
稳
乙
妈
植
息
扩
银
语
挥
酒
守
拿
序
纸
医
缺
雨
吗
针
刘
啊
急
唱
误
训
愿
审
附
获
茶
鲜
粮
斤
孩
脱
硫
肥
善
龙
演
父
渐
血
欢
械
掌
歌
沙
刚
攻
谓
盾
讨
晚
粒
乱
燃
矛
乎
杀
药
宁
鲁
贵
钟
煤
读
班
伯
香
介
迫
句
丰
培
握
兰
担
弦
蛋
沉
假
穿
执
答
乐
谁
顺
烟
缩
征
脸
喜
松
脚
困
异
免
背
星
福
买
染
井
概
慢
怕
磁
倍
祖
皇
促
静
补
评
翻
肉
践
尼
衣
宽
扬
棉
希
伤
操
垂
秋
宜
氢
套
督
振
架
亮
末
宪
庆
编
牛
触
映
雷
销
诗
座
居
抓
裂
胞
呼
娘
景
威
绿
晶
厚
盟
衡
鸡
孙
延
危
胶
屋
乡
临
陆
顾
掉
呀
灯
岁
措
束
耐
剧
玉
赵
跳
哥
季
课
凯
胡
额
款
绍
卷
齐
伟
蒸
殖
永
宗
苗
川
炉
岩
弱
零
杨
奏
沿
露
杆
探
滑
镇
饭
浓
航
怀
赶
库
夺
伊
灵
税
途
灭
赛
归
召
鼓
播
盘
裁
险
康
唯
录
菌
纯
借
糖
盖
横
符
私
努
堂
域
枪
润
幅
哈
竟
熟
虫
泽
脑
壤
碳
欧
遍
侧
寨
敢
彻
虑
斜
薄
庭
纳
弹
饲
伸
折
麦
湿
暗
荷
瓦
塞
床
筑
恶
户
访
塔
奇
透
梁
刀
旋
迹
卡
氯
遇
份
毒
泥
退
洗
摆
灰
彩
卖
耗
夏
择
忙
铜
献
硬
予
繁
圈
雪
函
亦
抽
篇
阵
阴
丁
尺
追
堆
雄
迎
泛
爸
楼
避
谋
吨
野
猪
旗
累
偏
典
馆
索
秦
脂
潮
爷
豆
忽
托
惊
塑
遗
愈
朱
替
纤
粗
倾
尚
痛
楚
谢
奋
购
磨
君
池
旁
碎
骨
监
捕
弟
暴
割
贯
殊
释
词
亡
壁
顿
宝
午
尘
闻
揭
炮
残
冬
桥
妇
警
综
招
吴
付
浮
遭
徐
您
摇
谷
赞
箱
隔
订
男
吹
园
纷
唐
败
宋
玻
巨
耕
坦
荣
闭
湾
键
凡
驻
锅
救
恩
剥
凝
碱
齿
截
炼
麻
纺
禁
废
盛
版
缓
净
睛
昌
婚
涉
筒
嘴
插
岸
朗
庄
街
藏
姑
贸
腐
奴
啦
惯
乘
伙
恢
匀
纱
扎
辩
耳
彪
臣
亿
璃
抵
脉
秀
萨
俄
网
舞
店
喷
纵
寸
汗
挂
洪
贺
闪
柬
爆
烯
津
稻
墙
软
勇
像
滚
厘
蒙
芳
肯
坡
柱
荡
腿
仪
旅
尾
轧
冰
贡
登
黎
削
钻
勒
逃
障
氨
郭
峰
币
港
伏
轨
亩
毕
擦
莫
刺
浪
秘
援
株
健
售
股
岛
甘
泡
睡
童
铸
汤
阀
休
汇
舍
牧
绕
炸
哲
磷
绩
朋
淡
尖
启
陷
柴
呈
徒
颜
泪
稍
忘
泵
蓝
拖
洞
授
镜
辛
壮
锋
贫
虚
弯
摩
泰
幼
廷
尊
窗
纲
弄
隶
疑
氏
宫
姐
震
瑞
怪
尤
琴
循
描
膜
违
夹
腰
缘
珠
穷
森
枝
竹
沟
催
绳
忆
邦
剩
幸
浆
栏
拥
牙
贮
礼
滤
钠
纹
罢
拍
咱
喊
袖
埃
勤
罚
焦
潜
伍
墨
欲
缝
姓
刊
饱
仿
奖
铝
鬼
丽
跨
默
挖
链
扫
喝
袋
炭
污
幕
诸
弧
励
梅
奶
洁
灾
舟
鉴
苯
讼
抱
毁
懂
寒
智
埔
寄
届
跃
渡
挑
丹
艰
贝
碰
拔
爹
戴
码
梦
芽
熔
赤
渔
哭
敬
颗
奔
铅
仲
虎
稀
妹
乏
珍
申
桌
遵
允
隆
螺
仓
魏
锐
晓
氮
兼
隐
碍
赫
拨
忠
肃
缸
牵
抢
博
巧
壳
兄
杜
讯
诚
碧
祥
柯
页
巡
矩
悲
灌
龄
伦
票
寻
桂
铺
圣
恐
恰
郑
趣
抬
荒
腾
贴
柔
滴
猛
阔
辆
妻
填
撤
储
签
闹
扰
紫
砂
递
戏
吊
陶
伐
喂
疗
瓶
婆
抚
臂
摸
忍
虾
蜡
邻
胸
巩
挤
偶
弃
槽
劲
乳
邓
吉
仁
烂
砖
租
乌
舰
伴
瓜
浅
丙
暂
燥
橡
柳
迷
暖
牌
秧
胆
详
簧
踏
瓷
谱
呆
宾
糊
洛
辉
愤
竞
隙
怒
粘
乃
绪
肩
籍
敏
涂
熙
皆
侦
悬
掘
享
纠
醒
狂
锁
淀
恨
牲
霸
爬
赏
逆
玩
陵
祝
秒
浙
貌
役
彼
悉
鸭
趋
凤
晨
畜
辈
秩
卵
署
梯
炎
滩
棋
驱
筛
峡
冒
啥
寿
译
浸
泉
帽
迟
硅
疆
贷
漏
稿
冠
嫩
胁
芯
牢
叛
蚀
奥
鸣
岭
羊
凭
串
塘
绘
酵
融
盆
锡
庙
筹
冻
辅
摄
袭
筋
拒
僚
旱
钾
鸟
漆
沈
眉
疏
添
棒
穗
硝
韩
逼
扭
侨
凉
挺
碗
栽
炒
杯
患
馏
劝
豪
辽
勃
鸿
旦
吏
拜
狗
埋
辊
掩
饮
搬
骂
辞
勾
扣
估
蒋
绒
雾
丈
朵
姆
拟
宇
辑
陕
雕
偿
蓄
崇
剪
倡
厅
咬
驶
薯
刷
斥
番
赋
奉
佛
浇
漫
曼
扇
钙
桃
扶
仔
返
俗
亏
腔
鞋
棱
覆
框
悄
叔
撞
骗
勘
旺
沸
孤
吐
孟
渠
屈
疾
妙
惜
仰
狠
胀
谐
抛
霉
桑
岗
嘛
衰
盗
渗
脏
赖
涌
甜
曹
阅
肌
哩
厉
烃
纬
毅
昨
伪
症
煮
叹
钉
搭
茎
笼
酷
偷
弓
锥
恒
杰
坑
鼻
翼
纶
叙
狱
逮
罐
络
棚
抑
膨
蔬
寺
骤
穆
冶
枯
册
尸
凸
绅
坯
牺
焰
轰
欣
晋
瘦
御
锭
锦
丧
旬
锻
垄
搜
扑
邀
亭
酯
迈
舒
脆
酶
闲
忧
酚
顽
羽
涨
卸
仗
陪
辟
惩
杭
姚
肚
捉
飘
漂
昆
欺
吾
郎
烷
汁
呵
饰
萧
雅
邮
迁
燕
撒
姻
赴
宴
烦
债
帐
斑
铃
旨
醇
董
饼
雏
姿
拌
傅
腹
妥
揉
贤
拆
歪
葡
胺
丢
浩
徽
昂
垫
挡
览
贪
慰
缴
汪
慌
冯
诺
姜
谊
凶
劣
诬
耀
昏
躺
盈
骑
乔
溪
丛
卢
抹
闷
咨
刮
驾
缆
悟
摘
铒
掷
颇
幻
柄
惠
惨
佳
仇
腊
窝
涤
剑
瞧
堡
泼
葱
罩
霍
捞
胎
苍
滨
俩
捅
湘
砍
霞
邵
萄
疯
淮
遂
熊
粪
烘
宿
档
戈
驳
嫂
裕
徙
箭
捐
肠
撑
晒
辨
殿
莲
摊
搅
酱
屏
疫
哀
蔡
堵
沫
皱
畅
叠
阁
莱
敲
辖
钩
痕
坝
巷
饿
祸
丘
玄
溜
曰
逻
彭
尝
卿
妨
艇
吞
韦
怨
矮
歇
================================================
FILE: bip-0039/chinese_traditional.txt
================================================
的
一
是
在
不
了
有
和
人
這
中
大
為
上
個
國
我
以
要
他
時
來
用
們
生
到
作
地
於
出
就
分
對
成
會
可
主
發
年
動
同
工
也
能
下
過
子
說
產
種
面
而
方
後
多
定
行
學
法
所
民
得
經
十
三
之
進
著
等
部
度
家
電
力
裡
如
水
化
高
自
二
理
起
小
物
現
實
加
量
都
兩
體
制
機
當
使
點
從
業
本
去
把
性
好
應
開
它
合
還
因
由
其
些
然
前
外
天
政
四
日
那
社
義
事
平
形
相
全
表
間
樣
與
關
各
重
新
線
內
數
正
心
反
你
明
看
原
又
麼
利
比
或
但
質
氣
第
向
道
命
此
變
條
只
沒
結
解
問
意
建
月
公
無
系
軍
很
情
者
最
立
代
想
已
通
並
提
直
題
黨
程
展
五
果
料
象
員
革
位
入
常
文
總
次
品
式
活
設
及
管
特
件
長
求
老
頭
基
資
邊
流
路
級
少
圖
山
統
接
知
較
將
組
見
計
別
她
手
角
期
根
論
運
農
指
幾
九
區
強
放
決
西
被
幹
做
必
戰
先
回
則
任
取
據
處
隊
南
給
色
光
門
即
保
治
北
造
百
規
熱
領
七
海
口
東
導
器
壓
志
世
金
增
爭
濟
階
油
思
術
極
交
受
聯
什
認
六
共
權
收
證
改
清
美
再
採
轉
更
單
風
切
打
白
教
速
花
帶
安
場
身
車
例
真
務
具
萬
每
目
至
達
走
積
示
議
聲
報
鬥
完
類
八
離
華
名
確
才
科
張
信
馬
節
話
米
整
空
元
況
今
集
溫
傳
土
許
步
群
廣
石
記
需
段
研
界
拉
林
律
叫
且
究
觀
越
織
裝
影
算
低
持
音
眾
書
布
复
容
兒
須
際
商
非
驗
連
斷
深
難
近
礦
千
週
委
素
技
備
半
辦
青
省
列
習
響
約
支
般
史
感
勞
便
團
往
酸
歷
市
克
何
除
消
構
府
稱
太
準
精
值
號
率
族
維
劃
選
標
寫
存
候
毛
親
快
效
斯
院
查
江
型
眼
王
按
格
養
易
置
派
層
片
始
卻
專
狀
育
廠
京
識
適
屬
圓
包
火
住
調
滿
縣
局
照
參
紅
細
引
聽
該
鐵
價
嚴
首
底
液
官
德
隨
病
蘇
失
爾
死
講
配
女
黃
推
顯
談
罪
神
藝
呢
席
含
企
望
密
批
營
項
防
舉
球
英
氧
勢
告
李
台
落
木
幫
輪
破
亞
師
圍
注
遠
字
材
排
供
河
態
封
另
施
減
樹
溶
怎
止
案
言
士
均
武
固
葉
魚
波
視
僅
費
緊
愛
左
章
早
朝
害
續
輕
服
試
食
充
兵
源
判
護
司
足
某
練
差
致
板
田
降
黑
犯
負
擊
范
繼
興
似
餘
堅
曲
輸
修
故
城
夫
夠
送
筆
船
佔
右
財
吃
富
春
職
覺
漢
畫
功
巴
跟
雖
雜
飛
檢
吸
助
昇
陽
互
初
創
抗
考
投
壞
策
古
徑
換
未
跑
留
鋼
曾
端
責
站
簡
述
錢
副
盡
帝
射
草
衝
承
獨
令
限
阿
宣
環
雙
請
超
微
讓
控
州
良
軸
找
否
紀
益
依
優
頂
礎
載
倒
房
突
坐
粉
敵
略
客
袁
冷
勝
絕
析
塊
劑
測
絲
協
訴
念
陳
仍
羅
鹽
友
洋
錯
苦
夜
刑
移
頻
逐
靠
混
母
短
皮
終
聚
汽
村
雲
哪
既
距
衛
停
烈
央
察
燒
迅
境
若
印
洲
刻
括
激
孔
搞
甚
室
待
核
校
散
侵
吧
甲
遊
久
菜
味
舊
模
湖
貨
損
預
阻
毫
普
穩
乙
媽
植
息
擴
銀
語
揮
酒
守
拿
序
紙
醫
缺
雨
嗎
針
劉
啊
急
唱
誤
訓
願
審
附
獲
茶
鮮
糧
斤
孩
脫
硫
肥
善
龍
演
父
漸
血
歡
械
掌
歌
沙
剛
攻
謂
盾
討
晚
粒
亂
燃
矛
乎
殺
藥
寧
魯
貴
鐘
煤
讀
班
伯
香
介
迫
句
豐
培
握
蘭
擔
弦
蛋
沉
假
穿
執
答
樂
誰
順
煙
縮
徵
臉
喜
松
腳
困
異
免
背
星
福
買
染
井
概
慢
怕
磁
倍
祖
皇
促
靜
補
評
翻
肉
踐
尼
衣
寬
揚
棉
希
傷
操
垂
秋
宜
氫
套
督
振
架
亮
末
憲
慶
編
牛
觸
映
雷
銷
詩
座
居
抓
裂
胞
呼
娘
景
威
綠
晶
厚
盟
衡
雞
孫
延
危
膠
屋
鄉
臨
陸
顧
掉
呀
燈
歲
措
束
耐
劇
玉
趙
跳
哥
季
課
凱
胡
額
款
紹
卷
齊
偉
蒸
殖
永
宗
苗
川
爐
岩
弱
零
楊
奏
沿
露
桿
探
滑
鎮
飯
濃
航
懷
趕
庫
奪
伊
靈
稅
途
滅
賽
歸
召
鼓
播
盤
裁
險
康
唯
錄
菌
純
借
糖
蓋
橫
符
私
努
堂
域
槍
潤
幅
哈
竟
熟
蟲
澤
腦
壤
碳
歐
遍
側
寨
敢
徹
慮
斜
薄
庭
納
彈
飼
伸
折
麥
濕
暗
荷
瓦
塞
床
築
惡
戶
訪
塔
奇
透
梁
刀
旋
跡
卡
氯
遇
份
毒
泥
退
洗
擺
灰
彩
賣
耗
夏
擇
忙
銅
獻
硬
予
繁
圈
雪
函
亦
抽
篇
陣
陰
丁
尺
追
堆
雄
迎
泛
爸
樓
避
謀
噸
野
豬
旗
累
偏
典
館
索
秦
脂
潮
爺
豆
忽
托
驚
塑
遺
愈
朱
替
纖
粗
傾
尚
痛
楚
謝
奮
購
磨
君
池
旁
碎
骨
監
捕
弟
暴
割
貫
殊
釋
詞
亡
壁
頓
寶
午
塵
聞
揭
炮
殘
冬
橋
婦
警
綜
招
吳
付
浮
遭
徐
您
搖
谷
贊
箱
隔
訂
男
吹
園
紛
唐
敗
宋
玻
巨
耕
坦
榮
閉
灣
鍵
凡
駐
鍋
救
恩
剝
凝
鹼
齒
截
煉
麻
紡
禁
廢
盛
版
緩
淨
睛
昌
婚
涉
筒
嘴
插
岸
朗
莊
街
藏
姑
貿
腐
奴
啦
慣
乘
夥
恢
勻
紗
扎
辯
耳
彪
臣
億
璃
抵
脈
秀
薩
俄
網
舞
店
噴
縱
寸
汗
掛
洪
賀
閃
柬
爆
烯
津
稻
牆
軟
勇
像
滾
厘
蒙
芳
肯
坡
柱
盪
腿
儀
旅
尾
軋
冰
貢
登
黎
削
鑽
勒
逃
障
氨
郭
峰
幣
港
伏
軌
畝
畢
擦
莫
刺
浪
秘
援
株
健
售
股
島
甘
泡
睡
童
鑄
湯
閥
休
匯
舍
牧
繞
炸
哲
磷
績
朋
淡
尖
啟
陷
柴
呈
徒
顏
淚
稍
忘
泵
藍
拖
洞
授
鏡
辛
壯
鋒
貧
虛
彎
摩
泰
幼
廷
尊
窗
綱
弄
隸
疑
氏
宮
姐
震
瑞
怪
尤
琴
循
描
膜
違
夾
腰
緣
珠
窮
森
枝
竹
溝
催
繩
憶
邦
剩
幸
漿
欄
擁
牙
貯
禮
濾
鈉
紋
罷
拍
咱
喊
袖
埃
勤
罰
焦
潛
伍
墨
欲
縫
姓
刊
飽
仿
獎
鋁
鬼
麗
跨
默
挖
鏈
掃
喝
袋
炭
污
幕
諸
弧
勵
梅
奶
潔
災
舟
鑑
苯
訟
抱
毀
懂
寒
智
埔
寄
屆
躍
渡
挑
丹
艱
貝
碰
拔
爹
戴
碼
夢
芽
熔
赤
漁
哭
敬
顆
奔
鉛
仲
虎
稀
妹
乏
珍
申
桌
遵
允
隆
螺
倉
魏
銳
曉
氮
兼
隱
礙
赫
撥
忠
肅
缸
牽
搶
博
巧
殼
兄
杜
訊
誠
碧
祥
柯
頁
巡
矩
悲
灌
齡
倫
票
尋
桂
鋪
聖
恐
恰
鄭
趣
抬
荒
騰
貼
柔
滴
猛
闊
輛
妻
填
撤
儲
簽
鬧
擾
紫
砂
遞
戲
吊
陶
伐
餵
療
瓶
婆
撫
臂
摸
忍
蝦
蠟
鄰
胸
鞏
擠
偶
棄
槽
勁
乳
鄧
吉
仁
爛
磚
租
烏
艦
伴
瓜
淺
丙
暫
燥
橡
柳
迷
暖
牌
秧
膽
詳
簧
踏
瓷
譜
呆
賓
糊
洛
輝
憤
競
隙
怒
粘
乃
緒
肩
籍
敏
塗
熙
皆
偵
懸
掘
享
糾
醒
狂
鎖
淀
恨
牲
霸
爬
賞
逆
玩
陵
祝
秒
浙
貌
役
彼
悉
鴨
趨
鳳
晨
畜
輩
秩
卵
署
梯
炎
灘
棋
驅
篩
峽
冒
啥
壽
譯
浸
泉
帽
遲
矽
疆
貸
漏
稿
冠
嫩
脅
芯
牢
叛
蝕
奧
鳴
嶺
羊
憑
串
塘
繪
酵
融
盆
錫
廟
籌
凍
輔
攝
襲
筋
拒
僚
旱
鉀
鳥
漆
沈
眉
疏
添
棒
穗
硝
韓
逼
扭
僑
涼
挺
碗
栽
炒
杯
患
餾
勸
豪
遼
勃
鴻
旦
吏
拜
狗
埋
輥
掩
飲
搬
罵
辭
勾
扣
估
蔣
絨
霧
丈
朵
姆
擬
宇
輯
陝
雕
償
蓄
崇
剪
倡
廳
咬
駛
薯
刷
斥
番
賦
奉
佛
澆
漫
曼
扇
鈣
桃
扶
仔
返
俗
虧
腔
鞋
棱
覆
框
悄
叔
撞
騙
勘
旺
沸
孤
吐
孟
渠
屈
疾
妙
惜
仰
狠
脹
諧
拋
黴
桑
崗
嘛
衰
盜
滲
臟
賴
湧
甜
曹
閱
肌
哩
厲
烴
緯
毅
昨
偽
症
煮
嘆
釘
搭
莖
籠
酷
偷
弓
錐
恆
傑
坑
鼻
翼
綸
敘
獄
逮
罐
絡
棚
抑
膨
蔬
寺
驟
穆
冶
枯
冊
屍
凸
紳
坯
犧
焰
轟
欣
晉
瘦
禦
錠
錦
喪
旬
鍛
壟
搜
撲
邀
亭
酯
邁
舒
脆
酶
閒
憂
酚
頑
羽
漲
卸
仗
陪
闢
懲
杭
姚
肚
捉
飄
漂
昆
欺
吾
郎
烷
汁
呵
飾
蕭
雅
郵
遷
燕
撒
姻
赴
宴
煩
債
帳
斑
鈴
旨
醇
董
餅
雛
姿
拌
傅
腹
妥
揉
賢
拆
歪
葡
胺
丟
浩
徽
昂
墊
擋
覽
貪
慰
繳
汪
慌
馮
諾
姜
誼
兇
劣
誣
耀
昏
躺
盈
騎
喬
溪
叢
盧
抹
悶
諮
刮
駕
纜
悟
摘
鉺
擲
頗
幻
柄
惠
慘
佳
仇
臘
窩
滌
劍
瞧
堡
潑
蔥
罩
霍
撈
胎
蒼
濱
倆
捅
湘
砍
霞
邵
萄
瘋
淮
遂
熊
糞
烘
宿
檔
戈
駁
嫂
裕
徙
箭
捐
腸
撐
曬
辨
殿
蓮
攤
攪
醬
屏
疫
哀
蔡
堵
沫
皺
暢
疊
閣
萊
敲
轄
鉤
痕
壩
巷
餓
禍
丘
玄
溜
曰
邏
彭
嘗
卿
妨
艇
吞
韋
怨
矮
歇
================================================
FILE: bip-0039/czech.txt
================================================
abdikace
abeceda
adresa
agrese
akce
aktovka
alej
alkohol
amputace
ananas
andulka
anekdota
anketa
antika
anulovat
archa
arogance
asfalt
asistent
aspirace
astma
astronom
atlas
atletika
atol
autobus
azyl
babka
bachor
bacil
baculka
badatel
bageta
bagr
bahno
bakterie
balada
baletka
balkon
balonek
balvan
balza
bambus
bankomat
barbar
baret
barman
baroko
barva
baterka
batoh
bavlna
bazalka
bazilika
bazuka
bedna
beran
beseda
bestie
beton
bezinka
bezmoc
beztak
bicykl
bidlo
biftek
bikiny
bilance
biograf
biolog
bitva
bizon
blahobyt
blatouch
blecha
bledule
blesk
blikat
blizna
blokovat
bloudit
blud
bobek
bobr
bodlina
bodnout
bohatost
bojkot
bojovat
bokorys
bolest
borec
borovice
bota
boubel
bouchat
bouda
boule
bourat
boxer
bradavka
brambora
branka
bratr
brepta
briketa
brko
brloh
bronz
broskev
brunetka
brusinka
brzda
brzy
bublina
bubnovat
buchta
buditel
budka
budova
bufet
bujarost
bukvice
buldok
bulva
bunda
bunkr
burza
butik
buvol
buzola
bydlet
bylina
bytovka
bzukot
capart
carevna
cedr
cedule
cejch
cejn
cela
celer
celkem
celnice
cenina
cennost
cenovka
centrum
cenzor
cestopis
cetka
chalupa
chapadlo
charita
chata
chechtat
chemie
chichot
chirurg
chlad
chleba
chlubit
chmel
chmura
chobot
chochol
chodba
cholera
chomout
chopit
choroba
chov
chrapot
chrlit
chrt
chrup
chtivost
chudina
chutnat
chvat
chvilka
chvost
chyba
chystat
chytit
cibule
cigareta
cihelna
cihla
cinkot
cirkus
cisterna
citace
citrus
cizinec
cizost
clona
cokoliv
couvat
ctitel
ctnost
cudnost
cuketa
cukr
cupot
cvaknout
cval
cvik
cvrkot
cyklista
daleko
dareba
datel
datum
dcera
debata
dechovka
decibel
deficit
deflace
dekl
dekret
demokrat
deprese
derby
deska
detektiv
dikobraz
diktovat
dioda
diplom
disk
displej
divadlo
divoch
dlaha
dlouho
dluhopis
dnes
dobro
dobytek
docent
dochutit
dodnes
dohled
dohoda
dohra
dojem
dojnice
doklad
dokola
doktor
dokument
dolar
doleva
dolina
doma
dominant
domluvit
domov
donutit
dopad
dopis
doplnit
doposud
doprovod
dopustit
dorazit
dorost
dort
dosah
doslov
dostatek
dosud
dosyta
dotaz
dotek
dotknout
doufat
doutnat
dovozce
dozadu
doznat
dozorce
drahota
drak
dramatik
dravec
draze
drdol
drobnost
drogerie
drozd
drsnost
drtit
drzost
duben
duchovno
dudek
duha
duhovka
dusit
dusno
dutost
dvojice
dvorec
dynamit
ekolog
ekonomie
elektron
elipsa
email
emise
emoce
empatie
epizoda
epocha
epopej
epos
esej
esence
eskorta
eskymo
etiketa
euforie
evoluce
exekuce
exkurze
expedice
exploze
export
extrakt
facka
fajfka
fakulta
fanatik
fantazie
farmacie
favorit
fazole
federace
fejeton
fenka
fialka
figurant
filozof
filtr
finance
finta
fixace
fjord
flanel
flirt
flotila
fond
fosfor
fotbal
fotka
foton
frakce
freska
fronta
fukar
funkce
fyzika
galeje
garant
genetika
geolog
gilotina
glazura
glejt
golem
golfista
gotika
graf
gramofon
granule
grep
gril
grog
groteska
guma
hadice
hadr
hala
halenka
hanba
hanopis
harfa
harpuna
havran
hebkost
hejkal
hejno
hejtman
hektar
helma
hematom
herec
herna
heslo
hezky
historik
hladovka
hlasivky
hlava
hledat
hlen
hlodavec
hloh
hloupost
hltat
hlubina
hluchota
hmat
hmota
hmyz
hnis
hnojivo
hnout
hoblina
hoboj
hoch
hodiny
hodlat
hodnota
hodovat
hojnost
hokej
holinka
holka
holub
homole
honitba
honorace
horal
horda
horizont
horko
horlivec
hormon
hornina
horoskop
horstvo
hospoda
hostina
hotovost
houba
houf
houpat
houska
hovor
hradba
hranice
hravost
hrazda
hrbolek
hrdina
hrdlo
hrdost
hrnek
hrobka
hromada
hrot
hrouda
hrozen
hrstka
hrubost
hryzat
hubenost
hubnout
hudba
hukot
humr
husita
hustota
hvozd
hybnost
hydrant
hygiena
hymna
hysterik
idylka
ihned
ikona
iluze
imunita
infekce
inflace
inkaso
inovace
inspekce
internet
invalida
investor
inzerce
ironie
jablko
jachta
jahoda
jakmile
jakost
jalovec
jantar
jarmark
jaro
jasan
jasno
jatka
javor
jazyk
jedinec
jedle
jednatel
jehlan
jekot
jelen
jelito
jemnost
jenom
jepice
jeseter
jevit
jezdec
jezero
jinak
jindy
jinoch
jiskra
jistota
jitrnice
jizva
jmenovat
jogurt
jurta
kabaret
kabel
kabinet
kachna
kadet
kadidlo
kahan
kajak
kajuta
kakao
kaktus
kalamita
kalhoty
kalibr
kalnost
kamera
kamkoliv
kamna
kanibal
kanoe
kantor
kapalina
kapela
kapitola
kapka
kaple
kapota
kapr
kapusta
kapybara
karamel
karotka
karton
kasa
katalog
katedra
kauce
kauza
kavalec
kazajka
kazeta
kazivost
kdekoliv
kdesi
kedluben
kemp
keramika
kino
klacek
kladivo
klam
klapot
klasika
klaun
klec
klenba
klepat
klesnout
klid
klima
klisna
klobouk
klokan
klopa
kloub
klubovna
klusat
kluzkost
kmen
kmitat
kmotr
kniha
knot
koalice
koberec
kobka
kobliha
kobyla
kocour
kohout
kojenec
kokos
koktejl
kolaps
koleda
kolize
kolo
komando
kometa
komik
komnata
komora
kompas
komunita
konat
koncept
kondice
konec
konfese
kongres
konina
konkurs
kontakt
konzerva
kopanec
kopie
kopnout
koprovka
korbel
korektor
kormidlo
koroptev
korpus
koruna
koryto
korzet
kosatec
kostka
kotel
kotleta
kotoul
koukat
koupelna
kousek
kouzlo
kovboj
koza
kozoroh
krabice
krach
krajina
kralovat
krasopis
kravata
kredit
krejcar
kresba
kreveta
kriket
kritik
krize
krkavec
krmelec
krmivo
krocan
krok
kronika
kropit
kroupa
krovka
krtek
kruhadlo
krupice
krutost
krvinka
krychle
krypta
krystal
kryt
kudlanka
kufr
kujnost
kukla
kulajda
kulich
kulka
kulomet
kultura
kuna
kupodivu
kurt
kurzor
kutil
kvalita
kvasinka
kvestor
kynolog
kyselina
kytara
kytice
kytka
kytovec
kyvadlo
labrador
lachtan
ladnost
laik
lakomec
lamela
lampa
lanovka
lasice
laso
lastura
latinka
lavina
lebka
leckdy
leden
lednice
ledovka
ledvina
legenda
legie
legrace
lehce
lehkost
lehnout
lektvar
lenochod
lentilka
lepenka
lepidlo
letadlo
letec
letmo
letokruh
levhart
levitace
levobok
libra
lichotka
lidojed
lidskost
lihovina
lijavec
lilek
limetka
linie
linka
linoleum
listopad
litina
litovat
lobista
lodivod
logika
logoped
lokalita
loket
lomcovat
lopata
lopuch
lord
losos
lotr
loudal
louh
louka
louskat
lovec
lstivost
lucerna
lucifer
lump
lusk
lustrace
lvice
lyra
lyrika
lysina
madam
madlo
magistr
mahagon
majetek
majitel
majorita
makak
makovice
makrela
malba
malina
malovat
malvice
maminka
mandle
manko
marnost
masakr
maskot
masopust
matice
matrika
maturita
mazanec
mazivo
mazlit
mazurka
mdloba
mechanik
meditace
medovina
melasa
meloun
mentolka
metla
metoda
metr
mezera
migrace
mihnout
mihule
mikina
mikrofon
milenec
milimetr
milost
mimika
mincovna
minibar
minomet
minulost
miska
mistr
mixovat
mladost
mlha
mlhovina
mlok
mlsat
mluvit
mnich
mnohem
mobil
mocnost
modelka
modlitba
mohyla
mokro
molekula
momentka
monarcha
monokl
monstrum
montovat
monzun
mosaz
moskyt
most
motivace
motorka
motyka
moucha
moudrost
mozaika
mozek
mozol
mramor
mravenec
mrkev
mrtvola
mrzet
mrzutost
mstitel
mudrc
muflon
mulat
mumie
munice
muset
mutace
muzeum
muzikant
myslivec
mzda
nabourat
nachytat
nadace
nadbytek
nadhoz
nadobro
nadpis
nahlas
nahnat
nahodile
nahradit
naivita
najednou
najisto
najmout
naklonit
nakonec
nakrmit
nalevo
namazat
namluvit
nanometr
naoko
naopak
naostro
napadat
napevno
naplnit
napnout
naposled
naprosto
narodit
naruby
narychlo
nasadit
nasekat
naslepo
nastat
natolik
navenek
navrch
navzdory
nazvat
nebe
nechat
necky
nedaleko
nedbat
neduh
negace
nehet
nehoda
nejen
nejprve
neklid
nelibost
nemilost
nemoc
neochota
neonka
nepokoj
nerost
nerv
nesmysl
nesoulad
netvor
neuron
nevina
nezvykle
nicota
nijak
nikam
nikdy
nikl
nikterak
nitro
nocleh
nohavice
nominace
nora
norek
nositel
nosnost
nouze
noviny
novota
nozdra
nuda
nudle
nuget
nutit
nutnost
nutrie
nymfa
obal
obarvit
obava
obdiv
obec
obehnat
obejmout
obezita
obhajoba
obilnice
objasnit
objekt
obklopit
oblast
oblek
obliba
obloha
obluda
obnos
obohatit
obojek
obout
obrazec
obrna
obruba
obrys
obsah
obsluha
obstarat
obuv
obvaz
obvinit
obvod
obvykle
obyvatel
obzor
ocas
ocel
ocenit
ochladit
ochota
ochrana
ocitnout
odboj
odbyt
odchod
odcizit
odebrat
odeslat
odevzdat
odezva
odhadce
odhodit
odjet
odjinud
odkaz
odkoupit
odliv
odluka
odmlka
odolnost
odpad
odpis
odplout
odpor
odpustit
odpykat
odrazka
odsoudit
odstup
odsun
odtok
odtud
odvaha
odveta
odvolat
odvracet
odznak
ofina
ofsajd
ohlas
ohnisko
ohrada
ohrozit
ohryzek
okap
okenice
oklika
okno
okouzlit
okovy
okrasa
okres
okrsek
okruh
okupant
okurka
okusit
olejnina
olizovat
omak
omeleta
omezit
omladina
omlouvat
omluva
omyl
onehdy
opakovat
opasek
operace
opice
opilost
opisovat
opora
opozice
opravdu
oproti
orbital
orchestr
orgie
orlice
orloj
ortel
osada
oschnout
osika
osivo
oslava
oslepit
oslnit
oslovit
osnova
osoba
osolit
ospalec
osten
ostraha
ostuda
ostych
osvojit
oteplit
otisk
otop
otrhat
otrlost
otrok
otruby
otvor
ovanout
ovar
oves
ovlivnit
ovoce
oxid
ozdoba
pachatel
pacient
padouch
pahorek
pakt
palanda
palec
palivo
paluba
pamflet
pamlsek
panenka
panika
panna
panovat
panstvo
pantofle
paprika
parketa
parodie
parta
paruka
paryba
paseka
pasivita
pastelka
patent
patrona
pavouk
pazneht
pazourek
pecka
pedagog
pejsek
peklo
peloton
penalta
pendrek
penze
periskop
pero
pestrost
petarda
petice
petrolej
pevnina
pexeso
pianista
piha
pijavice
pikle
piknik
pilina
pilnost
pilulka
pinzeta
pipeta
pisatel
pistole
pitevna
pivnice
pivovar
placenta
plakat
plamen
planeta
plastika
platit
plavidlo
plaz
plech
plemeno
plenta
ples
pletivo
plevel
plivat
plnit
plno
plocha
plodina
plomba
plout
pluk
plyn
pobavit
pobyt
pochod
pocit
poctivec
podat
podcenit
podepsat
podhled
podivit
podklad
podmanit
podnik
podoba
podpora
podraz
podstata
podvod
podzim
poezie
pohanka
pohnutka
pohovor
pohroma
pohyb
pointa
pojistka
pojmout
pokazit
pokles
pokoj
pokrok
pokuta
pokyn
poledne
polibek
polknout
poloha
polynom
pomalu
pominout
pomlka
pomoc
pomsta
pomyslet
ponechat
ponorka
ponurost
popadat
popel
popisek
poplach
poprosit
popsat
popud
poradce
porce
porod
porucha
poryv
posadit
posed
posila
poskok
poslanec
posoudit
pospolu
postava
posudek
posyp
potah
potkan
potlesk
potomek
potrava
potupa
potvora
poukaz
pouto
pouzdro
povaha
povidla
povlak
povoz
povrch
povstat
povyk
povzdech
pozdrav
pozemek
poznatek
pozor
pozvat
pracovat
prahory
praktika
prales
praotec
praporek
prase
pravda
princip
prkno
probudit
procento
prodej
profese
prohra
projekt
prolomit
promile
pronikat
propad
prorok
prosba
proton
proutek
provaz
prskavka
prsten
prudkost
prut
prvek
prvohory
psanec
psovod
pstruh
ptactvo
puberta
puch
pudl
pukavec
puklina
pukrle
pult
pumpa
punc
pupen
pusa
pusinka
pustina
putovat
putyka
pyramida
pysk
pytel
racek
rachot
radiace
radnice
radon
raft
ragby
raketa
rakovina
rameno
rampouch
rande
rarach
rarita
rasovna
rastr
ratolest
razance
razidlo
reagovat
reakce
recept
redaktor
referent
reflex
rejnok
reklama
rekord
rekrut
rektor
reputace
revize
revma
revolver
rezerva
riskovat
riziko
robotika
rodokmen
rohovka
rokle
rokoko
romaneto
ropovod
ropucha
rorejs
rosol
rostlina
rotmistr
rotoped
rotunda
roubenka
roucho
roup
roura
rovina
rovnice
rozbor
rozchod
rozdat
rozeznat
rozhodce
rozinka
rozjezd
rozkaz
rozloha
rozmar
rozpad
rozruch
rozsah
roztok
rozum
rozvod
rubrika
ruchadlo
rukavice
rukopis
ryba
rybolov
rychlost
rydlo
rypadlo
rytina
ryzost
sadista
sahat
sako
samec
samizdat
samota
sanitka
sardinka
sasanka
satelit
sazba
sazenice
sbor
schovat
sebranka
secese
sedadlo
sediment
sedlo
sehnat
sejmout
sekera
sekta
sekunda
sekvoje
semeno
seno
servis
sesadit
seshora
seskok
seslat
sestra
sesuv
sesypat
setba
setina
setkat
setnout
setrvat
sever
seznam
shoda
shrnout
sifon
silnice
sirka
sirotek
sirup
situace
skafandr
skalisko
skanzen
skaut
skeptik
skica
skladba
sklenice
sklo
skluz
skoba
skokan
skoro
skripta
skrz
skupina
skvost
skvrna
slabika
sladidlo
slanina
slast
slavnost
sledovat
slepec
sleva
slezina
slib
slina
sliznice
slon
sloupek
slovo
sluch
sluha
slunce
slupka
slza
smaragd
smetana
smilstvo
smlouva
smog
smrad
smrk
smrtka
smutek
smysl
snad
snaha
snob
sobota
socha
sodovka
sokol
sopka
sotva
souboj
soucit
soudce
souhlas
soulad
soumrak
souprava
soused
soutok
souviset
spalovna
spasitel
spis
splav
spodek
spojenec
spolu
sponzor
spornost
spousta
sprcha
spustit
sranda
sraz
srdce
srna
srnec
srovnat
srpen
srst
srub
stanice
starosta
statika
stavba
stehno
stezka
stodola
stolek
stopa
storno
stoupat
strach
stres
strhnout
strom
struna
studna
stupnice
stvol
styk
subjekt
subtropy
suchar
sudost
sukno
sundat
sunout
surikata
surovina
svah
svalstvo
svetr
svatba
svazek
svisle
svitek
svoboda
svodidlo
svorka
svrab
sykavka
sykot
synek
synovec
sypat
sypkost
syrovost
sysel
sytost
tabletka
tabule
tahoun
tajemno
tajfun
tajga
tajit
tajnost
taktika
tamhle
tampon
tancovat
tanec
tanker
tapeta
tavenina
tazatel
technika
tehdy
tekutina
telefon
temnota
tendence
tenista
tenor
teplota
tepna
teprve
terapie
termoska
textil
ticho
tiskopis
titulek
tkadlec
tkanina
tlapka
tleskat
tlukot
tlupa
tmel
toaleta
topinka
topol
torzo
touha
toulec
tradice
traktor
tramp
trasa
traverza
trefit
trest
trezor
trhavina
trhlina
trochu
trojice
troska
trouba
trpce
trpitel
trpkost
trubec
truchlit
truhlice
trus
trvat
tudy
tuhnout
tuhost
tundra
turista
turnaj
tuzemsko
tvaroh
tvorba
tvrdost
tvrz
tygr
tykev
ubohost
uboze
ubrat
ubrousek
ubrus
ubytovna
ucho
uctivost
udivit
uhradit
ujednat
ujistit
ujmout
ukazatel
uklidnit
uklonit
ukotvit
ukrojit
ulice
ulita
ulovit
umyvadlo
unavit
uniforma
uniknout
upadnout
uplatnit
uplynout
upoutat
upravit
uran
urazit
usednout
usilovat
usmrtit
usnadnit
usnout
usoudit
ustlat
ustrnout
utahovat
utkat
utlumit
utonout
utopenec
utrousit
uvalit
uvolnit
uvozovka
uzdravit
uzel
uzenina
uzlina
uznat
vagon
valcha
valoun
vana
vandal
vanilka
varan
varhany
varovat
vcelku
vchod
vdova
vedro
vegetace
vejce
velbloud
veletrh
velitel
velmoc
velryba
venkov
veranda
verze
veselka
veskrze
vesnice
vespodu
vesta
veterina
veverka
vibrace
vichr
videohra
vidina
vidle
vila
vinice
viset
vitalita
vize
vizitka
vjezd
vklad
vkus
vlajka
vlak
vlasec
vlevo
vlhkost
vliv
vlnovka
vloupat
vnucovat
vnuk
voda
vodivost
vodoznak
vodstvo
vojensky
vojna
vojsko
volant
volba
volit
volno
voskovka
vozidlo
vozovna
vpravo
vrabec
vracet
vrah
vrata
vrba
vrcholek
vrhat
vrstva
vrtule
vsadit
vstoupit
vstup
vtip
vybavit
vybrat
vychovat
vydat
vydra
vyfotit
vyhledat
vyhnout
vyhodit
vyhradit
vyhubit
vyjasnit
vyjet
vyjmout
vyklopit
vykonat
vylekat
vymazat
vymezit
vymizet
vymyslet
vynechat
vynikat
vynutit
vypadat
vyplatit
vypravit
vypustit
vyrazit
vyrovnat
vyrvat
vyslovit
vysoko
vystavit
vysunout
vysypat
vytasit
vytesat
vytratit
vyvinout
vyvolat
vyvrhel
vyzdobit
vyznat
vzadu
vzbudit
vzchopit
vzdor
vzduch
vzdychat
vzestup
vzhledem
vzkaz
vzlykat
vznik
vzorek
vzpoura
vztah
vztek
xylofon
zabrat
zabydlet
zachovat
zadarmo
zadusit
zafoukat
zahltit
zahodit
zahrada
zahynout
zajatec
zajet
zajistit
zaklepat
zakoupit
zalepit
zamezit
zamotat
zamyslet
zanechat
zanikat
zaplatit
zapojit
zapsat
zarazit
zastavit
zasunout
zatajit
zatemnit
zatknout
zaujmout
zavalit
zavelet
zavinit
zavolat
zavrtat
zazvonit
zbavit
zbrusu
zbudovat
zbytek
zdaleka
zdarma
zdatnost
zdivo
zdobit
zdroj
zdvih
zdymadlo
zelenina
zeman
zemina
zeptat
zezadu
zezdola
zhatit
zhltnout
zhluboka
zhotovit
zhruba
zima
zimnice
zjemnit
zklamat
zkoumat
zkratka
zkumavka
zlato
zlehka
zloba
zlom
zlost
zlozvyk
zmapovat
zmar
zmatek
zmije
zmizet
zmocnit
zmodrat
zmrzlina
zmutovat
znak
znalost
znamenat
znovu
zobrazit
zotavit
zoubek
zoufale
zplodit
zpomalit
zprava
zprostit
zprudka
zprvu
zrada
zranit
zrcadlo
zrnitost
zrno
zrovna
zrychlit
zrzavost
zticha
ztratit
zubovina
zubr
zvednout
zvenku
zvesela
zvon
zvrat
zvukovod
zvyk
================================================
FILE: bip-0039/english.txt
================================================
abandon
ability
able
about
above
absent
absorb
abstract
absurd
abuse
access
accident
account
accuse
achieve
acid
acoustic
acquire
across
act
action
actor
actress
actual
adapt
add
addict
address
adjust
admit
adult
advance
advice
aerobic
affair
afford
afraid
again
age
agent
agree
ahead
aim
air
airport
aisle
alarm
album
alcohol
alert
alien
all
alley
allow
almost
alone
alpha
already
also
alter
always
amateur
amazing
among
amount
amused
analyst
anchor
ancient
anger
angle
angry
animal
ankle
announce
annual
another
answer
antenna
antique
anxiety
any
apart
apology
appear
apple
approve
april
arch
arctic
area
arena
argue
arm
armed
armor
army
around
arrange
arrest
arrive
arrow
art
artefact
artist
artwork
ask
aspect
assault
asset
assist
assume
asthma
athlete
atom
attack
attend
attitude
attract
auction
audit
august
aunt
author
auto
autumn
average
avocado
avoid
awake
aware
away
awesome
awful
awkward
axis
baby
bachelor
bacon
badge
bag
balance
balcony
ball
bamboo
banana
banner
bar
barely
bargain
barrel
base
basic
basket
battle
beach
bean
beauty
because
become
beef
before
begin
behave
behind
believe
below
belt
bench
benefit
best
betray
better
between
beyond
bicycle
bid
bike
bind
biology
bird
birth
bitter
black
blade
blame
blanket
blast
bleak
bless
blind
blood
blossom
blouse
blue
blur
blush
board
boat
body
boil
bomb
bone
bonus
book
boost
border
boring
borrow
boss
bottom
bounce
box
boy
bracket
brain
brand
brass
brave
bread
breeze
brick
bridge
brief
bright
bring
brisk
broccoli
broken
bronze
broom
brother
brown
brush
bubble
buddy
budget
buffalo
build
bulb
bulk
bullet
bundle
bunker
burden
burger
burst
bus
business
busy
butter
buyer
buzz
cabbage
cabin
cable
cactus
cage
cake
call
calm
camera
camp
can
canal
cancel
candy
cannon
canoe
canvas
canyon
capable
capital
captain
car
carbon
card
cargo
carpet
carry
cart
case
cash
casino
castle
casual
cat
catalog
catch
category
cattle
caught
cause
caution
cave
ceiling
celery
cement
census
century
cereal
certain
chair
chalk
champion
change
chaos
chapter
charge
chase
chat
cheap
check
cheese
chef
cherry
chest
chicken
chief
child
chimney
choice
choose
chronic
chuckle
chunk
churn
cigar
cinnamon
circle
citizen
city
civil
claim
clap
clarify
claw
clay
clean
clerk
clever
click
client
cliff
climb
clinic
clip
clock
clog
close
cloth
cloud
clown
club
clump
cluster
clutch
coach
coast
coconut
code
coffee
coil
coin
collect
color
column
combine
come
comfort
comic
common
company
concert
conduct
confirm
congress
connect
consider
control
convince
cook
cool
copper
copy
coral
core
corn
correct
cost
cotton
couch
country
couple
course
cousin
cover
coyote
crack
cradle
craft
cram
crane
crash
crater
crawl
crazy
cream
credit
creek
crew
cricket
crime
crisp
critic
crop
cross
crouch
crowd
crucial
cruel
cruise
crumble
crunch
crush
cry
crystal
cube
culture
cup
cupboard
curious
current
curtain
curve
cushion
custom
cute
cycle
dad
damage
damp
dance
danger
daring
dash
daughter
dawn
day
deal
debate
debris
decade
december
decide
decline
decorate
decrease
deer
defense
define
defy
degree
delay
deliver
demand
demise
denial
dentist
deny
depart
depend
deposit
depth
deputy
derive
describe
desert
design
desk
despair
destroy
detail
detect
develop
device
devote
diagram
dial
diamond
diary
dice
diesel
diet
differ
digital
dignity
dilemma
dinner
dinosaur
direct
dirt
disagree
discover
disease
dish
dismiss
disorder
display
distance
divert
divide
divorce
dizzy
doctor
document
dog
doll
dolphin
domain
donate
donkey
donor
door
dose
double
dove
draft
dragon
drama
drastic
draw
dream
dress
drift
drill
drink
drip
drive
drop
drum
dry
duck
dumb
dune
during
dust
dutch
duty
dwarf
dynamic
eager
eagle
early
earn
earth
easily
east
easy
echo
ecology
economy
edge
edit
educate
effort
egg
eight
either
elbow
elder
electric
elegant
element
elephant
elevator
elite
else
embark
embody
embrace
emerge
emotion
employ
empower
empty
enable
enact
end
endless
endorse
enemy
energy
enforce
engage
engine
enhance
enjoy
enlist
enough
enrich
enroll
ensure
enter
entire
entry
envelope
episode
equal
equip
era
erase
erode
erosion
error
erupt
escape
essay
essence
estate
eternal
ethics
evidence
evil
evoke
evolve
exact
example
excess
exchange
excite
exclude
excuse
execute
exercise
exhaust
exhibit
exile
exist
exit
exotic
expand
expect
expire
explain
expose
express
extend
extra
eye
eyebrow
fabric
face
faculty
fade
faint
faith
fall
false
fame
family
famous
fan
fancy
fantasy
farm
fashion
fat
fatal
father
fatigue
fault
favorite
feature
february
federal
fee
feed
feel
female
fence
festival
fetch
fever
few
fiber
fiction
field
figure
file
film
filter
final
find
fine
finger
finish
fire
firm
first
fiscal
fish
fit
fitness
fix
flag
flame
flash
flat
flavor
flee
flight
flip
float
flock
floor
flower
fluid
flush
fly
foam
focus
fog
foil
fold
follow
food
foot
force
forest
forget
fork
fortune
forum
forward
fossil
foster
found
fox
fragile
frame
frequent
fresh
friend
fringe
frog
front
frost
frown
frozen
fruit
fuel
fun
funny
furnace
fury
future
gadget
gain
galaxy
gallery
game
gap
garage
garbage
garden
garlic
garment
gas
gasp
gate
gather
gauge
gaze
general
genius
genre
gentle
genuine
gesture
ghost
giant
gift
giggle
ginger
giraffe
girl
give
glad
glance
glare
glass
glide
glimpse
globe
gloom
glory
glove
glow
glue
goat
goddess
gold
good
goose
gorilla
gospel
gossip
govern
gown
grab
grace
grain
grant
grape
grass
gravity
great
green
grid
grief
grit
grocery
group
grow
grunt
guard
guess
guide
guilt
guitar
gun
gym
habit
hair
half
hammer
hamster
hand
happy
harbor
hard
harsh
harvest
hat
have
hawk
hazard
head
health
heart
heavy
hedgehog
height
hello
helmet
help
hen
hero
hidden
high
hill
hint
hip
hire
history
hobby
hockey
hold
hole
holiday
hollow
home
honey
hood
hope
horn
horror
horse
hospital
host
hotel
hour
hover
hub
huge
human
humble
humor
hundred
hungry
hunt
hurdle
hurry
hurt
husband
hybrid
ice
icon
idea
identify
idle
ignore
ill
illegal
illness
image
imitate
immense
immune
impact
impose
improve
impulse
inch
include
income
increase
index
indicate
indoor
industry
infant
inflict
inform
inhale
inherit
initial
inject
injury
inmate
inner
innocent
input
inquiry
insane
insect
inside
inspire
install
intact
interest
into
invest
invite
involve
iron
island
isolate
issue
item
ivory
jacket
jaguar
jar
jazz
jealous
jeans
jelly
jewel
job
join
joke
journey
joy
judge
juice
jump
jungle
junior
junk
just
kangaroo
keen
keep
ketchup
key
kick
kid
kidney
kind
kingdom
kiss
kit
kitchen
kite
kitten
kiwi
knee
knife
knock
know
lab
label
labor
ladder
lady
lake
lamp
language
laptop
large
later
latin
laugh
laundry
lava
law
lawn
lawsuit
layer
lazy
leader
leaf
learn
leave
lecture
left
leg
legal
legend
leisure
lemon
lend
length
lens
leopard
lesson
letter
level
liar
liberty
library
license
life
lift
light
like
limb
limit
link
lion
liquid
list
little
live
lizard
load
loan
lobster
local
lock
logic
lonely
long
loop
lottery
loud
lounge
love
loyal
lucky
luggage
lumber
lunar
lunch
luxury
lyrics
machine
mad
magic
magnet
maid
mail
main
major
make
mammal
man
manage
mandate
mango
mansion
manual
maple
marble
march
margin
marine
market
marriage
mask
mass
master
match
material
math
matrix
matter
maximum
maze
meadow
mean
measure
meat
mechanic
medal
media
melody
melt
member
memory
mention
menu
mercy
merge
merit
merry
mesh
message
metal
method
middle
midnight
milk
million
mimic
mind
minimum
minor
minute
miracle
mirror
misery
miss
mistake
mix
mixed
mixture
mobile
model
modify
mom
moment
monitor
monkey
monster
month
moon
moral
more
morning
mosquito
mother
motion
motor
mountain
mouse
move
movie
much
muffin
mule
multiply
muscle
museum
mushroom
music
must
mutual
myself
mystery
myth
naive
name
napkin
narrow
nasty
nation
nature
near
neck
need
negative
neglect
neither
nephew
nerve
nest
net
network
neutral
never
news
next
nice
night
noble
noise
nominee
noodle
normal
north
nose
notable
note
nothing
notice
novel
now
nuclear
number
nurse
nut
oak
obey
object
oblige
obscure
observe
obtain
obvious
occur
ocean
october
odor
off
offer
office
often
oil
okay
old
olive
olympic
omit
once
one
onion
online
only
open
opera
opinion
oppose
option
orange
orbit
orchard
order
ordinary
organ
orient
original
orphan
ostrich
other
outdoor
outer
output
outside
oval
oven
over
own
owner
oxygen
oyster
ozone
pact
paddle
page
pair
palace
palm
panda
panel
panic
panther
paper
parade
parent
park
parrot
party
pass
patch
path
patient
patrol
pattern
pause
pave
payment
peace
peanut
pear
peasant
pelican
pen
penalty
pencil
people
pepper
perfect
permit
person
pet
phone
photo
phrase
physical
piano
picnic
picture
piece
pig
pigeon
pill
pilot
pink
pioneer
pipe
pistol
pitch
pizza
place
planet
plastic
plate
play
please
pledge
pluck
plug
plunge
poem
poet
point
polar
pole
police
pond
pony
pool
popular
portion
position
possible
post
potato
pottery
poverty
powder
power
practice
praise
predict
prefer
prepare
present
pretty
prevent
price
pride
primary
print
priority
prison
private
prize
problem
process
produce
profit
program
project
promote
proof
property
prosper
protect
proud
provide
public
pudding
pull
pulp
pulse
pumpkin
punch
pupil
puppy
purchase
purity
purpose
purse
push
put
puzzle
pyramid
quality
quantum
quarter
question
quick
quit
quiz
quote
rabbit
raccoon
race
rack
radar
radio
rail
rain
raise
rally
ramp
ranch
random
range
rapid
rare
rate
rather
raven
raw
razor
ready
real
reason
rebel
rebuild
recall
receive
recipe
record
recycle
reduce
reflect
reform
refuse
region
regret
regular
reject
relax
release
relief
rely
remain
remember
remind
remove
render
renew
rent
reopen
repair
repeat
replace
report
require
rescue
resemble
resist
resource
response
result
retire
retreat
return
reunion
reveal
review
reward
rhythm
rib
ribbon
rice
rich
ride
ridge
rifle
right
rigid
ring
riot
ripple
risk
ritual
rival
river
road
roast
robot
robust
rocket
romance
roof
rookie
room
rose
rotate
rough
round
route
royal
rubber
rude
rug
rule
run
runway
rural
sad
saddle
sadness
safe
sail
salad
salmon
salon
salt
salute
same
sample
sand
satisfy
satoshi
sauce
sausage
save
say
scale
scan
scare
scatter
scene
scheme
school
science
scissors
scorpion
scout
scrap
screen
script
scrub
sea
search
season
seat
second
secret
section
security
seed
seek
segment
select
sell
seminar
senior
sense
sentence
series
service
session
settle
setup
seven
shadow
shaft
shallow
share
shed
shell
sheriff
shield
shift
shine
ship
shiver
shock
shoe
shoot
shop
short
shoulder
shove
shrimp
shrug
shuffle
shy
sibling
sick
side
siege
sight
sign
silent
silk
silly
silver
similar
simple
since
sing
siren
sister
situate
six
size
skate
sketch
ski
skill
skin
skirt
skull
slab
slam
sleep
slender
slice
slide
slight
slim
slogan
slot
slow
slush
small
smart
smile
smoke
smooth
snack
snake
snap
sniff
snow
soap
soccer
social
sock
soda
soft
solar
soldier
solid
solution
solve
someone
song
soon
sorry
sort
soul
sound
soup
source
south
space
spare
spatial
spawn
speak
special
speed
spell
spend
sphere
spice
spider
spike
spin
spirit
split
spoil
sponsor
spoon
sport
spot
spray
spread
spring
spy
square
squeeze
squirrel
stable
stadium
staff
stage
stairs
stamp
stand
start
state
stay
steak
steel
stem
step
stereo
stick
still
sting
stock
stomach
stone
stool
story
stove
strategy
street
strike
strong
struggle
student
stuff
stumble
style
subject
submit
subway
success
such
sudden
suffer
sugar
suggest
suit
summer
sun
sunny
sunset
super
supply
supreme
sure
surface
surge
surprise
surround
survey
suspect
sustain
swallow
swamp
swap
swarm
swear
sweet
swift
swim
swing
switch
sword
symbol
symptom
syrup
system
table
tackle
tag
tail
talent
talk
tank
tape
target
task
taste
tattoo
taxi
teach
team
tell
ten
tenant
tennis
tent
term
test
text
thank
that
theme
then
theory
there
they
thing
this
thought
three
thrive
throw
thumb
thunder
ticket
tide
tiger
tilt
timber
time
tiny
tip
tired
tissue
title
toast
tobacco
today
toddler
toe
together
toilet
token
tomato
tomorrow
tone
tongue
tonight
tool
tooth
top
topic
topple
torch
tornado
tortoise
toss
total
tourist
toward
tower
town
toy
track
trade
traffic
tragic
train
transfer
trap
trash
travel
tray
treat
tree
trend
trial
tribe
trick
trigger
trim
trip
trophy
trouble
truck
true
truly
trumpet
trust
truth
try
tube
tuition
tumble
tuna
tunnel
turkey
turn
turtle
twelve
twenty
twice
twin
twist
two
type
typical
ugly
umbrella
unable
unaware
uncle
uncover
under
undo
unfair
unfold
unhappy
uniform
unique
unit
universe
unknown
unlock
until
unusual
unveil
update
upgrade
uphold
upon
upper
upset
urban
urge
usage
use
used
useful
useless
usual
utility
vacant
vacuum
vague
valid
valley
valve
van
vanish
vapor
various
vast
vault
vehicle
velvet
vendor
venture
venue
verb
verify
version
very
vessel
veteran
viable
vibrant
vicious
victory
video
view
village
vintage
violin
virtual
virus
visa
visit
visual
vital
vivid
vocal
voice
void
volcano
volume
vote
voyage
wage
wagon
wait
walk
wall
walnut
want
warfare
warm
warrior
wash
wasp
waste
water
wave
way
wealth
weapon
wear
weasel
weather
web
wedding
weekend
weird
welcome
west
wet
whale
what
wheat
wheel
when
where
whip
whisper
wide
width
wife
wild
will
win
window
wine
wing
wink
winner
winter
wire
wisdom
wise
wish
witness
wolf
woman
wonder
wood
wool
word
work
world
worry
worth
wrap
wreck
wrestle
wrist
write
wrong
yard
year
yellow
you
young
youth
zebra
zero
zone
zoo
================================================
FILE: bip-0039/french.txt
================================================
abaisser
abandon
abdiquer
abeille
abolir
aborder
aboutir
aboyer
abrasif
abreuver
abriter
abroger
abrupt
absence
absolu
absurde
abusif
abyssal
académie
acajou
acarien
accabler
accepter
acclamer
accolade
accroche
accuser
acerbe
achat
acheter
aciduler
acier
acompte
acquérir
acronyme
acteur
actif
actuel
adepte
adéquat
adhésif
adjectif
adjuger
admettre
admirer
adopter
adorer
adoucir
adresse
adroit
adulte
adverbe
aérer
aéronef
affaire
affecter
affiche
affreux
affubler
agacer
agencer
agile
agiter
agrafer
agréable
agrume
aider
aiguille
ailier
aimable
aisance
ajouter
ajuster
alarmer
alchimie
alerte
algèbre
algue
aliéner
aliment
alléger
alliage
allouer
allumer
alourdir
alpaga
altesse
alvéole
amateur
ambigu
ambre
aménager
amertume
amidon
amiral
amorcer
amour
amovible
amphibie
ampleur
amusant
analyse
anaphore
anarchie
anatomie
ancien
anéantir
angle
angoisse
anguleux
animal
annexer
annonce
annuel
anodin
anomalie
anonyme
anormal
antenne
antidote
anxieux
apaiser
apéritif
aplanir
apologie
appareil
appeler
apporter
appuyer
aquarium
aqueduc
arbitre
arbuste
ardeur
ardoise
argent
arlequin
armature
armement
armoire
armure
arpenter
arracher
arriver
arroser
arsenic
artériel
article
aspect
asphalte
aspirer
assaut
asservir
assiette
associer
assurer
asticot
astre
astuce
atelier
atome
atrium
atroce
attaque
attentif
attirer
attraper
aubaine
auberge
audace
audible
augurer
aurore
automne
autruche
avaler
avancer
avarice
avenir
averse
aveugle
aviateur
avide
avion
aviser
avoine
avouer
avril
axial
axiome
badge
bafouer
bagage
baguette
baignade
balancer
balcon
baleine
balisage
bambin
bancaire
bandage
banlieue
bannière
banquier
barbier
baril
baron
barque
barrage
bassin
bastion
bataille
bateau
batterie
baudrier
bavarder
belette
bélier
belote
bénéfice
berceau
berger
berline
bermuda
besace
besogne
bétail
beurre
biberon
bicycle
bidule
bijou
bilan
bilingue
billard
binaire
biologie
biopsie
biotype
biscuit
bison
bistouri
bitume
bizarre
blafard
blague
blanchir
blessant
blinder
blond
bloquer
blouson
bobard
bobine
boire
boiser
bolide
bonbon
bondir
bonheur
bonifier
bonus
bordure
borne
botte
boucle
boueux
bougie
boulon
bouquin
bourse
boussole
boutique
boxeur
branche
brasier
brave
brebis
brèche
breuvage
bricoler
brigade
brillant
brioche
brique
brochure
broder
bronzer
brousse
broyeur
brume
brusque
brutal
bruyant
buffle
buisson
bulletin
bureau
burin
bustier
butiner
butoir
buvable
buvette
cabanon
cabine
cachette
cadeau
cadre
caféine
caillou
caisson
calculer
calepin
calibre
calmer
calomnie
calvaire
camarade
caméra
camion
campagne
canal
caneton
canon
cantine
canular
capable
caporal
caprice
capsule
capter
capuche
carabine
carbone
caresser
caribou
carnage
carotte
carreau
carton
cascade
casier
casque
cassure
causer
caution
cavalier
caverne
caviar
cédille
ceinture
céleste
cellule
cendrier
censurer
central
cercle
cérébral
cerise
cerner
cerveau
cesser
chagrin
chaise
chaleur
chambre
chance
chapitre
charbon
chasseur
chaton
chausson
chavirer
chemise
chenille
chéquier
chercher
cheval
chien
chiffre
chignon
chimère
chiot
chlorure
chocolat
choisir
chose
chouette
chrome
chute
cigare
cigogne
cimenter
cinéma
cintrer
circuler
cirer
cirque
citerne
citoyen
citron
civil
clairon
clameur
claquer
classe
clavier
client
cligner
climat
clivage
cloche
clonage
cloporte
cobalt
cobra
cocasse
cocotier
coder
codifier
coffre
cogner
cohésion
coiffer
coincer
colère
colibri
colline
colmater
colonel
combat
comédie
commande
compact
concert
conduire
confier
congeler
connoter
consonne
contact
convexe
copain
copie
corail
corbeau
cordage
corniche
corpus
correct
cortège
cosmique
costume
coton
coude
coupure
courage
couteau
couvrir
coyote
crabe
crainte
cravate
crayon
créature
créditer
crémeux
creuser
crevette
cribler
crier
cristal
critère
croire
croquer
crotale
crucial
cruel
crypter
cubique
cueillir
cuillère
cuisine
cuivre
culminer
cultiver
cumuler
cupide
curatif
curseur
cyanure
cycle
cylindre
cynique
daigner
damier
danger
danseur
dauphin
débattre
débiter
déborder
débrider
débutant
décaler
décembre
déchirer
décider
déclarer
décorer
décrire
décupler
dédale
déductif
déesse
défensif
défiler
défrayer
dégager
dégivrer
déglutir
dégrafer
déjeuner
délice
déloger
demander
demeurer
démolir
dénicher
dénouer
dentelle
dénuder
départ
dépenser
déphaser
déplacer
déposer
déranger
dérober
désastre
descente
désert
désigner
désobéir
dessiner
destrier
détacher
détester
détourer
détresse
devancer
devenir
deviner
devoir
diable
dialogue
diamant
dicter
différer
digérer
digital
digne
diluer
dimanche
diminuer
dioxyde
directif
diriger
discuter
disposer
dissiper
distance
divertir
diviser
docile
docteur
dogme
doigt
domaine
domicile
dompter
donateur
donjon
donner
dopamine
dortoir
dorure
dosage
doseur
dossier
dotation
douanier
double
douceur
douter
doyen
dragon
draper
dresser
dribbler
droiture
duperie
duplexe
durable
durcir
dynastie
éblouir
écarter
écharpe
échelle
éclairer
éclipse
éclore
écluse
école
économie
écorce
écouter
écraser
écrémer
écrivain
écrou
écume
écureuil
édifier
éduquer
effacer
effectif
effigie
effort
effrayer
effusion
égaliser
égarer
éjecter
élaborer
élargir
électron
élégant
éléphant
élève
éligible
élitisme
éloge
élucider
éluder
emballer
embellir
embryon
émeraude
émission
emmener
émotion
émouvoir
empereur
employer
emporter
emprise
émulsion
encadrer
enchère
enclave
encoche
endiguer
endosser
endroit
enduire
énergie
enfance
enfermer
enfouir
engager
engin
englober
énigme
enjamber
enjeu
enlever
ennemi
ennuyeux
enrichir
enrobage
enseigne
entasser
entendre
entier
entourer
entraver
énumérer
envahir
enviable
envoyer
enzyme
éolien
épaissir
épargne
épatant
épaule
épicerie
épidémie
épier
épilogue
épine
épisode
épitaphe
époque
épreuve
éprouver
épuisant
équerre
équipe
ériger
érosion
erreur
éruption
escalier
espadon
espèce
espiègle
espoir
esprit
esquiver
essayer
essence
essieu
essorer
estime
estomac
estrade
étagère
étaler
étanche
étatique
éteindre
étendoir
éternel
éthanol
éthique
ethnie
étirer
étoffer
étoile
étonnant
étourdir
étrange
étroit
étude
euphorie
évaluer
évasion
éventail
évidence
éviter
évolutif
évoquer
exact
exagérer
exaucer
exceller
excitant
exclusif
excuse
exécuter
exemple
exercer
exhaler
exhorter
exigence
exiler
exister
exotique
expédier
explorer
exposer
exprimer
exquis
extensif
extraire
exulter
fable
fabuleux
facette
facile
facture
faiblir
falaise
fameux
famille
farceur
farfelu
farine
farouche
fasciner
fatal
fatigue
faucon
fautif
faveur
favori
fébrile
féconder
fédérer
félin
femme
fémur
fendoir
féodal
fermer
féroce
ferveur
festival
feuille
feutre
février
fiasco
ficeler
fictif
fidèle
figure
filature
filetage
filière
filleul
filmer
filou
filtrer
financer
finir
fiole
firme
fissure
fixer
flairer
flamme
flasque
flatteur
fléau
flèche
fleur
flexion
flocon
flore
fluctuer
fluide
fluvial
folie
fonderie
fongible
fontaine
forcer
forgeron
formuler
fortune
fossile
foudre
fougère
fouiller
foulure
fourmi
fragile
fraise
franchir
frapper
frayeur
frégate
freiner
frelon
frémir
frénésie
frère
friable
friction
frisson
frivole
froid
fromage
frontal
frotter
fruit
fugitif
fuite
fureur
furieux
furtif
fusion
futur
gagner
galaxie
galerie
gambader
garantir
gardien
garnir
garrigue
gazelle
gazon
géant
gélatine
gélule
gendarme
général
génie
genou
gentil
géologie
géomètre
géranium
germe
gestuel
geyser
gibier
gicler
girafe
givre
glace
glaive
glisser
globe
gloire
glorieux
golfeur
gomme
gonfler
gorge
gorille
goudron
gouffre
goulot
goupille
gourmand
goutte
graduel
graffiti
graine
grand
grappin
gratuit
gravir
grenat
griffure
griller
grimper
grogner
gronder
grotte
groupe
gruger
grutier
gruyère
guépard
guerrier
guide
guimauve
guitare
gustatif
gymnaste
gyrostat
habitude
hachoir
halte
hameau
hangar
hanneton
haricot
harmonie
harpon
hasard
hélium
hématome
herbe
hérisson
hermine
héron
hésiter
heureux
hiberner
hibou
hilarant
histoire
hiver
homard
hommage
homogène
honneur
honorer
honteux
horde
horizon
horloge
hormone
horrible
houleux
housse
hublot
huileux
humain
humble
humide
humour
hurler
hydromel
hygiène
hymne
hypnose
idylle
ignorer
iguane
illicite
illusion
image
imbiber
imiter
immense
immobile
immuable
impact
impérial
implorer
imposer
imprimer
imputer
incarner
incendie
incident
incliner
incolore
indexer
indice
inductif
inédit
ineptie
inexact
infini
infliger
informer
infusion
ingérer
inhaler
inhiber
injecter
injure
innocent
inoculer
inonder
inscrire
insecte
insigne
insolite
inspirer
instinct
insulter
intact
intense
intime
intrigue
intuitif
inutile
invasion
inventer
inviter
invoquer
ironique
irradier
irréel
irriter
isoler
ivoire
ivresse
jaguar
jaillir
jambe
janvier
jardin
jauger
jaune
javelot
jetable
jeton
jeudi
jeunesse
joindre
joncher
jongler
joueur
jouissif
journal
jovial
joyau
joyeux
jubiler
jugement
junior
jupon
juriste
justice
juteux
juvénile
kayak
kimono
kiosque
label
labial
labourer
lacérer
lactose
lagune
laine
laisser
laitier
lambeau
lamelle
lampe
lanceur
langage
lanterne
lapin
largeur
larme
laurier
lavabo
lavoir
lecture
légal
léger
légume
lessive
lettre
levier
lexique
lézard
liasse
libérer
libre
licence
licorne
liège
lièvre
ligature
ligoter
ligue
limer
limite
limonade
limpide
linéaire
lingot
lionceau
liquide
lisière
lister
lithium
litige
littoral
livreur
logique
lointain
loisir
lombric
loterie
louer
lourd
loutre
louve
loyal
lubie
lucide
lucratif
lueur
lugubre
luisant
lumière
lunaire
lundi
luron
lutter
luxueux
machine
magasin
magenta
magique
maigre
maillon
maintien
mairie
maison
majorer
malaxer
maléfice
malheur
malice
mallette
mammouth
mandater
maniable
manquant
manteau
manuel
marathon
marbre
marchand
mardi
maritime
marqueur
marron
marteler
mascotte
massif
matériel
matière
matraque
maudire
maussade
mauve
maximal
méchant
méconnu
médaille
médecin
méditer
méduse
meilleur
mélange
mélodie
membre
mémoire
menacer
mener
menhir
mensonge
mentor
mercredi
mérite
merle
messager
mesure
métal
météore
méthode
métier
meuble
miauler
microbe
miette
mignon
migrer
milieu
million
mimique
mince
minéral
minimal
minorer
minute
miracle
miroiter
missile
mixte
mobile
moderne
moelleux
mondial
moniteur
monnaie
monotone
monstre
montagne
monument
moqueur
morceau
morsure
mortier
moteur
motif
mouche
moufle
moulin
mousson
mouton
mouvant
multiple
munition
muraille
murène
murmure
muscle
muséum
musicien
mutation
muter
mutuel
myriade
myrtille
mystère
mythique
nageur
nappe
narquois
narrer
natation
nation
nature
naufrage
nautique
navire
nébuleux
nectar
néfaste
négation
négliger
négocier
neige
nerveux
nettoyer
neurone
neutron
neveu
niche
nickel
nitrate
niveau
noble
nocif
nocturne
noirceur
noisette
nomade
nombreux
nommer
normatif
notable
notifier
notoire
nourrir
nouveau
novateur
novembre
novice
nuage
nuancer
nuire
nuisible
numéro
nuptial
nuque
nutritif
obéir
objectif
obliger
obscur
observer
obstacle
obtenir
obturer
occasion
occuper
océan
octobre
octroyer
octupler
oculaire
odeur
odorant
offenser
officier
offrir
ogive
oiseau
oisillon
olfactif
olivier
ombrage
omettre
onctueux
onduler
onéreux
onirique
opale
opaque
opérer
opinion
opportun
opprimer
opter
optique
orageux
orange
orbite
ordonner
oreille
organe
orgueil
orifice
ornement
orque
ortie
osciller
osmose
ossature
otarie
ouragan
ourson
outil
outrager
ouvrage
ovation
oxyde
oxygène
ozone
paisible
palace
palmarès
palourde
palper
panache
panda
pangolin
paniquer
panneau
panorama
pantalon
papaye
papier
papoter
papyrus
paradoxe
parcelle
paresse
parfumer
parler
parole
parrain
parsemer
partager
parure
parvenir
passion
pastèque
paternel
patience
patron
pavillon
pavoiser
payer
paysage
peigne
peintre
pelage
pélican
pelle
pelouse
peluche
pendule
pénétrer
pénible
pensif
pénurie
pépite
péplum
perdrix
perforer
période
permuter
perplexe
persil
perte
peser
pétale
petit
pétrir
peuple
pharaon
phobie
phoque
photon
phrase
physique
piano
pictural
pièce
pierre
pieuvre
pilote
pinceau
pipette
piquer
pirogue
piscine
piston
pivoter
pixel
pizza
placard
plafond
plaisir
planer
plaque
plastron
plateau
pleurer
plexus
pliage
plomb
plonger
pluie
plumage
pochette
poésie
poète
pointe
poirier
poisson
poivre
polaire
policier
pollen
polygone
pommade
pompier
ponctuel
pondérer
poney
portique
position
posséder
posture
potager
poteau
potion
pouce
poulain
poumon
pourpre
poussin
pouvoir
prairie
pratique
précieux
prédire
préfixe
prélude
prénom
présence
prétexte
prévoir
primitif
prince
prison
priver
problème
procéder
prodige
profond
progrès
proie
projeter
prologue
promener
propre
prospère
protéger
prouesse
proverbe
prudence
pruneau
psychose
public
puceron
puiser
pulpe
pulsar
punaise
punitif
pupitre
purifier
puzzle
pyramide
quasar
querelle
question
quiétude
quitter
quotient
racine
raconter
radieux
ragondin
raideur
raisin
ralentir
rallonge
ramasser
rapide
rasage
ratisser
ravager
ravin
rayonner
réactif
réagir
réaliser
réanimer
recevoir
réciter
réclamer
récolter
recruter
reculer
recycler
rédiger
redouter
refaire
réflexe
réformer
refrain
refuge
régalien
région
réglage
régulier
réitérer
rejeter
rejouer
relatif
relever
relief
remarque
remède
remise
remonter
remplir
remuer
renard
renfort
renifler
renoncer
rentrer
renvoi
replier
reporter
reprise
reptile
requin
réserve
résineux
résoudre
respect
rester
résultat
rétablir
retenir
réticule
retomber
retracer
réunion
réussir
revanche
revivre
révolte
révulsif
richesse
rideau
rieur
rigide
rigoler
rincer
riposter
risible
risque
rituel
rival
rivière
rocheux
romance
rompre
ronce
rondin
roseau
rosier
rotatif
rotor
rotule
rouge
rouille
rouleau
routine
royaume
ruban
rubis
ruche
ruelle
rugueux
ruiner
ruisseau
ruser
rustique
rythme
sabler
saboter
sabre
sacoche
safari
sagesse
saisir
salade
salive
salon
saluer
samedi
sanction
sanglier
sarcasme
sardine
saturer
saugrenu
saumon
sauter
sauvage
savant
savonner
scalpel
scandale
scélérat
scénario
sceptre
schéma
science
scinder
score
scrutin
sculpter
séance
sécable
sécher
secouer
sécréter
sédatif
séduire
seigneur
séjour
sélectif
semaine
sembler
semence
séminal
sénateur
sensible
sentence
séparer
séquence
serein
sergent
sérieux
serrure
sérum
service
sésame
sévir
sevrage
sextuple
sidéral
siècle
siéger
siffler
sigle
signal
silence
silicium
simple
sincère
sinistre
siphon
sirop
sismique
situer
skier
social
socle
sodium
soigneux
soldat
soleil
solitude
soluble
sombre
sommeil
somnoler
sonde
songeur
sonnette
sonore
sorcier
sortir
sosie
sottise
soucieux
soudure
souffle
soulever
soupape
source
soutirer
souvenir
spacieux
spatial
spécial
sphère
spiral
stable
station
sternum
stimulus
stipuler
strict
studieux
stupeur
styliste
sublime
substrat
subtil
subvenir
succès
sucre
suffixe
suggérer
suiveur
sulfate
superbe
supplier
surface
suricate
surmener
surprise
sursaut
survie
suspect
syllabe
symbole
symétrie
synapse
syntaxe
système
tabac
tablier
tactile
tailler
talent
talisman
talonner
tambour
tamiser
tangible
tapis
taquiner
tarder
tarif
tartine
tasse
tatami
tatouage
taupe
taureau
taxer
témoin
temporel
tenaille
tendre
teneur
tenir
tension
terminer
terne
terrible
tétine
texte
thème
théorie
thérapie
thorax
tibia
tiède
timide
tirelire
tiroir
tissu
titane
titre
tituber
toboggan
tolérant
tomate
tonique
tonneau
toponyme
torche
tordre
tornade
torpille
torrent
torse
tortue
totem
toucher
tournage
tousser
toxine
traction
trafic
tragique
trahir
train
trancher
travail
trèfle
tremper
trésor
treuil
triage
tribunal
tricoter
trilogie
triomphe
tripler
triturer
trivial
trombone
tronc
tropical
troupeau
tuile
tulipe
tumulte
tunnel
turbine
tuteur
tutoyer
tuyau
tympan
typhon
typique
tyran
ubuesque
ultime
ultrason
unanime
unifier
union
unique
unitaire
univers
uranium
urbain
urticant
usage
usine
usuel
usure
utile
utopie
vacarme
vaccin
vagabond
vague
vaillant
vaincre
vaisseau
valable
valise
vallon
valve
vampire
vanille
vapeur
varier
vaseux
vassal
vaste
vecteur
vedette
végétal
véhicule
veinard
véloce
vendredi
vénérer
venger
venimeux
ventouse
verdure
vérin
vernir
verrou
verser
vertu
veston
vétéran
vétuste
vexant
vexer
viaduc
viande
victoire
vidange
vidéo
vignette
vigueur
vilain
village
vinaigre
violon
vipère
virement
virtuose
virus
visage
viseur
vision
visqueux
visuel
vital
vitesse
viticole
vitrine
vivace
vivipare
vocation
voguer
voile
voisin
voiture
volaille
volcan
voltiger
volume
vorace
vortex
voter
vouloir
voyage
voyelle
wagon
xénon
yacht
zèbre
zénith
zeste
zoologie
================================================
FILE: bip-0039/italian.txt
================================================
abaco
abbaglio
abbinato
abete
abisso
abolire
abrasivo
abrogato
accadere
accenno
accusato
acetone
achille
acido
acqua
acre
acrilico
acrobata
acuto
adagio
addebito
addome
adeguato
aderire
adipe
adottare
adulare
affabile
affetto
affisso
affranto
aforisma
afoso
africano
agave
agente
agevole
aggancio
agire
agitare
agonismo
agricolo
agrumeto
aguzzo
alabarda
alato
albatro
alberato
albo
albume
alce
alcolico
alettone
alfa
algebra
aliante
alibi
alimento
allagato
allegro
allievo
allodola
allusivo
almeno
alogeno
alpaca
alpestre
altalena
alterno
alticcio
altrove
alunno
alveolo
alzare
amalgama
amanita
amarena
ambito
ambrato
ameba
america
ametista
amico
ammasso
ammenda
ammirare
ammonito
amore
ampio
ampliare
amuleto
anacardo
anagrafe
analista
anarchia
anatra
anca
ancella
ancora
andare
andrea
anello
angelo
angolare
angusto
anima
annegare
annidato
anno
annuncio
anonimo
anticipo
anzi
apatico
apertura
apode
apparire
appetito
appoggio
approdo
appunto
aprile
arabica
arachide
aragosta
araldica
arancio
aratura
arazzo
arbitro
archivio
ardito
arenile
argento
argine
arguto
aria
armonia
arnese
arredato
arringa
arrosto
arsenico
arso
artefice
arzillo
asciutto
ascolto
asepsi
asettico
asfalto
asino
asola
aspirato
aspro
assaggio
asse
assoluto
assurdo
asta
astenuto
astice
astratto
atavico
ateismo
atomico
atono
attesa
attivare
attorno
attrito
attuale
ausilio
austria
autista
autonomo
autunno
avanzato
avere
avvenire
avviso
avvolgere
azione
azoto
azzimo
azzurro
babele
baccano
bacino
baco
badessa
badilata
bagnato
baita
balcone
baldo
balena
ballata
balzano
bambino
bandire
baraonda
barbaro
barca
baritono
barlume
barocco
basilico
basso
batosta
battuto
baule
bava
bavosa
becco
beffa
belgio
belva
benda
benevole
benigno
benzina
bere
berlina
beta
bibita
bici
bidone
bifido
biga
bilancia
bimbo
binocolo
biologo
bipede
bipolare
birbante
birra
biscotto
bisesto
bisnonno
bisonte
bisturi
bizzarro
blando
blatta
bollito
bonifico
bordo
bosco
botanico
bottino
bozzolo
braccio
bradipo
brama
branca
bravura
bretella
brevetto
brezza
briglia
brillante
brindare
broccolo
brodo
bronzina
brullo
bruno
bubbone
buca
budino
buffone
buio
bulbo
buono
burlone
burrasca
bussola
busta
cadetto
caduco
calamaro
calcolo
calesse
calibro
calmo
caloria
cambusa
camerata
camicia
cammino
camola
campale
canapa
candela
cane
canino
canotto
cantina
capace
capello
capitolo
capogiro
cappero
capra
capsula
carapace
carcassa
cardo
carisma
carovana
carretto
cartolina
casaccio
cascata
caserma
caso
cassone
castello
casuale
catasta
catena
catrame
cauto
cavillo
cedibile
cedrata
cefalo
celebre
cellulare
cena
cenone
centesimo
ceramica
cercare
certo
cerume
cervello
cesoia
cespo
ceto
chela
chiaro
chicca
chiedere
chimera
china
chirurgo
chitarra
ciao
ciclismo
cifrare
cigno
cilindro
ciottolo
circa
cirrosi
citrico
cittadino
ciuffo
civetta
civile
classico
clinica
cloro
cocco
codardo
codice
coerente
cognome
collare
colmato
colore
colposo
coltivato
colza
coma
cometa
commando
comodo
computer
comune
conciso
condurre
conferma
congelare
coniuge
connesso
conoscere
consumo
continuo
convegno
coperto
copione
coppia
copricapo
corazza
cordata
coricato
cornice
corolla
corpo
corredo
corsia
cortese
cosmico
costante
cottura
covato
cratere
cravatta
creato
credere
cremoso
crescita
creta
criceto
crinale
crisi
critico
croce
cronaca
crostata
cruciale
crusca
cucire
cuculo
cugino
cullato
cupola
curatore
cursore
curvo
cuscino
custode
dado
daino
dalmata
damerino
daniela
dannoso
danzare
datato
davanti
davvero
debutto
decennio
deciso
declino
decollo
decreto
dedicato
definito
deforme
degno
delegare
delfino
delirio
delta
demenza
denotato
dentro
deposito
derapata
derivare
deroga
descritto
deserto
desiderio
desumere
detersivo
devoto
diametro
dicembre
diedro
difeso
diffuso
digerire
digitale
diluvio
dinamico
dinnanzi
dipinto
diploma
dipolo
diradare
dire
dirotto
dirupo
disagio
discreto
disfare
disgelo
disposto
distanza
disumano
dito
divano
divelto
dividere
divorato
doblone
docente
doganale
dogma
dolce
domato
domenica
dominare
dondolo
dono
dormire
dote
dottore
dovuto
dozzina
drago
druido
dubbio
dubitare
ducale
duna
duomo
duplice
duraturo
ebano
eccesso
ecco
eclissi
economia
edera
edicola
edile
editoria
educare
egemonia
egli
egoismo
egregio
elaborato
elargire
elegante
elencato
eletto
elevare
elfico
elica
elmo
elsa
eluso
emanato
emblema
emesso
emiro
emotivo
emozione
empirico
emulo
endemico
enduro
energia
enfasi
enoteca
entrare
enzima
epatite
epilogo
episodio
epocale
eppure
equatore
erario
erba
erboso
erede
eremita
erigere
ermetico
eroe
erosivo
errante
esagono
esame
esanime
esaudire
esca
esempio
esercito
esibito
esigente
esistere
esito
esofago
esortato
esoso
espanso
espresso
essenza
esso
esteso
estimare
estonia
estroso
esultare
etilico
etnico
etrusco
etto
euclideo
europa
evaso
evidenza
evitato
evoluto
evviva
fabbrica
faccenda
fachiro
falco
famiglia
fanale
fanfara
fango
fantasma
fare
farfalla
farinoso
farmaco
fascia
fastoso
fasullo
faticare
fato
favoloso
febbre
fecola
fede
fegato
felpa
feltro
femmina
fendere
fenomeno
fermento
ferro
fertile
fessura
festivo
fetta
feudo
fiaba
fiducia
fifa
figurato
filo
finanza
finestra
finire
fiore
fiscale
fisico
fiume
flacone
flamenco
flebo
flemma
florido
fluente
fluoro
fobico
focaccia
focoso
foderato
foglio
folata
folclore
folgore
fondente
fonetico
fonia
fontana
forbito
forchetta
foresta
formica
fornaio
foro
fortezza
forzare
fosfato
fosso
fracasso
frana
frassino
fratello
freccetta
frenata
fresco
frigo
frollino
fronde
frugale
frutta
fucilata
fucsia
fuggente
fulmine
fulvo
fumante
fumetto
fumoso
fune
funzione
fuoco
furbo
furgone
furore
fuso
futile
gabbiano
gaffe
galateo
gallina
galoppo
gambero
gamma
garanzia
garbo
garofano
garzone
gasdotto
gasolio
gastrico
gatto
gaudio
gazebo
gazzella
geco
gelatina
gelso
gemello
gemmato
gene
genitore
gennaio
genotipo
gergo
ghepardo
ghiaccio
ghisa
giallo
gilda
ginepro
giocare
gioiello
giorno
giove
girato
girone
gittata
giudizio
giurato
giusto
globulo
glutine
gnomo
gobba
golf
gomito
gommone
gonfio
gonna
governo
gracile
grado
grafico
grammo
grande
grattare
gravoso
grazia
greca
gregge
grifone
grigio
grinza
grotta
gruppo
guadagno
guaio
guanto
guardare
gufo
guidare
ibernato
icona
identico
idillio
idolo
idra
idrico
idrogeno
igiene
ignaro
ignorato
ilare
illeso
illogico
illudere
imballo
imbevuto
imbocco
imbuto
immane
immerso
immolato
impacco
impeto
impiego
importo
impronta
inalare
inarcare
inattivo
incanto
incendio
inchino
incisivo
incluso
incontro
incrocio
incubo
indagine
india
indole
inedito
infatti
infilare
inflitto
ingaggio
ingegno
inglese
ingordo
ingrosso
innesco
inodore
inoltrare
inondato
insano
insetto
insieme
insonnia
insulina
intasato
intero
intonaco
intuito
inumidire
invalido
invece
invito
iperbole
ipnotico
ipotesi
ippica
iride
irlanda
ironico
irrigato
irrorare
isolato
isotopo
isterico
istituto
istrice
italia
iterare
labbro
labirinto
lacca
lacerato
lacrima
lacuna
laddove
lago
lampo
lancetta
lanterna
lardoso
larga
laringe
lastra
latenza
latino
lattuga
lavagna
lavoro
legale
leggero
lembo
lentezza
lenza
leone
lepre
lesivo
lessato
lesto
letterale
leva
levigato
libero
lido
lievito
lilla
limatura
limitare
limpido
lineare
lingua
liquido
lira
lirica
lisca
lite
litigio
livrea
locanda
lode
logica
lombare
londra
longevo
loquace
lorenzo
loto
lotteria
luce
lucidato
lumaca
luminoso
lungo
lupo
luppolo
lusinga
lusso
lutto
macabro
macchina
macero
macinato
madama
magico
maglia
magnete
magro
maiolica
malafede
malgrado
malinteso
malsano
malto
malumore
mana
mancia
mandorla
mangiare
manifesto
mannaro
manovra
mansarda
mantide
manubrio
mappa
maratona
marcire
maretta
marmo
marsupio
maschera
massaia
mastino
materasso
matricola
mattone
maturo
mazurca
meandro
meccanico
mecenate
medesimo
meditare
mega
melassa
melis
melodia
meninge
meno
mensola
mercurio
merenda
merlo
meschino
mese
messere
mestolo
metallo
metodo
mettere
miagolare
mica
micelio
michele
microbo
midollo
miele
migliore
milano
milite
mimosa
minerale
mini
minore
mirino
mirtillo
miscela
missiva
misto
misurare
mitezza
mitigare
mitra
mittente
mnemonico
modello
modifica
modulo
mogano
mogio
mole
molosso
monastero
monco
mondina
monetario
monile
monotono
monsone
montato
monviso
mora
mordere
morsicato
mostro
motivato
motosega
motto
movenza
movimento
mozzo
mucca
mucosa
muffa
mughetto
mugnaio
mulatto
mulinello
multiplo
mummia
munto
muovere
murale
musa
muscolo
musica
mutevole
muto
nababbo
nafta
nanometro
narciso
narice
narrato
nascere
nastrare
naturale
nautica
naviglio
nebulosa
necrosi
negativo
negozio
nemmeno
neofita
neretto
nervo
nessuno
nettuno
neutrale
neve
nevrotico
nicchia
ninfa
nitido
nobile
nocivo
nodo
nome
nomina
nordico
normale
norvegese
nostrano
notare
notizia
notturno
novella
nucleo
nulla
numero
nuovo
nutrire
nuvola
nuziale
oasi
obbedire
obbligo
obelisco
oblio
obolo
obsoleto
occasione
occhio
occidente
occorrere
occultare
ocra
oculato
odierno
odorare
offerta
offrire
offuscato
oggetto
oggi
ognuno
olandese
olfatto
oliato
oliva
ologramma
oltre
omaggio
ombelico
ombra
omega
omissione
ondoso
onere
onice
onnivoro
onorevole
onta
operato
opinione
opposto
oracolo
orafo
ordine
orecchino
orefice
orfano
organico
origine
orizzonte
orma
ormeggio
ornativo
orologio
orrendo
orribile
ortensia
ortica
orzata
orzo
osare
oscurare
osmosi
ospedale
ospite
ossa
ossidare
ostacolo
oste
otite
otre
ottagono
ottimo
ottobre
ovale
ovest
ovino
oviparo
ovocito
ovunque
ovviare
ozio
pacchetto
pace
pacifico
padella
padrone
paese
paga
pagina
palazzina
palesare
pallido
palo
palude
pandoro
pannello
paolo
paonazzo
paprica
parabola
parcella
parere
pargolo
pari
parlato
parola
partire
parvenza
parziale
passivo
pasticca
patacca
patologia
pattume
pavone
peccato
pedalare
pedonale
peggio
peloso
penare
pendice
penisola
pennuto
penombra
pensare
pentola
pepe
pepita
perbene
percorso
perdonato
perforare
pergamena
periodo
permesso
perno
perplesso
persuaso
pertugio
pervaso
pesatore
pesista
peso
pestifero
petalo
pettine
petulante
pezzo
piacere
pianta
piattino
piccino
picozza
piega
pietra
piffero
pigiama
pigolio
pigro
pila
pilifero
pillola
pilota
pimpante
pineta
pinna
pinolo
pioggia
piombo
piramide
piretico
pirite
pirolisi
pitone
pizzico
placebo
planare
plasma
platano
plenario
pochezza
poderoso
podismo
poesia
poggiare
polenta
poligono
pollice
polmonite
polpetta
polso
poltrona
polvere
pomice
pomodoro
ponte
popoloso
porfido
poroso
porpora
porre
portata
posa
positivo
possesso
postulato
potassio
potere
pranzo
prassi
pratica
precluso
predica
prefisso
pregiato
prelievo
premere
prenotare
preparato
presenza
pretesto
prevalso
prima
principe
privato
problema
procura
produrre
profumo
progetto
prolunga
promessa
pronome
proposta
proroga
proteso
prova
prudente
prugna
prurito
psiche
pubblico
pudica
pugilato
pugno
pulce
pulito
pulsante
puntare
pupazzo
pupilla
puro
quadro
qualcosa
quasi
querela
quota
raccolto
raddoppio
radicale
radunato
raffica
ragazzo
ragione
ragno
ramarro
ramingo
ramo
randagio
rantolare
rapato
rapina
rappreso
rasatura
raschiato
rasente
rassegna
rastrello
rata
ravveduto
reale
recepire
recinto
recluta
recondito
recupero
reddito
redimere
regalato
registro
regola
regresso
relazione
remare
remoto
renna
replica
reprimere
reputare
resa
residente
responso
restauro
rete
retina
retorica
rettifica
revocato
riassunto
ribadire
ribelle
ribrezzo
ricarica
ricco
ricevere
riciclato
ricordo
ricreduto
ridicolo
ridurre
rifasare
riflesso
riforma
rifugio
rigare
rigettato
righello
rilassato
rilevato
rimanere
rimbalzo
rimedio
rimorchio
rinascita
rincaro
rinforzo
rinnovo
rinomato
rinsavito
rintocco
rinuncia
rinvenire
riparato
ripetuto
ripieno
riportare
ripresa
ripulire
risata
rischio
riserva
risibile
riso
rispetto
ristoro
risultato
risvolto
ritardo
ritegno
ritmico
ritrovo
riunione
riva
riverso
rivincita
rivolto
rizoma
roba
robotico
robusto
roccia
roco
rodaggio
rodere
roditore
rogito
rollio
romantico
rompere
ronzio
rosolare
rospo
rotante
rotondo
rotula
rovescio
rubizzo
rubrica
ruga
rullino
rumine
rumoroso
ruolo
rupe
russare
rustico
sabato
sabbiare
sabotato
sagoma
salasso
saldatura
salgemma
salivare
salmone
salone
saltare
saluto
salvo
sapere
sapido
saporito
saraceno
sarcasmo
sarto
sassoso
satellite
satira
satollo
saturno
savana
savio
saziato
sbadiglio
sbalzo
sbancato
sbarra
sbattere
sbavare
sbendare
sbirciare
sbloccato
sbocciato
sbrinare
sbruffone
sbuffare
scabroso
scadenza
scala
scambiare
scandalo
scapola
scarso
scatenare
scavato
scelto
scenico
scettro
scheda
schiena
sciarpa
scienza
scindere
scippo
sciroppo
scivolo
sclerare
scodella
scolpito
scomparto
sconforto
scoprire
scorta
scossone
scozzese
scriba
scrollare
scrutinio
scuderia
scultore
scuola
scuro
scusare
sdebitare
sdoganare
seccatura
secondo
sedano
seggiola
segnalato
segregato
seguito
selciato
selettivo
sella
selvaggio
semaforo
sembrare
seme
seminato
sempre
senso
sentire
sepolto
sequenza
serata
serbato
sereno
serio
serpente
serraglio
servire
sestina
setola
settimana
sfacelo
sfaldare
sfamato
sfarzoso
sfaticato
sfera
sfida
sfilato
sfinge
sfocato
sfoderare
sfogo
sfoltire
sforzato
sfratto
sfruttato
sfuggito
sfumare
sfuso
sgabello
sgarbato
sgonfiare
sgorbio
sgrassato
sguardo
sibilo
siccome
sierra
sigla
signore
silenzio
sillaba
simbolo
simpatico
simulato
sinfonia
singolo
sinistro
sino
sintesi
sinusoide
sipario
sisma
sistole
situato
slitta
slogatura
sloveno
smarrito
smemorato
smentito
smeraldo
smilzo
smontare
smottato
smussato
snellire
snervato
snodo
sobbalzo
sobrio
soccorso
sociale
sodale
soffitto
sogno
soldato
solenne
solido
sollazzo
solo
solubile
solvente
somatico
somma
sonda
sonetto
sonnifero
sopire
soppeso
sopra
sorgere
sorpasso
sorriso
sorso
sorteggio
sorvolato
sospiro
sosta
sottile
spada
spalla
spargere
spatola
spavento
spazzola
specie
spedire
spegnere
spelatura
speranza
spessore
spettrale
spezzato
spia
spigoloso
spillato
spinoso
spirale
splendido
sportivo
sposo
spranga
sprecare
spronato
spruzzo
spuntino
squillo
sradicare
srotolato
stabile
stacco
staffa
stagnare
stampato
stantio
starnuto
stasera
statuto
stelo
steppa
sterzo
stiletto
stima
stirpe
stivale
stizzoso
stonato
storico
strappo
stregato
stridulo
strozzare
strutto
stuccare
stufo
stupendo
subentro
succoso
sudore
suggerito
sugo
sultano
suonare
superbo
supporto
surgelato
surrogato
sussurro
sutura
svagare
svedese
sveglio
svelare
svenuto
svezia
sviluppo
svista
svizzera
svolta
svuotare
tabacco
tabulato
tacciare
taciturno
tale
talismano
tampone
tannino
tara
tardivo
targato
tariffa
tarpare
tartaruga
tasto
tattico
taverna
tavolata
tazza
teca
tecnico
telefono
temerario
tempo
temuto
tendone
tenero
tensione
tentacolo
teorema
terme
terrazzo
terzetto
tesi
tesserato
testato
tetro
tettoia
tifare
tigella
timbro
tinto
tipico
tipografo
tiraggio
tiro
titanio
titolo
titubante
tizio
tizzone
toccare
tollerare
tolto
tombola
tomo
tonfo
tonsilla
topazio
topologia
toppa
torba
tornare
torrone
tortora
toscano
tossire
tostatura
totano
trabocco
trachea
trafila
tragedia
tralcio
tramonto
transito
trapano
trarre
trasloco
trattato
trave
treccia
tremolio
trespolo
tributo
tricheco
trifoglio
trillo
trincea
trio
tristezza
triturato
trivella
tromba
trono
troppo
trottola
trovare
truccato
tubatura
tuffato
tulipano
tumulto
tunisia
turbare
turchino
tuta
tutela
ubicato
uccello
uccisore
udire
uditivo
uffa
ufficio
uguale
ulisse
ultimato
umano
umile
umorismo
uncinetto
ungere
ungherese
unicorno
unificato
unisono
unitario
unte
uovo
upupa
uragano
urgenza
urlo
usanza
usato
uscito
usignolo
usuraio
utensile
utilizzo
utopia
vacante
vaccinato
vagabondo
vagliato
valanga
valgo
valico
valletta
valoroso
valutare
valvola
vampata
vangare
vanitoso
vano
vantaggio
vanvera
vapore
varano
varcato
variante
vasca
vedetta
vedova
veduto
vegetale
veicolo
velcro
velina
velluto
veloce
venato
vendemmia
vento
verace
verbale
vergogna
verifica
vero
verruca
verticale
vescica
vessillo
vestale
veterano
vetrina
vetusto
viandante
vibrante
vicenda
vichingo
vicinanza
vidimare
vigilia
vigneto
vigore
vile
villano
vimini
vincitore
viola
vipera
virgola
virologo
virulento
viscoso
visione
vispo
vissuto
visura
vita
vitello
vittima
vivanda
vivido
viziare
voce
voga
volatile
volere
volpe
voragine
vulcano
zampogna
zanna
zappato
zattera
zavorra
zefiro
zelante
zelo
zenzero
zerbino
zibetto
zinco
zircone
zitto
zolla
zotico
zucchero
zufolo
zulu
zuppa
================================================
FILE: bip-0039/japanese.txt
================================================
あいこくしん
あいさつ
あいだ
あおぞら
あかちゃん
あきる
あけがた
あける
あこがれる
あさい
あさひ
あしあと
あじわう
あずかる
あずき
あそぶ
あたえる
あたためる
あたりまえ
あたる
あつい
あつかう
あっしゅく
あつまり
あつめる
あてな
あてはまる
あひる
あぶら
あぶる
あふれる
あまい
あまど
あまやかす
あまり
あみもの
あめりか
あやまる
あゆむ
あらいぐま
あらし
あらすじ
あらためる
あらゆる
あらわす
ありがとう
あわせる
あわてる
あんい
あんがい
あんこ
あんぜん
あんてい
あんない
あんまり
いいだす
いおん
いがい
いがく
いきおい
いきなり
いきもの
いきる
いくじ
いくぶん
いけばな
いけん
いこう
いこく
いこつ
いさましい
いさん
いしき
いじゅう
いじょう
いじわる
いずみ
いずれ
いせい
いせえび
いせかい
いせき
いぜん
いそうろう
いそがしい
いだい
いだく
いたずら
いたみ
いたりあ
いちおう
いちじ
いちど
いちば
いちぶ
いちりゅう
いつか
いっしゅん
いっせい
いっそう
いったん
いっち
いってい
いっぽう
いてざ
いてん
いどう
いとこ
いない
いなか
いねむり
いのち
いのる
いはつ
いばる
いはん
いびき
いひん
いふく
いへん
いほう
いみん
いもうと
いもたれ
いもり
いやがる
いやす
いよかん
いよく
いらい
いらすと
いりぐち
いりょう
いれい
いれもの
いれる
いろえんぴつ
いわい
いわう
いわかん
いわば
いわゆる
いんげんまめ
いんさつ
いんしょう
いんよう
うえき
うえる
うおざ
うがい
うかぶ
うかべる
うきわ
うくらいな
うくれれ
うけたまわる
うけつけ
うけとる
うけもつ
うける
うごかす
うごく
うこん
うさぎ
うしなう
うしろがみ
うすい
うすぎ
うすぐらい
うすめる
うせつ
うちあわせ
うちがわ
うちき
うちゅう
うっかり
うつくしい
うったえる
うつる
うどん
うなぎ
うなじ
うなずく
うなる
うねる
うのう
うぶげ
うぶごえ
うまれる
うめる
うもう
うやまう
うよく
うらがえす
うらぐち
うらない
うりあげ
うりきれ
うるさい
うれしい
うれゆき
うれる
うろこ
うわき
うわさ
うんこう
うんちん
うんてん
うんどう
えいえん
えいが
えいきょう
えいご
えいせい
えいぶん
えいよう
えいわ
えおり
えがお
えがく
えきたい
えくせる
えしゃく
えすて
えつらん
えのぐ
えほうまき
えほん
えまき
えもじ
えもの
えらい
えらぶ
えりあ
えんえん
えんかい
えんぎ
えんげき
えんしゅう
えんぜつ
えんそく
えんちょう
えんとつ
おいかける
おいこす
おいしい
おいつく
おうえん
おうさま
おうじ
おうせつ
おうたい
おうふく
おうべい
おうよう
おえる
おおい
おおう
おおどおり
おおや
おおよそ
おかえり
おかず
おがむ
おかわり
おぎなう
おきる
おくさま
おくじょう
おくりがな
おくる
おくれる
おこす
おこなう
おこる
おさえる
おさない
おさめる
おしいれ
おしえる
おじぎ
おじさん
おしゃれ
おそらく
おそわる
おたがい
おたく
おだやか
おちつく
おっと
おつり
おでかけ
おとしもの
おとなしい
おどり
おどろかす
おばさん
おまいり
おめでとう
おもいで
おもう
おもたい
おもちゃ
おやつ
おやゆび
およぼす
おらんだ
おろす
おんがく
おんけい
おんしゃ
おんせん
おんだん
おんちゅう
おんどけい
かあつ
かいが
がいき
がいけん
がいこう
かいさつ
かいしゃ
かいすいよく
かいぜん
かいぞうど
かいつう
かいてん
かいとう
かいふく
がいへき
かいほう
かいよう
がいらい
かいわ
かえる
かおり
かかえる
かがく
かがし
かがみ
かくご
かくとく
かざる
がぞう
かたい
かたち
がちょう
がっきゅう
がっこう
がっさん
がっしょう
かなざわし
かのう
がはく
かぶか
かほう
かほご
かまう
かまぼこ
かめれおん
かゆい
かようび
からい
かるい
かろう
かわく
かわら
がんか
かんけい
かんこう
かんしゃ
かんそう
かんたん
かんち
がんばる
きあい
きあつ
きいろ
ぎいん
きうい
きうん
きえる
きおう
きおく
きおち
きおん
きかい
きかく
きかんしゃ
ききて
きくばり
きくらげ
きけんせい
きこう
きこえる
きこく
きさい
きさく
きさま
きさらぎ
ぎじかがく
ぎしき
ぎじたいけん
ぎじにってい
ぎじゅつしゃ
きすう
きせい
きせき
きせつ
きそう
きぞく
きぞん
きたえる
きちょう
きつえん
ぎっちり
きつつき
きつね
きてい
きどう
きどく
きない
きなが
きなこ
きぬごし
きねん
きのう
きのした
きはく
きびしい
きひん
きふく
きぶん
きぼう
きほん
きまる
きみつ
きむずかしい
きめる
きもだめし
きもち
きもの
きゃく
きやく
ぎゅうにく
きよう
きょうりゅう
きらい
きらく
きりん
きれい
きれつ
きろく
ぎろん
きわめる
ぎんいろ
きんかくじ
きんじょ
きんようび
ぐあい
くいず
くうかん
くうき
くうぐん
くうこう
ぐうせい
くうそう
ぐうたら
くうふく
くうぼ
くかん
くきょう
くげん
ぐこう
くさい
くさき
くさばな
くさる
くしゃみ
くしょう
くすのき
くすりゆび
くせげ
くせん
ぐたいてき
くださる
くたびれる
くちこみ
くちさき
くつした
ぐっすり
くつろぐ
くとうてん
くどく
くなん
くねくね
くのう
くふう
くみあわせ
くみたてる
くめる
くやくしょ
くらす
くらべる
くるま
くれる
くろう
くわしい
ぐんかん
ぐんしょく
ぐんたい
ぐんて
けあな
けいかく
けいけん
けいこ
けいさつ
げいじゅつ
けいたい
げいのうじん
けいれき
けいろ
けおとす
けおりもの
げきか
げきげん
げきだん
げきちん
げきとつ
げきは
げきやく
げこう
げこくじょう
げざい
けさき
げざん
けしき
けしごむ
けしょう
げすと
けたば
けちゃっぷ
けちらす
けつあつ
けつい
けつえき
けっこん
けつじょ
けっせき
けってい
けつまつ
げつようび
げつれい
けつろん
げどく
けとばす
けとる
けなげ
けなす
けなみ
けぬき
げねつ
けねん
けはい
げひん
けぶかい
げぼく
けまり
けみかる
けむし
けむり
けもの
けらい
けろけろ
けわしい
けんい
けんえつ
けんお
けんか
げんき
けんげん
けんこう
けんさく
けんしゅう
けんすう
げんそう
けんちく
けんてい
けんとう
けんない
けんにん
げんぶつ
けんま
けんみん
けんめい
けんらん
けんり
こあくま
こいぬ
こいびと
ごうい
こうえん
こうおん
こうかん
ごうきゅう
ごうけい
こうこう
こうさい
こうじ
こうすい
ごうせい
こうそく
こうたい
こうちゃ
こうつう
こうてい
こうどう
こうない
こうはい
ごうほう
ごうまん
こうもく
こうりつ
こえる
こおり
ごかい
ごがつ
ごかん
こくご
こくさい
こくとう
こくない
こくはく
こぐま
こけい
こける
ここのか
こころ
こさめ
こしつ
こすう
こせい
こせき
こぜん
こそだて
こたい
こたえる
こたつ
こちょう
こっか
こつこつ
こつばん
こつぶ
こてい
こてん
ことがら
ことし
ことば
ことり
こなごな
こねこね
このまま
このみ
このよ
ごはん
こひつじ
こふう
こふん
こぼれる
ごまあぶら
こまかい
ごますり
こまつな
こまる
こむぎこ
こもじ
こもち
こもの
こもん
こやく
こやま
こゆう
こゆび
こよい
こよう
こりる
これくしょん
ころっけ
こわもて
こわれる
こんいん
こんかい
こんき
こんしゅう
こんすい
こんだて
こんとん
こんなん
こんびに
こんぽん
こんまけ
こんや
こんれい
こんわく
ざいえき
さいかい
さいきん
ざいげん
ざいこ
さいしょ
さいせい
ざいたく
ざいちゅう
さいてき
ざいりょう
さうな
さかいし
さがす
さかな
さかみち
さがる
さぎょう
さくし
さくひん
さくら
さこく
さこつ
さずかる
ざせき
さたん
さつえい
ざつおん
ざっか
ざつがく
さっきょく
ざっし
さつじん
ざっそう
さつたば
さつまいも
さてい
さといも
さとう
さとおや
さとし
さとる
さのう
さばく
さびしい
さべつ
さほう
さほど
さます
さみしい
さみだれ
さむけ
さめる
さやえんどう
さゆう
さよう
さよく
さらだ
ざるそば
さわやか
さわる
さんいん
さんか
さんきゃく
さんこう
さんさい
ざんしょ
さんすう
さんせい
さんそ
さんち
さんま
さんみ
さんらん
しあい
しあげ
しあさって
しあわせ
しいく
しいん
しうち
しえい
しおけ
しかい
しかく
じかん
しごと
しすう
じだい
したうけ
したぎ
したて
したみ
しちょう
しちりん
しっかり
しつじ
しつもん
してい
してき
してつ
じてん
じどう
しなぎれ
しなもの
しなん
しねま
しねん
しのぐ
しのぶ
しはい
しばかり
しはつ
しはらい
しはん
しひょう
しふく
じぶん
しへい
しほう
しほん
しまう
しまる
しみん
しむける
じむしょ
しめい
しめる
しもん
しゃいん
しゃうん
しゃおん
じゃがいも
しやくしょ
しゃくほう
しゃけん
しゃこ
しゃざい
しゃしん
しゃせん
しゃそう
しゃたい
しゃちょう
しゃっきん
じゃま
しゃりん
しゃれい
じゆう
じゅうしょ
しゅくはく
じゅしん
しゅっせき
しゅみ
しゅらば
じゅんばん
しょうかい
しょくたく
しょっけん
しょどう
しょもつ
しらせる
しらべる
しんか
しんこう
じんじゃ
しんせいじ
しんちく
しんりん
すあげ
すあし
すあな
ずあん
すいえい
すいか
すいとう
ずいぶん
すいようび
すうがく
すうじつ
すうせん
すおどり
すきま
すくう
すくない
すける
すごい
すこし
ずさん
すずしい
すすむ
すすめる
すっかり
ずっしり
ずっと
すてき
すてる
すねる
すのこ
すはだ
すばらしい
ずひょう
ずぶぬれ
すぶり
すふれ
すべて
すべる
ずほう
すぼん
すまい
すめし
すもう
すやき
すらすら
するめ
すれちがう
すろっと
すわる
すんぜん
すんぽう
せあぶら
せいかつ
せいげん
せいじ
せいよう
せおう
せかいかん
せきにん
せきむ
せきゆ
せきらんうん
せけん
せこう
せすじ
せたい
せたけ
せっかく
せっきゃく
ぜっく
せっけん
せっこつ
せっさたくま
せつぞく
せつだん
せつでん
せっぱん
せつび
せつぶん
せつめい
せつりつ
せなか
せのび
せはば
せびろ
せぼね
せまい
せまる
せめる
せもたれ
せりふ
ぜんあく
せんい
せんえい
せんか
せんきょ
せんく
せんげん
ぜんご
せんさい
せんしゅ
せんすい
せんせい
せんぞ
せんたく
せんちょう
せんてい
せんとう
せんぬき
せんねん
せんぱい
ぜんぶ
ぜんぽう
せんむ
せんめんじょ
せんもん
せんやく
せんゆう
せんよう
ぜんら
ぜんりゃく
せんれい
せんろ
そあく
そいとげる
そいね
そうがんきょう
そうき
そうご
そうしん
そうだん
そうなん
そうび
そうめん
そうり
そえもの
そえん
そがい
そげき
そこう
そこそこ
そざい
そしな
そせい
そせん
そそぐ
そだてる
そつう
そつえん
そっかん
そつぎょう
そっけつ
そっこう
そっせん
そっと
そとがわ
そとづら
そなえる
そなた
そふぼ
そぼく
そぼろ
そまつ
そまる
そむく
そむりえ
そめる
そもそも
そよかぜ
そらまめ
そろう
そんかい
そんけい
そんざい
そんしつ
そんぞく
そんちょう
ぞんび
ぞんぶん
そんみん
たあい
たいいん
たいうん
たいえき
たいおう
だいがく
たいき
たいぐう
たいけん
たいこ
たいざい
だいじょうぶ
だいすき
たいせつ
たいそう
だいたい
たいちょう
たいてい
だいどころ
たいない
たいねつ
たいのう
たいはん
だいひょう
たいふう
たいへん
たいほ
たいまつばな
たいみんぐ
たいむ
たいめん
たいやき
たいよう
たいら
たいりょく
たいる
たいわん
たうえ
たえる
たおす
たおる
たおれる
たかい
たかね
たきび
たくさん
たこく
たこやき
たさい
たしざん
だじゃれ
たすける
たずさわる
たそがれ
たたかう
たたく
ただしい
たたみ
たちばな
だっかい
だっきゃく
だっこ
だっしゅつ
だったい
たてる
たとえる
たなばた
たにん
たぬき
たのしみ
たはつ
たぶん
たべる
たぼう
たまご
たまる
だむる
ためいき
ためす
ためる
たもつ
たやすい
たよる
たらす
たりきほんがん
たりょう
たりる
たると
たれる
たれんと
たろっと
たわむれる
だんあつ
たんい
たんおん
たんか
たんき
たんけん
たんご
たんさん
たんじょうび
だんせい
たんそく
たんたい
だんち
たんてい
たんとう
だんな
たんにん
だんねつ
たんのう
たんぴん
だんぼう
たんまつ
たんめい
だんれつ
だんろ
だんわ
ちあい
ちあん
ちいき
ちいさい
ちえん
ちかい
ちから
ちきゅう
ちきん
ちけいず
ちけん
ちこく
ちさい
ちしき
ちしりょう
ちせい
ちそう
ちたい
ちたん
ちちおや
ちつじょ
ちてき
ちてん
ちぬき
ちぬり
ちのう
ちひょう
ちへいせん
ちほう
ちまた
ちみつ
ちみどろ
ちめいど
ちゃんこなべ
ちゅうい
ちゆりょく
ちょうし
ちょさくけん
ちらし
ちらみ
ちりがみ
ちりょう
ちるど
ちわわ
ちんたい
ちんもく
ついか
ついたち
つうか
つうじょう
つうはん
つうわ
つかう
つかれる
つくね
つくる
つけね
つける
つごう
つたえる
つづく
つつじ
つつむ
つとめる
つながる
つなみ
つねづね
つのる
つぶす
つまらない
つまる
つみき
つめたい
つもり
つもる
つよい
つるぼ
つるみく
つわもの
つわり
てあし
てあて
てあみ
ていおん
ていか
ていき
ていけい
ていこく
ていさつ
ていし
ていせい
ていたい
ていど
ていねい
ていひょう
ていへん
ていぼう
てうち
ておくれ
てきとう
てくび
でこぼこ
てさぎょう
てさげ
てすり
てそう
てちがい
てちょう
てつがく
てつづき
でっぱ
てつぼう
てつや
でぬかえ
てぬき
てぬぐい
てのひら
てはい
てぶくろ
てふだ
てほどき
てほん
てまえ
てまきずし
てみじか
てみやげ
てらす
てれび
てわけ
てわたし
でんあつ
てんいん
てんかい
てんき
てんぐ
てんけん
てんごく
てんさい
てんし
てんすう
でんち
てんてき
てんとう
てんない
てんぷら
てんぼうだい
てんめつ
てんらんかい
でんりょく
でんわ
どあい
といれ
どうかん
とうきゅう
どうぐ
とうし
とうむぎ
とおい
とおか
とおく
とおす
とおる
とかい
とかす
ときおり
ときどき
とくい
とくしゅう
とくてん
とくに
とくべつ
とけい
とける
とこや
とさか
としょかん
とそう
とたん
とちゅう
とっきゅう
とっくん
とつぜん
とつにゅう
とどける
ととのえる
とない
となえる
となり
とのさま
とばす
どぶがわ
とほう
とまる
とめる
ともだち
ともる
どようび
とらえる
とんかつ
どんぶり
ないかく
ないこう
ないしょ
ないす
ないせん
ないそう
なおす
ながい
なくす
なげる
なこうど
なさけ
なたでここ
なっとう
なつやすみ
ななおし
なにごと
なにもの
なにわ
なのか
なふだ
なまいき
なまえ
なまみ
なみだ
なめらか
なめる
なやむ
ならう
ならび
ならぶ
なれる
なわとび
なわばり
にあう
にいがた
にうけ
におい
にかい
にがて
にきび
にくしみ
にくまん
にげる
にさんかたんそ
にしき
にせもの
にちじょう
にちようび
にっか
にっき
にっけい
にっこう
にっさん
にっしょく
にっすう
にっせき
にってい
になう
にほん
にまめ
にもつ
にやり
にゅういん
にりんしゃ
にわとり
にんい
にんか
にんき
にんげん
にんしき
にんずう
にんそう
にんたい
にんち
にんてい
にんにく
にんぷ
にんまり
にんむ
にんめい
にんよう
ぬいくぎ
ぬかす
ぬぐいとる
ぬぐう
ぬくもり
ぬすむ
ぬまえび
ぬめり
ぬらす
ぬんちゃく
ねあげ
ねいき
ねいる
ねいろ
ねぐせ
ねくたい
ねくら
ねこぜ
ねこむ
ねさげ
ねすごす
ねそべる
ねだん
ねつい
ねっしん
ねつぞう
ねったいぎょ
ねぶそく
ねふだ
ねぼう
ねほりはほり
ねまき
ねまわし
ねみみ
ねむい
ねむたい
ねもと
ねらう
ねわざ
ねんいり
ねんおし
ねんかん
ねんきん
ねんぐ
ねんざ
ねんし
ねんちゃく
ねんど
ねんぴ
ねんぶつ
ねんまつ
ねんりょう
ねんれい
のいず
のおづま
のがす
のきなみ
のこぎり
のこす
のこる
のせる
のぞく
のぞむ
のたまう
のちほど
のっく
のばす
のはら
のべる
のぼる
のみもの
のやま
のらいぬ
のらねこ
のりもの
のりゆき
のれん
のんき
ばあい
はあく
ばあさん
ばいか
ばいく
はいけん
はいご
はいしん
はいすい
はいせん
はいそう
はいち
ばいばい
はいれつ
はえる
はおる
はかい
ばかり
はかる
はくしゅ
はけん
はこぶ
はさみ
はさん
はしご
ばしょ
はしる
はせる
ぱそこん
はそん
はたん
はちみつ
はつおん
はっかく
はづき
はっきり
はっくつ
はっけん
はっこう
はっさん
はっしん
はったつ
はっちゅう
はってん
はっぴょう
はっぽう
はなす
はなび
はにかむ
はぶらし
はみがき
はむかう
はめつ
はやい
はやし
はらう
はろうぃん
はわい
はんい
はんえい
はんおん
はんかく
はんきょう
ばんぐみ
はんこ
はんしゃ
はんすう
はんだん
ぱんち
ぱんつ
はんてい
はんとし
はんのう
はんぱ
はんぶん
はんぺん
はんぼうき
はんめい
はんらん
はんろん
ひいき
ひうん
ひえる
ひかく
ひかり
ひかる
ひかん
ひくい
ひけつ
ひこうき
ひこく
ひさい
ひさしぶり
ひさん
びじゅつかん
ひしょ
ひそか
ひそむ
ひたむき
ひだり
ひたる
ひつぎ
ひっこし
ひっし
ひつじゅひん
ひっす
ひつぜん
ぴったり
ぴっちり
ひつよう
ひてい
ひとごみ
ひなまつり
ひなん
ひねる
ひはん
ひびく
ひひょう
ひほう
ひまわり
ひまん
ひみつ
ひめい
ひめじし
ひやけ
ひやす
ひよう
びょうき
ひらがな
ひらく
ひりつ
ひりょう
ひるま
ひるやすみ
ひれい
ひろい
ひろう
ひろき
ひろゆき
ひんかく
ひんけつ
ひんこん
ひんしゅ
ひんそう
ぴんち
ひんぱん
びんぼう
ふあん
ふいうち
ふうけい
ふうせん
ぷうたろう
ふうとう
ふうふ
ふえる
ふおん
ふかい
ふきん
ふくざつ
ふくぶくろ
ふこう
ふさい
ふしぎ
ふじみ
ふすま
ふせい
ふせぐ
ふそく
ぶたにく
ふたん
ふちょう
ふつう
ふつか
ふっかつ
ふっき
ふっこく
ぶどう
ふとる
ふとん
ふのう
ふはい
ふひょう
ふへん
ふまん
ふみん
ふめつ
ふめん
ふよう
ふりこ
ふりる
ふるい
ふんいき
ぶんがく
ぶんぐ
ふんしつ
ぶんせき
ふんそう
ぶんぽう
へいあん
へいおん
へいがい
へいき
へいげん
へいこう
へいさ
へいしゃ
へいせつ
へいそ
へいたく
へいてん
へいねつ
へいわ
へきが
へこむ
べにいろ
べにしょうが
へらす
へんかん
べんきょう
べんごし
へんさい
へんたい
べんり
ほあん
ほいく
ぼうぎょ
ほうこく
ほうそう
ほうほう
ほうもん
ほうりつ
ほえる
ほおん
ほかん
ほきょう
ぼきん
ほくろ
ほけつ
ほけん
ほこう
ほこる
ほしい
ほしつ
ほしゅ
ほしょう
ほせい
ほそい
ほそく
ほたて
ほたる
ぽちぶくろ
ほっきょく
ほっさ
ほったん
ほとんど
ほめる
ほんい
ほんき
ほんけ
ほんしつ
ほんやく
まいにち
まかい
まかせる
まがる
まける
まこと
まさつ
まじめ
ますく
まぜる
まつり
まとめ
まなぶ
まぬけ
まねく
まほう
まもる
まゆげ
まよう
まろやか
まわす
まわり
まわる
まんが
まんきつ
まんぞく
まんなか
みいら
みうち
みえる
みがく
みかた
みかん
みけん
みこん
みじかい
みすい
みすえる
みせる
みっか
みつかる
みつける
みてい
みとめる
みなと
みなみかさい
みねらる
みのう
みのがす
みほん
みもと
みやげ
みらい
みりょく
みわく
みんか
みんぞく
むいか
むえき
むえん
むかい
むかう
むかえ
むかし
むぎちゃ
むける
むげん
むさぼる
むしあつい
むしば
むじゅん
むしろ
むすう
むすこ
むすぶ
むすめ
むせる
むせん
むちゅう
むなしい
むのう
むやみ
むよう
むらさき
むりょう
むろん
めいあん
めいうん
めいえん
めいかく
めいきょく
めいさい
めいし
めいそう
めいぶつ
めいれい
めいわく
めぐまれる
めざす
めした
めずらしい
めだつ
めまい
めやす
めんきょ
めんせき
めんどう
もうしあげる
もうどうけん
もえる
もくし
もくてき
もくようび
もちろん
もどる
もらう
もんく
もんだい
やおや
やける
やさい
やさしい
やすい
やすたろう
やすみ
やせる
やそう
やたい
やちん
やっと
やっぱり
やぶる
やめる
ややこしい
やよい
やわらかい
ゆうき
ゆうびんきょく
ゆうべ
ゆうめい
ゆけつ
ゆしゅつ
ゆせん
ゆそう
ゆたか
ゆちゃく
ゆでる
ゆにゅう
ゆびわ
ゆらい
ゆれる
ようい
ようか
ようきゅう
ようじ
ようす
ようちえん
よかぜ
よかん
よきん
よくせい
よくぼう
よけい
よごれる
よさん
よしゅう
よそう
よそく
よっか
よてい
よどがわく
よねつ
よやく
よゆう
よろこぶ
よろしい
らいう
らくがき
らくご
らくさつ
らくだ
らしんばん
らせん
らぞく
らたい
らっか
られつ
りえき
りかい
りきさく
りきせつ
りくぐん
りくつ
りけん
りこう
りせい
りそう
りそく
りてん
りねん
りゆう
りゅうがく
りよう
りょうり
りょかん
りょくちゃ
りょこう
りりく
りれき
りろん
りんご
るいけい
るいさい
るいじ
るいせき
るすばん
るりがわら
れいかん
れいぎ
れいせい
れいぞうこ
れいとう
れいぼう
れきし
れきだい
れんあい
れんけい
れんこん
れんさい
れんしゅう
れんぞく
れんらく
ろうか
ろうご
ろうじん
ろうそく
ろくが
ろこつ
ろじうら
ろしゅつ
ろせん
ろてん
ろめん
ろれつ
ろんぎ
ろんぱ
ろんぶん
ろんり
わかす
わかめ
わかやま
わかれる
わしつ
わじまし
わすれもの
わらう
われる
================================================
FILE: bip-0039/korean.txt
================================================
가격
가끔
가난
가능
가득
가르침
가뭄
가방
가상
가슴
가운데
가을
가이드
가입
가장
가정
가족
가죽
각오
각자
간격
간부
간섭
간장
간접
간판
갈등
갈비
갈색
갈증
감각
감기
감소
감수성
감자
감정
갑자기
강남
강당
강도
강력히
강변
강북
강사
강수량
강아지
강원도
강의
강제
강조
같이
개구리
개나리
개방
개별
개선
개성
개인
객관적
거실
거액
거울
거짓
거품
걱정
건강
건물
건설
건조
건축
걸음
검사
검토
게시판
게임
겨울
견해
결과
결국
결론
결석
결승
결심
결정
결혼
경계
경고
경기
경력
경복궁
경비
경상도
경영
경우
경쟁
경제
경주
경찰
경치
경향
경험
계곡
계단
계란
계산
계속
계약
계절
계층
계획
고객
고구려
고궁
고급
고등학생
고무신
고민
고양이
고장
고전
고집
고춧가루
고통
고향
곡식
골목
골짜기
골프
공간
공개
공격
공군
공급
공기
공동
공무원
공부
공사
공식
공업
공연
공원
공장
공짜
공책
공통
공포
공항
공휴일
과목
과일
과장
과정
과학
관객
관계
관광
관념
관람
관련
관리
관습
관심
관점
관찰
광경
광고
광장
광주
괴로움
굉장히
교과서
교문
교복
교실
교양
교육
교장
교직
교통
교환
교훈
구경
구름
구멍
구별
구분
구석
구성
구속
구역
구입
구청
구체적
국가
국기
국내
국립
국물
국민
국수
국어
국왕
국적
국제
국회
군대
군사
군인
궁극적
권리
권위
권투
귀국
귀신
규정
규칙
균형
그날
그냥
그늘
그러나
그룹
그릇
그림
그제서야
그토록
극복
극히
근거
근교
근래
근로
근무
근본
근원
근육
근처
글씨
글자
금강산
금고
금년
금메달
금액
금연
금요일
금지
긍정적
기간
기관
기념
기능
기독교
기둥
기록
기름
기법
기본
기분
기쁨
기숙사
기술
기억
기업
기온
기운
기원
기적
기준
기침
기혼
기획
긴급
긴장
길이
김밥
김치
김포공항
깍두기
깜빡
깨달음
깨소금
껍질
꼭대기
꽃잎
나들이
나란히
나머지
나물
나침반
나흘
낙엽
난방
날개
날씨
날짜
남녀
남대문
남매
남산
남자
남편
남학생
낭비
낱말
내년
내용
내일
냄비
냄새
냇물
냉동
냉면
냉방
냉장고
넥타이
넷째
노동
노란색
노력
노인
녹음
녹차
녹화
논리
논문
논쟁
놀이
농구
농담
농민
농부
농업
농장
농촌
높이
눈동자
눈물
눈썹
뉴욕
느낌
늑대
능동적
능력
다방
다양성
다음
다이어트
다행
단계
단골
단독
단맛
단순
단어
단위
단점
단체
단추
단편
단풍
달걀
달러
달력
달리
닭고기
담당
담배
담요
담임
답변
답장
당근
당분간
당연히
당장
대규모
대낮
대단히
대답
대도시
대략
대량
대륙
대문
대부분
대신
대응
대장
대전
대접
대중
대책
대출
대충
대통령
대학
대한민국
대합실
대형
덩어리
데이트
도대체
도덕
도둑
도망
도서관
도심
도움
도입
도자기
도저히
도전
도중
도착
독감
독립
독서
독일
독창적
동화책
뒷모습
뒷산
딸아이
마누라
마늘
마당
마라톤
마련
마무리
마사지
마약
마요네즈
마을
마음
마이크
마중
마지막
마찬가지
마찰
마흔
막걸리
막내
막상
만남
만두
만세
만약
만일
만점
만족
만화
많이
말기
말씀
말투
맘대로
망원경
매년
매달
매력
매번
매스컴
매일
매장
맥주
먹이
먼저
먼지
멀리
메일
며느리
며칠
면담
멸치
명단
명령
명예
명의
명절
명칭
명함
모금
모니터
모델
모든
모범
모습
모양
모임
모조리
모집
모퉁이
목걸이
목록
목사
목소리
목숨
목적
목표
몰래
몸매
몸무게
몸살
몸속
몸짓
몸통
몹시
무관심
무궁화
무더위
무덤
무릎
무슨
무엇
무역
무용
무조건
무지개
무척
문구
문득
문법
문서
문제
문학
문화
물가
물건
물결
물고기
물론
물리학
물음
물질
물체
미국
미디어
미사일
미술
미역
미용실
미움
미인
미팅
미혼
민간
민족
민주
믿음
밀가루
밀리미터
밑바닥
바가지
바구니
바나나
바늘
바닥
바닷가
바람
바이러스
바탕
박물관
박사
박수
반대
반드시
반말
반발
반성
반응
반장
반죽
반지
반찬
받침
발가락
발걸음
발견
발달
발레
발목
발바닥
발생
발음
발자국
발전
발톱
발표
밤하늘
밥그릇
밥맛
밥상
밥솥
방금
방면
방문
방바닥
방법
방송
방식
방안
방울
방지
방학
방해
방향
배경
배꼽
배달
배드민턴
백두산
백색
백성
백인
백제
백화점
버릇
버섯
버튼
번개
번역
번지
번호
벌금
벌레
벌써
범위
범인
범죄
법률
법원
법적
법칙
베이징
벨트
변경
변동
변명
변신
변호사
변화
별도
별명
별일
병실
병아리
병원
보관
보너스
보라색
보람
보름
보상
보안
보자기
보장
보전
보존
보통
보편적
보험
복도
복사
복숭아
복습
볶음
본격적
본래
본부
본사
본성
본인
본질
볼펜
봉사
봉지
봉투
부근
부끄러움
부담
부동산
부문
부분
부산
부상
부엌
부인
부작용
부장
부정
부족
부지런히
부친
부탁
부품
부회장
북부
북한
분노
분량
분리
분명
분석
분야
분위기
분필
분홍색
불고기
불과
불교
불꽃
불만
불법
불빛
불안
불이익
불행
브랜드
비극
비난
비닐
비둘기
비디오
비로소
비만
비명
비밀
비바람
비빔밥
비상
비용
비율
비중
비타민
비판
빌딩
빗물
빗방울
빗줄기
빛깔
빨간색
빨래
빨리
사건
사계절
사나이
사냥
사람
사랑
사립
사모님
사물
사방
사상
사생활
사설
사슴
사실
사업
사용
사월
사장
사전
사진
사촌
사춘기
사탕
사투리
사흘
산길
산부인과
산업
산책
살림
살인
살짝
삼계탕
삼국
삼십
삼월
삼촌
상관
상금
상대
상류
상반기
상상
상식
상업
상인
상자
상점
상처
상추
상태
상표
상품
상황
새벽
색깔
색연필
생각
생명
생물
생방송
생산
생선
생신
생일
생활
서랍
서른
서명
서민
서비스
서양
서울
서적
서점
서쪽
서클
석사
석유
선거
선물
선배
선생
선수
선원
선장
선전
선택
선풍기
설거지
설날
설렁탕
설명
설문
설사
설악산
설치
설탕
섭씨
성공
성당
성명
성별
성인
성장
성적
성질
성함
세금
세미나
세상
세월
세종대왕
세탁
센터
센티미터
셋째
소규모
소극적
소금
소나기
소년
소득
소망
소문
소설
소속
소아과
소용
소원
소음
소중히
소지품
소질
소풍
소형
속담
속도
속옷
손가락
손길
손녀
손님
손등
손목
손뼉
손실
손질
손톱
손해
솔직히
솜씨
송아지
송이
송편
쇠고기
쇼핑
수건
수년
수단
수돗물
수동적
수면
수명
수박
수상
수석
수술
수시로
수업
수염
수영
수입
수준
수집
수출
수컷
수필
수학
수험생
수화기
숙녀
숙소
숙제
순간
순서
순수
순식간
순위
숟가락
술병
술집
숫자
스님
스물
스스로
스승
스웨터
스위치
스케이트
스튜디오
스트레스
스포츠
슬쩍
슬픔
습관
습기
승객
승리
승부
승용차
승진
시각
시간
시골
시금치
시나리오
시댁
시리즈
시멘트
시민
시부모
시선
시설
시스템
시아버지
시어머니
시월
시인
시일
시작
시장
시절
시점
시중
시즌
시집
시청
시합
시험
식구
식기
식당
식량
식료품
식물
식빵
식사
식생활
식초
식탁
식품
신고
신규
신념
신문
신발
신비
신사
신세
신용
신제품
신청
신체
신화
실감
실내
실력
실례
실망
실수
실습
실시
실장
실정
실질적
실천
실체
실컷
실태
실패
실험
실현
심리
심부름
심사
심장
심정
심판
쌍둥이
씨름
씨앗
아가씨
아나운서
아드님
아들
아쉬움
아스팔트
아시아
아울러
아저씨
아줌마
아직
아침
아파트
아프리카
아픔
아홉
아흔
악기
악몽
악수
안개
안경
안과
안내
안녕
안동
안방
안부
안주
알루미늄
알코올
암시
암컷
압력
앞날
앞문
애인
애정
액수
앨범
야간
야단
야옹
약간
약국
약속
약수
약점
약품
약혼녀
양념
양력
양말
양배추
양주
양파
어둠
어려움
어른
어젯밤
어쨌든
어쩌다가
어쩐지
언니
언덕
언론
언어
얼굴
얼른
얼음
얼핏
엄마
업무
업종
업체
엉덩이
엉망
엉터리
엊그제
에너지
에어컨
엔진
여건
여고생
여관
여군
여권
여대생
여덟
여동생
여든
여론
여름
여섯
여성
여왕
여인
여전히
여직원
여학생
여행
역사
역시
역할
연결
연구
연극
연기
연락
연설
연세
연속
연습
연애
연예인
연인
연장
연주
연출
연필
연합
연휴
열기
열매
열쇠
열심히
열정
열차
열흘
염려
엽서
영국
영남
영상
영양
영역
영웅
영원히
영하
영향
영혼
영화
옆구리
옆방
옆집
예감
예금
예방
예산
예상
예선
예술
예습
예식장
예약
예전
예절
예정
예컨대
옛날
오늘
오락
오랫동안
오렌지
오로지
오른발
오븐
오십
오염
오월
오전
오직
오징어
오페라
오피스텔
오히려
옥상
옥수수
온갖
온라인
온몸
온종일
온통
올가을
올림픽
올해
옷차림
와이셔츠
와인
완성
완전
왕비
왕자
왜냐하면
왠지
외갓집
외국
외로움
외삼촌
외출
외침
외할머니
왼발
왼손
왼쪽
요금
요일
요즘
요청
용기
용서
용어
우산
우선
우승
우연히
우정
우체국
우편
운동
운명
운반
운전
운행
울산
울음
움직임
웃어른
웃음
워낙
원고
원래
원서
원숭이
원인
원장
원피스
월급
월드컵
월세
월요일
웨이터
위반
위법
위성
위원
위험
위협
윗사람
유난히
유럽
유명
유물
유산
유적
유치원
유학
유행
유형
육군
육상
육십
육체
은행
음력
음료
음반
음성
음식
음악
음주
의견
의논
의문
의복
의식
의심
의외로
의욕
의원
의학
이것
이곳
이념
이놈
이달
이대로
이동
이렇게
이력서
이론적
이름
이민
이발소
이별
이불
이빨
이상
이성
이슬
이야기
이용
이웃
이월
이윽고
이익
이전
이중
이튿날
이틀
이혼
인간
인격
인공
인구
인근
인기
인도
인류
인물
인생
인쇄
인연
인원
인재
인종
인천
인체
인터넷
인하
인형
일곱
일기
일단
일대
일등
일반
일본
일부
일상
일생
일손
일요일
일월
일정
일종
일주일
일찍
일체
일치
일행
일회용
임금
임무
입대
입력
입맛
입사
입술
입시
입원
입장
입학
자가용
자격
자극
자동
자랑
자부심
자식
자신
자연
자원
자율
자전거
자정
자존심
자판
작가
작년
작성
작업
작용
작은딸
작품
잔디
잔뜩
잔치
잘못
잠깐
잠수함
잠시
잠옷
잠자리
잡지
장관
장군
장기간
장래
장례
장르
장마
장면
장모
장미
장비
장사
장소
장식
장애인
장인
장점
장차
장학금
재능
재빨리
재산
재생
재작년
재정
재채기
재판
재학
재활용
저것
저고리
저곳
저녁
저런
저렇게
저번
저울
저절로
저축
적극
적당히
적성
적용
적응
전개
전공
전기
전달
전라도
전망
전문
전반
전부
전세
전시
전용
전자
전쟁
전주
전철
전체
전통
전혀
전후
절대
절망
절반
절약
절차
점검
점수
점심
점원
점점
점차
접근
접시
접촉
젓가락
정거장
정도
정류장
정리
정말
정면
정문
정반대
정보
정부
정비
정상
정성
정오
정원
정장
정지
정치
정확히
제공
제과점
제대로
제목
제발
제법
제삿날
제안
제일
제작
제주도
제출
제품
제한
조각
조건
조금
조깅
조명
조미료
조상
조선
조용히
조절
조정
조직
존댓말
존재
졸업
졸음
종교
종로
종류
종소리
종업원
종종
종합
좌석
죄인
주관적
주름
주말
주머니
주먹
주문
주민
주방
주변
주식
주인
주일
주장
주전자
주택
준비
줄거리
줄기
줄무늬
중간
중계방송
중국
중년
중단
중독
중반
중부
중세
중소기업
중순
중앙
중요
중학교
즉석
즉시
즐거움
증가
증거
증권
증상
증세
지각
지갑
지경
지극히
지금
지급
지능
지름길
지리산
지방
지붕
지식
지역
지우개
지원
지적
지점
지진
지출
직선
직업
직원
직장
진급
진동
진로
진료
진리
진짜
진찰
진출
진통
진행
질문
질병
질서
짐작
집단
집안
집중
짜증
찌꺼기
차남
차라리
차량
차림
차별
차선
차츰
착각
찬물
찬성
참가
참기름
참새
참석
참여
참외
참조
찻잔
창가
창고
창구
창문
창밖
창작
창조
채널
채점
책가방
책방
책상
책임
챔피언
처벌
처음
천국
천둥
천장
천재
천천히
철도
철저히
철학
첫날
첫째
청년
청바지
청소
청춘
체계
체력
체온
체육
체중
체험
초등학생
초반
초밥
초상화
초순
초여름
초원
초저녁
초점
초청
초콜릿
촛불
총각
총리
총장
촬영
최근
최상
최선
최신
최악
최종
추석
추억
추진
추천
추측
축구
축소
축제
축하
출근
출발
출산
출신
출연
출입
출장
출판
충격
충고
충돌
충분히
충청도
취업
취직
취향
치약
친구
친척
칠십
칠월
칠판
침대
침묵
침실
칫솔
칭찬
카메라
카운터
칼국수
캐릭터
캠퍼스
캠페인
커튼
컨디션
컬러
컴퓨터
코끼리
코미디
콘서트
콜라
콤플렉스
콩나물
쾌감
쿠데타
크림
큰길
큰딸
큰소리
큰아들
큰어머니
큰일
큰절
클래식
클럽
킬로
타입
타자기
탁구
탁자
탄생
태권도
태양
태풍
택시
탤런트
터널
터미널
테니스
테스트
테이블
텔레비전
토론
토마토
토요일
통계
통과
통로
통신
통역
통일
통장
통제
통증
통합
통화
퇴근
퇴원
퇴직금
튀김
트럭
특급
특별
특성
특수
특징
특히
튼튼히
티셔츠
파란색
파일
파출소
판결
판단
판매
판사
팔십
팔월
팝송
패션
팩스
팩시밀리
팬티
퍼센트
페인트
편견
편의
편지
편히
평가
평균
평생
평소
평양
평일
평화
포스터
포인트
포장
포함
표면
표정
표준
표현
품목
품질
풍경
풍속
풍습
프랑스
프린터
플라스틱
피곤
피망
피아노
필름
필수
필요
필자
필통
핑계
하느님
하늘
하드웨어
하룻밤
하반기
하숙집
하순
하여튼
하지만
하천
하품
하필
학과
학교
학급
학기
학년
학력
학번
학부모
학비
학생
학술
학습
학용품
학원
학위
학자
학점
한계
한글
한꺼번에
한낮
한눈
한동안
한때
한라산
한마디
한문
한번
한복
한식
한여름
한쪽
할머니
할아버지
할인
함께
함부로
합격
합리적
항공
항구
항상
항의
해결
해군
해답
해당
해물
해석
해설
해수욕장
해안
핵심
핸드백
햄버거
햇볕
햇살
행동
행복
행사
행운
행위
향기
향상
향수
허락
허용
헬기
현관
현금
현대
현상
현실
현장
현재
현지
혈액
협력
형부
형사
형수
형식
형제
형태
형편
혜택
호기심
호남
호랑이
호박
호텔
호흡
혹시
홀로
홈페이지
홍보
홍수
홍차
화면
화분
화살
화요일
화장
화학
확보
확인
확장
확정
환갑
환경
환영
환율
환자
활기
활동
활발히
활용
활짝
회견
회관
회복
회색
회원
회장
회전
횟수
횡단보도
효율적
후반
후춧가루
훈련
훨씬
휴식
휴일
흉내
흐름
흑백
흑인
흔적
흔히
흥미
흥분
희곡
희망
희생
흰색
힘껏
================================================
FILE: bip-0039/portuguese.txt
================================================
abacate
abaixo
abalar
abater
abduzir
abelha
aberto
abismo
abotoar
abranger
abreviar
abrigar
abrupto
absinto
absoluto
absurdo
abutre
acabado
acalmar
acampar
acanhar
acaso
aceitar
acelerar
acenar
acervo
acessar
acetona
achatar
acidez
acima
acionado
acirrar
aclamar
aclive
acolhida
acomodar
acoplar
acordar
acumular
acusador
adaptar
adega
adentro
adepto
adequar
aderente
adesivo
adeus
adiante
aditivo
adjetivo
adjunto
admirar
adorar
adquirir
adubo
adverso
advogado
aeronave
afastar
aferir
afetivo
afinador
afivelar
aflito
afluente
afrontar
agachar
agarrar
agasalho
agenciar
agilizar
agiota
agitado
agora
agradar
agreste
agrupar
aguardar
agulha
ajoelhar
ajudar
ajustar
alameda
alarme
alastrar
alavanca
albergue
albino
alcatra
aldeia
alecrim
alegria
alertar
alface
alfinete
algum
alheio
aliar
alicate
alienar
alinhar
aliviar
almofada
alocar
alpiste
alterar
altitude
alucinar
alugar
aluno
alusivo
alvo
amaciar
amador
amarelo
amassar
ambas
ambiente
ameixa
amenizar
amido
amistoso
amizade
amolador
amontoar
amoroso
amostra
amparar
ampliar
ampola
anagrama
analisar
anarquia
anatomia
andaime
anel
anexo
angular
animar
anjo
anomalia
anotado
ansioso
anterior
anuidade
anunciar
anzol
apagador
apalpar
apanhado
apego
apelido
apertada
apesar
apetite
apito
aplauso
aplicada
apoio
apontar
aposta
aprendiz
aprovar
aquecer
arame
aranha
arara
arcada
ardente
areia
arejar
arenito
aresta
argiloso
argola
arma
arquivo
arraial
arrebate
arriscar
arroba
arrumar
arsenal
arterial
artigo
arvoredo
asfaltar
asilado
aspirar
assador
assinar
assoalho
assunto
astral
atacado
atadura
atalho
atarefar
atear
atender
aterro
ateu
atingir
atirador
ativo
atoleiro
atracar
atrevido
atriz
atual
atum
auditor
aumentar
aura
aurora
autismo
autoria
autuar
avaliar
avante
avaria
avental
avesso
aviador
avisar
avulso
axila
azarar
azedo
azeite
azulejo
babar
babosa
bacalhau
bacharel
bacia
bagagem
baiano
bailar
baioneta
bairro
baixista
bajular
baleia
baliza
balsa
banal
bandeira
banho
banir
banquete
barato
barbado
baronesa
barraca
barulho
baseado
bastante
batata
batedor
batida
batom
batucar
baunilha
beber
beijo
beirada
beisebol
beldade
beleza
belga
beliscar
bendito
bengala
benzer
berimbau
berlinda
berro
besouro
bexiga
bezerro
bico
bicudo
bienal
bifocal
bifurcar
bigorna
bilhete
bimestre
bimotor
biologia
biombo
biosfera
bipolar
birrento
biscoito
bisneto
bispo
bissexto
bitola
bizarro
blindado
bloco
bloquear
boato
bobagem
bocado
bocejo
bochecha
boicotar
bolada
boletim
bolha
bolo
bombeiro
bonde
boneco
bonita
borbulha
borda
boreal
borracha
bovino
boxeador
branco
brasa
braveza
breu
briga
brilho
brincar
broa
brochura
bronzear
broto
bruxo
bucha
budismo
bufar
bule
buraco
busca
busto
buzina
cabana
cabelo
cabide
cabo
cabrito
cacau
cacetada
cachorro
cacique
cadastro
cadeado
cafezal
caiaque
caipira
caixote
cajado
caju
calafrio
calcular
caldeira
calibrar
calmante
calota
camada
cambista
camisa
camomila
campanha
camuflar
canavial
cancelar
caneta
canguru
canhoto
canivete
canoa
cansado
cantar
canudo
capacho
capela
capinar
capotar
capricho
captador
capuz
caracol
carbono
cardeal
careca
carimbar
carneiro
carpete
carreira
cartaz
carvalho
casaco
casca
casebre
castelo
casulo
catarata
cativar
caule
causador
cautelar
cavalo
caverna
cebola
cedilha
cegonha
celebrar
celular
cenoura
censo
centeio
cercar
cerrado
certeiro
cerveja
cetim
cevada
chacota
chaleira
chamado
chapada
charme
chatice
chave
chefe
chegada
cheiro
cheque
chicote
chifre
chinelo
chocalho
chover
chumbo
chutar
chuva
cicatriz
ciclone
cidade
cidreira
ciente
cigana
cimento
cinto
cinza
ciranda
circuito
cirurgia
citar
clareza
clero
clicar
clone
clube
coado
coagir
cobaia
cobertor
cobrar
cocada
coelho
coentro
coeso
cogumelo
coibir
coifa
coiote
colar
coleira
colher
colidir
colmeia
colono
coluna
comando
combinar
comentar
comitiva
comover
complexo
comum
concha
condor
conectar
confuso
congelar
conhecer
conjugar
consumir
contrato
convite
cooperar
copeiro
copiador
copo
coquetel
coragem
cordial
corneta
coronha
corporal
correio
cortejo
coruja
corvo
cosseno
costela
cotonete
couro
couve
covil
cozinha
cratera
cravo
creche
credor
creme
crer
crespo
criada
criminal
crioulo
crise
criticar
crosta
crua
cruzeiro
cubano
cueca
cuidado
cujo
culatra
culminar
culpar
cultura
cumprir
cunhado
cupido
curativo
curral
cursar
curto
cuspir
custear
cutelo
damasco
datar
debater
debitar
deboche
debulhar
decalque
decimal
declive
decote
decretar
dedal
dedicado
deduzir
defesa
defumar
degelo
degrau
degustar
deitado
deixar
delator
delegado
delinear
delonga
demanda
demitir
demolido
dentista
depenado
depilar
depois
depressa
depurar
deriva
derramar
desafio
desbotar
descanso
desenho
desfiado
desgaste
desigual
deslize
desmamar
desova
despesa
destaque
desviar
detalhar
detentor
detonar
detrito
deusa
dever
devido
devotado
dezena
diagrama
dialeto
didata
difuso
digitar
dilatado
diluente
diminuir
dinastia
dinheiro
diocese
direto
discreta
disfarce
disparo
disquete
dissipar
distante
ditador
diurno
diverso
divisor
divulgar
dizer
dobrador
dolorido
domador
dominado
donativo
donzela
dormente
dorsal
dosagem
dourado
doutor
drenagem
drible
drogaria
duelar
duende
dueto
duplo
duquesa
durante
duvidoso
eclodir
ecoar
ecologia
edificar
edital
educado
efeito
efetivar
ejetar
elaborar
eleger
eleitor
elenco
elevador
eliminar
elogiar
embargo
embolado
embrulho
embutido
emenda
emergir
emissor
empatia
empenho
empinado
empolgar
emprego
empurrar
emulador
encaixe
encenado
enchente
encontro
endeusar
endossar
enfaixar
enfeite
enfim
engajado
engenho
englobar
engomado
engraxar
enguia
enjoar
enlatar
enquanto
enraizar
enrolado
enrugar
ensaio
enseada
ensino
ensopado
entanto
enteado
entidade
entortar
entrada
entulho
envergar
enviado
envolver
enxame
enxerto
enxofre
enxuto
epiderme
equipar
ereto
erguido
errata
erva
ervilha
esbanjar
esbelto
escama
escola
escrita
escuta
esfinge
esfolar
esfregar
esfumado
esgrima
esmalte
espanto
espelho
espiga
esponja
espreita
espumar
esquerda
estaca
esteira
esticar
estofado
estrela
estudo
esvaziar
etanol
etiqueta
euforia
europeu
evacuar
evaporar
evasivo
eventual
evidente
evoluir
exagero
exalar
examinar
exato
exausto
excesso
excitar
exclamar
executar
exemplo
exibir
exigente
exonerar
expandir
expelir
expirar
explanar
exposto
expresso
expulsar
externo
extinto
extrato
fabricar
fabuloso
faceta
facial
fada
fadiga
faixa
falar
falta
familiar
fandango
fanfarra
fantoche
fardado
farelo
farinha
farofa
farpa
fartura
fatia
fator
favorita
faxina
fazenda
fechado
feijoada
feirante
felino
feminino
fenda
feno
fera
feriado
ferrugem
ferver
festejar
fetal
feudal
fiapo
fibrose
ficar
ficheiro
figurado
fileira
filho
filme
filtrar
firmeza
fisgada
fissura
fita
fivela
fixador
fixo
flacidez
flamingo
flanela
flechada
flora
flutuar
fluxo
focal
focinho
fofocar
fogo
foguete
foice
folgado
folheto
forjar
formiga
forno
forte
fosco
fossa
fragata
fralda
frango
frasco
fraterno
freira
frente
fretar
frieza
friso
fritura
fronha
frustrar
fruteira
fugir
fulano
fuligem
fundar
fungo
funil
furador
furioso
futebol
gabarito
gabinete
gado
gaiato
gaiola
gaivota
galega
galho
galinha
galocha
ganhar
garagem
garfo
gargalo
garimpo
garoupa
garrafa
gasoduto
gasto
gata
gatilho
gaveta
gazela
gelado
geleia
gelo
gemada
gemer
gemido
generoso
gengiva
genial
genoma
genro
geologia
gerador
germinar
gesso
gestor
ginasta
gincana
gingado
girafa
girino
glacial
glicose
global
glorioso
goela
goiaba
golfe
golpear
gordura
gorjeta
gorro
gostoso
goteira
governar
gracejo
gradual
grafite
gralha
grampo
granada
gratuito
graveto
graxa
grego
grelhar
greve
grilo
grisalho
gritaria
grosso
grotesco
grudado
grunhido
gruta
guache
guarani
guaxinim
guerrear
guiar
guincho
guisado
gula
guloso
guru
habitar
harmonia
haste
haver
hectare
herdar
heresia
hesitar
hiato
hibernar
hidratar
hiena
hino
hipismo
hipnose
hipoteca
hoje
holofote
homem
honesto
honrado
hormonal
hospedar
humorado
iate
ideia
idoso
ignorado
igreja
iguana
ileso
ilha
iludido
iluminar
ilustrar
imagem
imediato
imenso
imersivo
iminente
imitador
imortal
impacto
impedir
implante
impor
imprensa
impune
imunizar
inalador
inapto
inativo
incenso
inchar
incidir
incluir
incolor
indeciso
indireto
indutor
ineficaz
inerente
infantil
infestar
infinito
inflamar
informal
infrator
ingerir
inibido
inicial
inimigo
injetar
inocente
inodoro
inovador
inox
inquieto
inscrito
inseto
insistir
inspetor
instalar
insulto
intacto
integral
intimar
intocado
intriga
invasor
inverno
invicto
invocar
iogurte
iraniano
ironizar
irreal
irritado
isca
isento
isolado
isqueiro
italiano
janeiro
jangada
janta
jararaca
jardim
jarro
jasmim
jato
javali
jazida
jejum
joaninha
joelhada
jogador
joia
jornal
jorrar
jovem
juba
judeu
judoca
juiz
julgador
julho
jurado
jurista
juro
justa
labareda
laboral
lacre
lactante
ladrilho
lagarta
lagoa
laje
lamber
lamentar
laminar
lampejo
lanche
lapidar
lapso
laranja
lareira
largura
lasanha
lastro
lateral
latido
lavanda
lavoura
lavrador
laxante
lazer
lealdade
lebre
legado
legendar
legista
leigo
leiloar
leitura
lembrete
leme
lenhador
lentilha
leoa
lesma
leste
letivo
letreiro
levar
leveza
levitar
liberal
libido
liderar
ligar
ligeiro
limitar
limoeiro
limpador
linda
linear
linhagem
liquidez
listagem
lisura
litoral
livro
lixa
lixeira
locador
locutor
lojista
lombo
lona
longe
lontra
lorde
lotado
loteria
loucura
lousa
louvar
luar
lucidez
lucro
luneta
lustre
lutador
luva
macaco
macete
machado
macio
madeira
madrinha
magnata
magreza
maior
mais
malandro
malha
malote
maluco
mamilo
mamoeiro
mamute
manada
mancha
mandato
manequim
manhoso
manivela
manobrar
mansa
manter
manusear
mapeado
maquinar
marcador
maresia
marfim
margem
marinho
marmita
maroto
marquise
marreco
martelo
marujo
mascote
masmorra
massagem
mastigar
matagal
materno
matinal
matutar
maxilar
medalha
medida
medusa
megafone
meiga
melancia
melhor
membro
memorial
menino
menos
mensagem
mental
merecer
mergulho
mesada
mesclar
mesmo
mesquita
mestre
metade
meteoro
metragem
mexer
mexicano
micro
migalha
migrar
milagre
milenar
milhar
mimado
minerar
minhoca
ministro
minoria
miolo
mirante
mirtilo
misturar
mocidade
moderno
modular
moeda
moer
moinho
moita
moldura
moleza
molho
molinete
molusco
montanha
moqueca
morango
morcego
mordomo
morena
mosaico
mosquete
mostarda
motel
motim
moto
motriz
muda
muito
mulata
mulher
multar
mundial
munido
muralha
murcho
muscular
museu
musical
nacional
nadador
naja
namoro
narina
narrado
nascer
nativa
natureza
navalha
navegar
navio
neblina
nebuloso
negativa
negociar
negrito
nervoso
neta
neural
nevasca
nevoeiro
ninar
ninho
nitidez
nivelar
nobreza
noite
noiva
nomear
nominal
nordeste
nortear
notar
noticiar
noturno
novelo
novilho
novo
nublado
nudez
numeral
nupcial
nutrir
nuvem
obcecado
obedecer
objetivo
obrigado
obscuro
obstetra
obter
obturar
ocidente
ocioso
ocorrer
oculista
ocupado
ofegante
ofensiva
oferenda
oficina
ofuscado
ogiva
olaria
oleoso
olhar
oliveira
ombro
omelete
omisso
omitir
ondulado
oneroso
ontem
opcional
operador
oponente
oportuno
oposto
orar
orbitar
ordem
ordinal
orfanato
orgasmo
orgulho
oriental
origem
oriundo
orla
ortodoxo
orvalho
oscilar
ossada
osso
ostentar
otimismo
ousadia
outono
outubro
ouvido
ovelha
ovular
oxidar
oxigenar
pacato
paciente
pacote
pactuar
padaria
padrinho
pagar
pagode
painel
pairar
paisagem
palavra
palestra
palheta
palito
palmada
palpitar
pancada
panela
panfleto
panqueca
pantanal
papagaio
papelada
papiro
parafina
parcial
pardal
parede
partida
pasmo
passado
pastel
patamar
patente
patinar
patrono
paulada
pausar
peculiar
pedalar
pedestre
pediatra
pedra
pegada
peitoral
peixe
pele
pelicano
penca
pendurar
peneira
penhasco
pensador
pente
perceber
perfeito
pergunta
perito
permitir
perna
perplexo
persiana
pertence
peruca
pescado
pesquisa
pessoa
petiscar
piada
picado
piedade
pigmento
pilastra
pilhado
pilotar
pimenta
pincel
pinguim
pinha
pinote
pintar
pioneiro
pipoca
piquete
piranha
pires
pirueta
piscar
pistola
pitanga
pivete
planta
plaqueta
platina
plebeu
plumagem
pluvial
pneu
poda
poeira
poetisa
polegada
policiar
poluente
polvilho
pomar
pomba
ponderar
pontaria
populoso
porta
possuir
postal
pote
poupar
pouso
povoar
praia
prancha
prato
praxe
prece
predador
prefeito
premiar
prensar
preparar
presilha
pretexto
prevenir
prezar
primata
princesa
prisma
privado
processo
produto
profeta
proibido
projeto
prometer
propagar
prosa
protetor
provador
publicar
pudim
pular
pulmonar
pulseira
punhal
punir
pupilo
pureza
puxador
quadra
quantia
quarto
quase
quebrar
queda
queijo
quente
querido
quimono
quina
quiosque
rabanada
rabisco
rachar
racionar
radial
raiar
rainha
raio
raiva
rajada
ralado
ramal
ranger
ranhura
rapadura
rapel
rapidez
raposa
raquete
raridade
rasante
rascunho
rasgar
raspador
rasteira
rasurar
ratazana
ratoeira
realeza
reanimar
reaver
rebaixar
rebelde
rebolar
recado
recente
recheio
recibo
recordar
recrutar
recuar
rede
redimir
redonda
reduzida
reenvio
refinar
refletir
refogar
refresco
refugiar
regalia
regime
regra
reinado
reitor
rejeitar
relativo
remador
remendo
remorso
renovado
reparo
repelir
repleto
repolho
represa
repudiar
requerer
resenha
resfriar
resgatar
residir
resolver
respeito
ressaca
restante
resumir
retalho
reter
retirar
retomada
retratar
revelar
revisor
revolta
riacho
rica
rigidez
rigoroso
rimar
ringue
risada
risco
risonho
robalo
rochedo
rodada
rodeio
rodovia
roedor
roleta
romano
roncar
rosado
roseira
rosto
rota
roteiro
rotina
rotular
rouco
roupa
roxo
rubro
rugido
rugoso
ruivo
rumo
rupestre
russo
sabor
saciar
sacola
sacudir
sadio
safira
saga
sagrada
saibro
salada
saleiro
salgado
saliva
salpicar
salsicha
saltar
salvador
sambar
samurai
sanar
sanfona
sangue
sanidade
sapato
sarda
sargento
sarjeta
saturar
saudade
saxofone
sazonal
secar
secular
seda
sedento
sediado
sedoso
sedutor
segmento
segredo
segundo
seiva
seleto
selvagem
semanal
semente
senador
senhor
sensual
sentado
separado
sereia
seringa
serra
servo
setembro
setor
sigilo
silhueta
silicone
simetria
simpatia
simular
sinal
sincero
singular
sinopse
sintonia
sirene
siri
situado
soberano
sobra
socorro
sogro
soja
solda
soletrar
solteiro
sombrio
sonata
sondar
sonegar
sonhador
sono
soprano
soquete
sorrir
sorteio
sossego
sotaque
soterrar
sovado
sozinho
suavizar
subida
submerso
subsolo
subtrair
sucata
sucesso
suco
sudeste
sufixo
sugador
sugerir
sujeito
sulfato
sumir
suor
superior
suplicar
suposto
suprimir
surdina
surfista
surpresa
surreal
surtir
suspiro
sustento
tabela
tablete
tabuada
tacho
tagarela
talher
talo
talvez
tamanho
tamborim
tampa
tangente
tanto
tapar
tapioca
tardio
tarefa
tarja
tarraxa
tatuagem
taurino
taxativo
taxista
teatral
tecer
tecido
teclado
tedioso
teia
teimar
telefone
telhado
tempero
tenente
tensor
tentar
termal
terno
terreno
tese
tesoura
testado
teto
textura
texugo
tiara
tigela
tijolo
timbrar
timidez
tingido
tinteiro
tiragem
titular
toalha
tocha
tolerar
tolice
tomada
tomilho
tonel
tontura
topete
tora
torcido
torneio
torque
torrada
torto
tostar
touca
toupeira
toxina
trabalho
tracejar
tradutor
trafegar
trajeto
trama
trancar
trapo
traseiro
tratador
travar
treino
tremer
trepidar
trevo
triagem
tribo
triciclo
tridente
trilogia
trindade
triplo
triturar
triunfal
trocar
trombeta
trova
trunfo
truque
tubular
tucano
tudo
tulipa
tupi
turbo
turma
turquesa
tutelar
tutorial
uivar
umbigo
unha
unidade
uniforme
urologia
urso
urtiga
urubu
usado
usina
usufruir
vacina
vadiar
vagaroso
vaidoso
vala
valente
validade
valores
vantagem
vaqueiro
varanda
vareta
varrer
vascular
vasilha
vassoura
vazar
vazio
veado
vedar
vegetar
veicular
veleiro
velhice
veludo
vencedor
vendaval
venerar
ventre
verbal
verdade
vereador
vergonha
vermelho
verniz
versar
vertente
vespa
vestido
vetorial
viaduto
viagem
viajar
viatura
vibrador
videira
vidraria
viela
viga
vigente
vigiar
vigorar
vilarejo
vinco
vinheta
vinil
violeta
virada
virtude
visitar
visto
vitral
viveiro
vizinho
voador
voar
vogal
volante
voleibol
voltagem
volumoso
vontade
vulto
vuvuzela
xadrez
xarope
xeque
xeretar
xerife
xingar
zangado
zarpar
zebu
zelador
zombar
zoologia
zumbido
================================================
FILE: bip-0039/spanish.txt
================================================
ábaco
abdomen
abeja
abierto
abogado
abono
aborto
abrazo
abrir
abuelo
abuso
acabar
academia
acceso
acción
aceite
acelga
acento
aceptar
ácido
aclarar
acné
acoger
acoso
activo
acto
actriz
actuar
acudir
acuerdo
acusar
adicto
admitir
adoptar
adorno
aduana
adulto
aéreo
afectar
afición
afinar
afirmar
ágil
agitar
agonía
agosto
agotar
agregar
agrio
agua
agudo
águila
aguja
ahogo
ahorro
aire
aislar
ajedrez
ajeno
ajuste
alacrán
alambre
alarma
alba
álbum
alcalde
aldea
alegre
alejar
alerta
aleta
alfiler
alga
algodón
aliado
aliento
alivio
alma
almeja
almíbar
altar
alteza
altivo
alto
altura
alumno
alzar
amable
amante
amapola
amargo
amasar
ámbar
ámbito
ameno
amigo
amistad
amor
amparo
amplio
ancho
anciano
ancla
andar
andén
anemia
ángulo
anillo
ánimo
anís
anotar
antena
antiguo
antojo
anual
anular
anuncio
añadir
añejo
año
apagar
aparato
apetito
apio
aplicar
apodo
aporte
apoyo
aprender
aprobar
apuesta
apuro
arado
araña
arar
árbitro
árbol
arbusto
archivo
arco
arder
ardilla
arduo
área
árido
aries
armonía
arnés
aroma
arpa
arpón
arreglo
arroz
arruga
arte
artista
asa
asado
asalto
ascenso
asegurar
aseo
asesor
asiento
asilo
asistir
asno
asombro
áspero
astilla
astro
astuto
asumir
asunto
atajo
ataque
atar
atento
ateo
ático
atleta
átomo
atraer
atroz
atún
audaz
audio
auge
aula
aumento
ausente
autor
aval
avance
avaro
ave
avellana
avena
avestruz
avión
aviso
ayer
ayuda
ayuno
azafrán
azar
azote
azúcar
azufre
azul
baba
babor
bache
bahía
baile
bajar
balanza
balcón
balde
bambú
banco
banda
baño
barba
barco
barniz
barro
báscula
bastón
basura
batalla
batería
batir
batuta
baúl
bazar
bebé
bebida
bello
besar
beso
bestia
bicho
bien
bingo
blanco
bloque
blusa
boa
bobina
bobo
boca
bocina
boda
bodega
boina
bola
bolero
bolsa
bomba
bondad
bonito
bono
bonsái
borde
borrar
bosque
bote
botín
bóveda
bozal
bravo
brazo
brecha
breve
brillo
brinco
brisa
broca
broma
bronce
brote
bruja
brusco
bruto
buceo
bucle
bueno
buey
bufanda
bufón
búho
buitre
bulto
burbuja
burla
burro
buscar
butaca
buzón
caballo
cabeza
cabina
cabra
cacao
cadáver
cadena
caer
café
caída
caimán
caja
cajón
cal
calamar
calcio
caldo
calidad
calle
calma
calor
calvo
cama
cambio
camello
camino
campo
cáncer
candil
canela
canguro
canica
canto
caña
cañón
caoba
caos
capaz
capitán
capote
captar
capucha
cara
carbón
cárcel
careta
carga
cariño
carne
carpeta
carro
carta
casa
casco
casero
caspa
castor
catorce
catre
caudal
causa
cazo
cebolla
ceder
cedro
celda
célebre
celoso
célula
cemento
ceniza
centro
cerca
cerdo
cereza
cero
cerrar
certeza
césped
cetro
chacal
chaleco
champú
chancla
chapa
charla
chico
chiste
chivo
choque
choza
chuleta
chupar
ciclón
ciego
cielo
cien
cierto
cifra
cigarro
cima
cinco
cine
cinta
ciprés
circo
ciruela
cisne
cita
ciudad
clamor
clan
claro
clase
clave
cliente
clima
clínica
cobre
cocción
cochino
cocina
coco
código
codo
cofre
coger
cohete
cojín
cojo
cola
colcha
colegio
colgar
colina
collar
colmo
columna
combate
comer
comida
cómodo
compra
conde
conejo
conga
conocer
consejo
contar
copa
copia
corazón
corbata
corcho
cordón
corona
correr
coser
cosmos
costa
cráneo
cráter
crear
crecer
creído
crema
cría
crimen
cripta
crisis
cromo
crónica
croqueta
crudo
cruz
cuadro
cuarto
cuatro
cubo
cubrir
cuchara
cuello
cuento
cuerda
cuesta
cueva
cuidar
culebra
culpa
culto
cumbre
cumplir
cuna
cuneta
cuota
cupón
cúpula
curar
curioso
curso
curva
cutis
dama
danza
dar
dardo
dátil
deber
débil
década
decir
dedo
defensa
definir
dejar
delfín
delgado
delito
demora
denso
dental
deporte
derecho
derrota
desayuno
deseo
desfile
desnudo
destino
desvío
detalle
detener
deuda
día
diablo
diadema
diamante
diana
diario
dibujo
dictar
diente
dieta
diez
difícil
digno
dilema
diluir
dinero
directo
dirigir
disco
diseño
disfraz
diva
divino
doble
doce
dolor
domingo
don
donar
dorado
dormir
dorso
dos
dosis
dragón
droga
ducha
duda
duelo
dueño
dulce
dúo
duque
durar
dureza
duro
ébano
ebrio
echar
eco
ecuador
edad
edición
edificio
editor
educar
efecto
eficaz
eje
ejemplo
elefante
elegir
elemento
elevar
elipse
élite
elixir
elogio
eludir
embudo
emitir
emoción
empate
empeño
empleo
empresa
enano
encargo
enchufe
encía
enemigo
enero
enfado
enfermo
engaño
enigma
enlace
enorme
enredo
ensayo
enseñar
entero
entrar
envase
envío
época
equipo
erizo
escala
escena
escolar
escribir
escudo
esencia
esfera
esfuerzo
espada
espejo
espía
esposa
espuma
esquí
estar
este
estilo
estufa
etapa
eterno
ética
etnia
evadir
evaluar
evento
evitar
exacto
examen
exceso
excusa
exento
exigir
exilio
existir
éxito
experto
explicar
exponer
extremo
fábrica
fábula
fachada
fácil
factor
faena
faja
falda
fallo
falso
faltar
fama
familia
famoso
faraón
farmacia
farol
farsa
fase
fatiga
fauna
favor
fax
febrero
fecha
feliz
feo
feria
feroz
fértil
fervor
festín
fiable
fianza
fiar
fibra
ficción
ficha
fideo
fiebre
fiel
fiera
fiesta
figura
fijar
fijo
fila
filete
filial
filtro
fin
finca
fingir
finito
firma
flaco
flauta
flecha
flor
flota
fluir
flujo
flúor
fobia
foca
fogata
fogón
folio
folleto
fondo
forma
forro
fortuna
forzar
fosa
foto
fracaso
frágil
franja
frase
fraude
freír
freno
fresa
frío
frito
fruta
fuego
fuente
fuerza
fuga
fumar
función
funda
furgón
furia
fusil
fútbol
futuro
gacela
gafas
gaita
gajo
gala
galería
gallo
gamba
ganar
gancho
ganga
ganso
garaje
garza
gasolina
gastar
gato
gavilán
gemelo
gemir
gen
género
genio
gente
geranio
gerente
germen
gesto
gigante
gimnasio
girar
giro
glaciar
globo
gloria
gol
golfo
goloso
golpe
goma
gordo
gorila
gorra
gota
goteo
gozar
grada
gráfico
grano
grasa
gratis
grave
grieta
grillo
gripe
gris
grito
grosor
grúa
grueso
grumo
grupo
guante
guapo
guardia
guerra
guía
guiño
guion
guiso
guitarra
gusano
gustar
haber
hábil
hablar
hacer
hacha
hada
hallar
hamaca
harina
haz
hazaña
hebilla
hebra
hecho
helado
helio
hembra
herir
hermano
héroe
hervir
hielo
hierro
hígado
higiene
hijo
himno
historia
hocico
hogar
hoguera
hoja
hombre
hongo
honor
honra
hora
hormiga
horno
hostil
hoyo
hueco
huelga
huerta
hueso
huevo
huida
huir
humano
húmedo
humilde
humo
hundir
huracán
hurto
icono
ideal
idioma
ídolo
iglesia
iglú
igual
ilegal
ilusión
imagen
imán
imitar
impar
imperio
imponer
impulso
incapaz
índice
inerte
infiel
informe
ingenio
inicio
inmenso
inmune
innato
insecto
instante
interés
íntimo
intuir
inútil
invierno
ira
iris
ironía
isla
islote
jabalí
jabón
jamón
jarabe
jardín
jarra
jaula
jazmín
jefe
jeringa
jinete
jornada
joroba
joven
joya
juerga
jueves
juez
jugador
jugo
juguete
juicio
junco
jungla
junio
juntar
júpiter
jurar
justo
juvenil
juzgar
kilo
koala
labio
lacio
lacra
lado
ladrón
lagarto
lágrima
laguna
laico
lamer
lámina
lámpara
lana
lancha
langosta
lanza
lápiz
largo
larva
lástima
lata
látex
latir
laurel
lavar
lazo
leal
lección
leche
lector
leer
legión
legumbre
lejano
lengua
lento
leña
león
leopardo
lesión
letal
letra
leve
leyenda
libertad
libro
licor
líder
lidiar
lienzo
liga
ligero
lima
límite
limón
limpio
lince
lindo
línea
lingote
lino
linterna
líquido
liso
lista
litera
litio
litro
llaga
llama
llanto
llave
llegar
llenar
llevar
llorar
llover
lluvia
lobo
loción
loco
locura
lógica
logro
lombriz
lomo
lonja
lote
lucha
lucir
lugar
lujo
luna
lunes
lupa
lustro
luto
luz
maceta
macho
madera
madre
maduro
maestro
mafia
magia
mago
maíz
maldad
maleta
malla
malo
mamá
mambo
mamut
manco
mando
manejar
manga
maniquí
manjar
mano
manso
manta
mañana
mapa
máquina
mar
marco
marea
marfil
margen
marido
mármol
marrón
martes
marzo
masa
máscara
masivo
matar
materia
matiz
matriz
máximo
mayor
mazorca
mecha
medalla
medio
médula
mejilla
mejor
melena
melón
memoria
menor
mensaje
mente
menú
mercado
merengue
mérito
mes
mesón
meta
meter
método
metro
mezcla
miedo
miel
miembro
miga
mil
milagro
militar
millón
mimo
mina
minero
mínimo
minuto
miope
mirar
misa
miseria
misil
mismo
mitad
mito
mochila
moción
moda
modelo
moho
mojar
molde
moler
molino
momento
momia
monarca
moneda
monja
monto
moño
morada
morder
moreno
morir
morro
morsa
mortal
mosca
mostrar
motivo
mover
móvil
mozo
mucho
mudar
mueble
muela
muerte
muestra
mugre
mujer
mula
muleta
multa
mundo
muñeca
mural
muro
músculo
museo
musgo
música
muslo
nácar
nación
nadar
naipe
naranja
nariz
narrar
nasal
natal
nativo
natural
náusea
naval
nave
navidad
necio
néctar
negar
negocio
negro
neón
nervio
neto
neutro
nevar
nevera
nicho
nido
niebla
nieto
niñez
niño
nítido
nivel
nobleza
noche
nómina
noria
norma
norte
nota
noticia
novato
novela
novio
nube
nuca
núcleo
nudillo
nudo
nuera
nueve
nuez
nulo
número
nutria
oasis
obeso
obispo
objeto
obra
obrero
observar
obtener
obvio
oca
ocaso
océano
ochenta
ocho
ocio
ocre
octavo
octubre
oculto
ocupar
ocurrir
odiar
odio
odisea
oeste
ofensa
oferta
oficio
ofrecer
ogro
oído
oír
ojo
ola
oleada
olfato
olivo
olla
olmo
olor
olvido
ombligo
onda
onza
opaco
opción
ópera
opinar
oponer
optar
óptica
opuesto
oración
orador
oral
órbita
orca
orden
oreja
órgano
orgía
orgullo
oriente
origen
orilla
oro
orquesta
oruga
osadía
oscuro
osezno
oso
ostra
otoño
otro
oveja
óvulo
óxido
oxígeno
oyente
ozono
pacto
padre
paella
página
pago
país
pájaro
palabra
palco
paleta
pálido
palma
paloma
palpar
pan
panal
pánico
pantera
pañuelo
papá
papel
papilla
paquete
parar
parcela
pared
parir
paro
párpado
parque
párrafo
parte
pasar
paseo
pasión
paso
pasta
pata
patio
patria
pausa
pauta
pavo
payaso
peatón
pecado
pecera
pecho
pedal
pedir
pegar
peine
pelar
peldaño
pelea
peligro
pellejo
pelo
peluca
pena
pensar
peñón
peón
peor
pepino
pequeño
pera
percha
perder
pereza
perfil
perico
perla
permiso
perro
persona
pesa
pesca
pésimo
pestaña
pétalo
petróleo
pez
pezuña
picar
pichón
pie
piedra
pierna
pieza
pijama
pilar
piloto
pimienta
pino
pintor
pinza
piña
piojo
pipa
pirata
pisar
piscina
piso
pista
pitón
pizca
placa
plan
plata
playa
plaza
pleito
pleno
plomo
pluma
plural
pobre
poco
poder
podio
poema
poesía
poeta
polen
policía
pollo
polvo
pomada
pomelo
pomo
pompa
poner
porción
portal
posada
poseer
posible
poste
potencia
potro
pozo
prado
precoz
pregunta
premio
prensa
preso
previo
primo
príncipe
prisión
privar
proa
probar
proceso
producto
proeza
profesor
programa
prole
promesa
pronto
propio
próximo
prueba
público
puchero
pudor
pueblo
puerta
puesto
pulga
pulir
pulmón
pulpo
pulso
puma
punto
puñal
puño
pupa
pupila
puré
quedar
queja
quemar
querer
queso
quieto
química
quince
quitar
rábano
rabia
rabo
ración
radical
raíz
rama
rampa
rancho
rango
rapaz
rápido
rapto
rasgo
raspa
rato
rayo
raza
razón
reacción
realidad
rebaño
rebote
recaer
receta
rechazo
recoger
recreo
recto
recurso
red
redondo
reducir
reflejo
reforma
refrán
refugio
regalo
regir
regla
regreso
rehén
reino
reír
reja
relato
relevo
relieve
relleno
reloj
remar
remedio
remo
rencor
rendir
renta
reparto
repetir
reposo
reptil
res
rescate
resina
respeto
resto
resumen
retiro
retorno
retrato
reunir
revés
revista
rey
rezar
rico
riego
rienda
riesgo
rifa
rígido
rigor
rincón
riñón
río
riqueza
risa
ritmo
rito
rizo
roble
roce
rociar
rodar
rodeo
rodilla
roer
rojizo
rojo
romero
romper
ron
ronco
ronda
ropa
ropero
rosa
rosca
rostro
rotar
rubí
rubor
rudo
rueda
rugir
ruido
ruina
ruleta
rulo
rumbo
rumor
ruptura
ruta
rutina
sábado
saber
sabio
sable
sacar
sagaz
sagrado
sala
saldo
salero
salir
salmón
salón
salsa
salto
salud
salvar
samba
sanción
sandía
sanear
sangre
sanidad
sano
santo
sapo
saque
sardina
sartén
sastre
satán
sauna
saxofón
sección
seco
secreto
secta
sed
seguir
seis
sello
selva
semana
semilla
senda
sensor
señal
señor
separar
sepia
sequía
ser
serie
sermón
servir
sesenta
sesión
seta
setenta
severo
sexo
sexto
sidra
siesta
siete
siglo
signo
sílaba
silbar
silencio
silla
símbolo
simio
sirena
sistema
sitio
situar
sobre
socio
sodio
sol
solapa
soldado
soledad
sólido
soltar
solución
sombra
sondeo
sonido
sonoro
sonrisa
sopa
soplar
soporte
sordo
sorpresa
sorteo
sostén
sótano
suave
subir
suceso
sudor
suegra
suelo
sueño
suerte
sufrir
sujeto
sultán
sumar
superar
suplir
suponer
supremo
sur
surco
sureño
surgir
susto
sutil
tabaco
tabique
tabla
tabú
taco
tacto
tajo
talar
talco
talento
talla
talón
tamaño
tambor
tango
tanque
tapa
tapete
tapia
tapón
taquilla
tarde
tarea
tarifa
tarjeta
tarot
tarro
tarta
tatuaje
tauro
taza
tazón
teatro
techo
tecla
técnica
tejado
tejer
tejido
tela
teléfono
tema
temor
templo
tenaz
tender
tener
tenis
tenso
teoría
terapia
terco
término
ternura
terror
tesis
tesoro
testigo
tetera
texto
tez
tibio
tiburón
tiempo
tienda
tierra
tieso
tigre
tijera
tilde
timbre
tímido
timo
tinta
tío
típico
tipo
tira
tirón
titán
títere
título
tiza
toalla
tobillo
tocar
tocino
todo
toga
toldo
tomar
tono
tonto
topar
tope
toque
tórax
torero
tormenta
torneo
toro
torpedo
torre
torso
tortuga
tos
tosco
toser
tóxico
trabajo
tractor
traer
tráfico
trago
traje
tramo
trance
trato
trauma
trazar
trébol
tregua
treinta
tren
trepar
tres
tribu
trigo
tripa
triste
triunfo
trofeo
trompa
tronco
tropa
trote
trozo
truco
trueno
trufa
tubería
tubo
tuerto
tumba
tumor
túnel
túnica
turbina
turismo
turno
tutor
ubicar
úlcera
umbral
unidad
unir
universo
uno
untar
uña
urbano
urbe
urgente
urna
usar
usuario
útil
utopía
uva
vaca
vacío
vacuna
vagar
vago
vaina
vajilla
vale
válido
valle
valor
válvula
vampiro
vara
variar
varón
vaso
vecino
vector
vehículo
veinte
vejez
vela
velero
veloz
vena
vencer
venda
veneno
vengar
venir
venta
venus
ver
verano
verbo
verde
vereda
verja
verso
verter
vía
viaje
vibrar
vicio
víctima
vida
vídeo
vidrio
viejo
viernes
vigor
vil
villa
vinagre
vino
viñedo
violín
viral
virgo
virtud
visor
víspera
vista
vitamina
viudo
vivaz
vivero
vivir
vivo
volcán
volumen
volver
voraz
votar
voto
voz
vuelo
vulgar
yacer
yate
yegua
yema
yerno
yeso
yodo
yoga
yogur
zafiro
zanja
zapato
zarza
zona
zorro
zumo
zurdo
================================================
FILE: bip-0039.mediawiki
================================================
BIP: 39
Layer: Applications
Title: Mnemonic code for generating deterministic keys
Authors: Marek Palatinus
Pavol Rusnak
Aaron Voisine
Sean Bowe
Comments-Summary: Unanimously Discourage for implementation
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0039
Status: Deployed
Type: Specification
Assigned: 2013-09-10
License: MIT
==Abstract==
This BIP describes the implementation of a mnemonic code or mnemonic sentence --
a group of easy to remember words -- for the generation of deterministic wallets.
It consists of two parts: generating the mnemonic and converting it into a
binary seed. This seed can be later used to generate deterministic wallets using
BIP-0032 or similar methods.
==Copyright==
This BIP falls under the MIT License.
==Motivation==
A mnemonic code or sentence is superior for human interaction compared to the
handling of raw binary or hexadecimal representations of a wallet seed. The
sentence could be written on paper or spoken over the telephone.
This guide is meant to be a way to transport computer-generated randomness with
a human-readable transcription. It's not a way to process user-created
sentences (also known as brainwallets) into a wallet seed.
==Generating the mnemonic==
The mnemonic must encode entropy in a multiple of 32 bits. With more entropy
security is improved but the sentence length increases. We refer to the
initial entropy length as ENT. The allowed size of ENT is 128-256 bits.
First, an initial entropy of ENT bits is generated. A checksum is generated by
taking the first ENT / 32 bits of its SHA256 hash. This checksum is
appended to the end of the initial entropy. Next, these concatenated bits
are split into groups of 11 bits, each encoding a number from 0-2047, serving
as an index into a wordlist. Finally, we convert these numbers into words and
use the joined words as a mnemonic sentence.
The following table describes the relation between the initial entropy
length (ENT), the checksum length (CS), and the length of the generated mnemonic
sentence (MS) in words.
==Wordlist==
An ideal wordlist has the following characteristics:
a) smart selection of words
- the wordlist is created in such a way that it's enough to type the first four
letters to unambiguously identify the word
b) similar words avoided
- word pairs like "build" and "built", "woman" and "women", or "quick" and "quickly"
not only make remembering the sentence difficult but are also more error
prone and more difficult to guess
c) sorted wordlists
- the wordlist is sorted which allows for more efficient lookup of the code words
(i.e. implementations can use binary search instead of linear search)
- this also allows trie (a prefix tree) to be used, e.g. for better compression
The wordlist can contain native characters, but they must be encoded in UTF-8
using Normalization Form Compatibility Decomposition (NFKD).
==From mnemonic to seed==
A user may decide to protect their mnemonic with a passphrase. If a passphrase is not
present, an empty string "" is used instead.
To create a binary seed from the mnemonic, we use the PBKDF2 function with a mnemonic
sentence (in UTF-8 NFKD) used as the password and the string "mnemonic" + passphrase (again
in UTF-8 NFKD) used as the salt. The iteration count is set to 2048 and HMAC-SHA512 is used as
the pseudo-random function. The length of the derived key is 512 bits (= 64 bytes).
This seed can be later used to generate deterministic wallets using BIP-0032 or
similar methods.
The conversion of the mnemonic sentence to a binary seed is completely independent
from generating the sentence. This results in a rather simple code; there are no
constraints on sentence structure and clients are free to implement their own
wordlists or even whole sentence generators, allowing for flexibility in wordlists
for typo detection or other purposes.
Although using a mnemonic not generated by the algorithm described in "Generating the
mnemonic" section is possible, this is not advised and software must compute a
checksum for the mnemonic sentence using a wordlist and issue a warning if it is
invalid.
The described method also provides plausible deniability, because every passphrase
generates a valid seed (and thus a deterministic wallet) but only the correct one
will make the desired wallet available.
==Wordlists==
Since the vast majority of BIP39 wallets supports only the English wordlist,
it is '''strongly discouraged''' to use non-English wordlists for generating
the mnemonic sentences.
If you still feel your application really needs to use a localized wordlist,
use one of the following instead of inventing your own.
* [[bip-0039/bip-0039-wordlists.md|Wordlists]]
==Test vectors==
The test vectors include input entropy, mnemonic and seed. The
passphrase "TREZOR" is used for all vectors.
https://github.com/trezor/python-mnemonic/blob/master/vectors.json
Also see https://github.com/bip32JP/bip32JP.github.io/blob/master/test_JP_BIP39.json
(Japanese wordlist test with heavily normalized symbols as passphrase)
==Reference Implementation==
Reference implementation including wordlists is available from
http://github.com/trezor/python-mnemonic
================================================
FILE: bip-0042.mediawiki
================================================
==Abstract==
Although it is widely believed that Satoshi was an inflation-hating goldbug he never said this, and in fact programmed Bitcoin's money supply to grow indefinitely, forever. He modeled the monetary supply as 4 gold mines being discovered per mibillennium (1024 years), with equal intervals between them, each one being depleted over the course of 140 years.
This poses obvious problems, however. Prominent among them is the discussion on what to call 1 billion bitcoin, which symbol color to use for it, and when wallet clients should switch to it by default.
To combat this, this document proposes a controversial change: making Bitcoin's monetary supply finite.
==Details==
As is well known, Satoshi was a master programmer whose knowledge of C++ was surpassed only by his knowledge of Japanese culture. The code below:
int64_t nSubsidy = 50 * COIN;
// Subsidy is cut in half every 210,000 blocks
// which will occur approximately every 4 years.
nSubsidy >>= (nHeight / 210000);
is carefully written to rely on undefined behaviour in the C++ specification - perhaps so it can be hardware accelerated in future.
The block number is divided by 210000 (the "apparent" subsidy halving interval in blocks), and the result is used as input for a binary shift, applied to the original payout (50 BTC), expressed in base units. Thanks to the new-goldmine interval being exactly 64 times the halving interval, and 64 being the size in bits of the currency datatype, the cycle repeats itself every 64 halvings on all currently supported platforms.
Despite the nice showoff of underhanded programming skills - we want Bitcoin to be well-specified. Otherwise, we're clearly in for a bumpy ride:
Note that several other programming languages do not exhibit this behaviour, making new implementations likely to be slower and generally more bogus than Bitcoin Core. For example, Python unexpectedly returns 0 when shifting an integer beyond its size.
==Other solutions==
===Floating-point approximation===
An obvious solution would be to reimplement the shape of the subsidy curve using floating-point approximations, such as simulated annealing or quantitative easing, which have already proven their worth in consensus systems. Unfortunately, since the financial crisis everyone considers numbers with decimal points in them fishy, and integers are not well supported by Javascript.
===Truncation===
An alternative solution would be to represent the total number of bitcoins as a string:
"21000000000000000000000"
and then use string manipulation to remove the rightmost zero every 4 years, give or take a leap-year:
strSubsidy = strSubsidy.substr(0, strSubsidy.size() - 2);
This style relies less heavily on clever C++ and is more familiar to the Core Dev Team who are primarily PHP programmers.
==Proposal==
Instead, how about we stop thinking about long term issues when we'll all be dead (barring near lightspeed travel, cryogenic revival, or other technology— like cryptocurrency— which only exists in science fiction).
A softfork (see BIP16, BIP34, BIP62) will take place on april 1st 2214, permanently setting the subsidy to zero. The result of this will be that the total currency supply will be limited to 42 halfmillion (including the genesis coinbase output, which is not actually spendable).
==Implementation==
An implementation for the reference client can be found on https://github.com/bitcoin/bitcoin/pull/3842 .
==Compatibility==
Given the moderate time frame over which this change is to be implemented, we expect all miners to choose to screw themselves and deploy this change before 2214.
If they don't, and a minority remains on the old code base, a fork may occur. Essentially, they'll be mining fool's gold after that time.
==Acknowledgements==
Thanks to Gregory Maxwell for proposing this solution, and to Mike Hearn for insights into web development. Also thanks to "ditto-b" on github to implement a prototype ahead of time.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0043.mediawiki
================================================
BIP: 43
Layer: Applications
Title: Purpose Field for Deterministic Wallets
Authors: Marek Palatinus
Pavol Rusnak
Status: Deployed
Type: Specification
Assigned: 2014-04-24
==Abstract==
This BIP introduces a "Purpose Field" for use in deterministic wallets
based on algorithm described in BIP-0032 (BIP32 from now on).
==Motivation==
Although Hierarchical Deterministic Wallet structure as described by BIP32
is an important step in user experience and security of the cryptocoin wallets,
the BIP32 specification offers implementers too many degrees of freedom.
Multiple implementations may claim they are BIP32 compatible, but in fact
they can produce wallets with different logical structures making them
non-interoperable. This situation unfortunately renders "BIP32 compatible"
statement rather useless.
==Purpose==
We propose the first level of BIP32 tree structure to be used as "purpose".
This purpose determines the further structure beneath this node.
m / purpose' / *
Apostrophe indicates that BIP32 hardened derivation is used.
We encourage different schemes to apply for assigning a separate BIP number
and use the same number for purpose field, so addresses won't be generated
from overlapping BIP32 spaces.
Purpose codes from 10001 to 19999 are reserved for [[https://github.com/satoshilabs/slips|SLIPs]].
Example: Scheme described in BIP44 should use 44' (or 0x8000002C) as purpose.
Note that m / 0' / * is already taken by BIP32 (default account), which
preceded this BIP.
Not all wallets may want to support the full range of features and possibilities
described in these BIPs. Instead of choosing arbitrary subset of defined features
and calling themselves BIPxx compatible, we suggest that software which needs
only a limited structure should describe such structure in another BIP and use
different "purpose" value.
==Node serialization==
Because this scheme can be used to generate nodes for more cryptocurrencies
at once, or even something totally unrelated to cryptocurrencies, there's no
point in using a special version magic described in section "Serialization
format" of BIP32. We suggest to use always 0x0488B21E for public and 0x0488ADE4
for private nodes (leading to prefixes "xpub" and "xprv" respectively).
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
================================================
FILE: bip-0044.mediawiki
================================================
==Abstract==
This BIP defines a logical hierarchy for deterministic wallets based on an algorithm
described in BIP-0032 (BIP32 from now on) and purpose scheme described in
BIP-0043 (BIP43 from now on).
This BIP is a particular application of BIP43.
==Motivation==
The hierarchy proposed in this paper is quite comprehensive. It allows the handling of
multiple coins, multiple accounts, external and internal chains per account and
millions of addresses per chain.
==Path levels==
We define the following 5 levels in BIP32 path:
Apostrophe in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
===Purpose===
Purpose is a constant set to 44' (or 0x8000002C) following the BIP43 recommendation.
It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
===Coin type===
One master node (seed) can be used for unlimited number of independent
cryptocoins such as Bitcoin, Litecoin or Namecoin. However, sharing the same
space for various cryptocoins has some disadvantages.
This level creates a separate subtree for every cryptocoin, avoiding
reusing addresses across cryptocoins and improving privacy issues.
Coin type is a constant, set for each cryptocoin. Cryptocoin developers may ask
for registering unused number for their project.
The list of already allocated coin types is in the chapter
"Registered coin types" below.
Hardened derivation is used at this level.
===Account===
This level splits the key space into independent user identities,
so the wallet never mixes the coins across different accounts.
Users can use these accounts to organize the funds in the same
fashion as bank accounts; for donation purposes (where all
addresses are considered public), for saving purposes,
for common expenses etc.
Accounts are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Hardened derivation is used at this level.
Software should prevent a creation of an account if a previous account does not
have a transaction history (meaning none of its addresses have been used before).
Software needs to discover all used accounts after importing the seed from
an external source. Such an algorithm is described in "Account discovery" chapter.
===Change===
Constant 0 is used for external chain and constant 1 for internal chain (also
known as change addresses). External chain is used for addresses that are meant
to be visible outside of the wallet (e.g. for receiving payments). Internal
chain is used for addresses which are not meant to be visible outside of the
wallet and is used for return transaction change.
Public derivation is used at this level.
===Index===
Addresses are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Public derivation is used at this level.
==Account discovery==
When the master seed is imported from an external source the software should
start to discover the accounts in the following manner:
# derive the first account's node (index = 0)
# derive the external chain node of this account
# scan addresses of the external chain; respect the gap limit described below
# if no transactions are found on the external chain, stop discovery
# if there are some transactions, increase the account index and go to step 1
This algorithm is successful because software should disallow creation of new
accounts if previous one has no transaction history, as described in chapter
"Account" above.
Please note that the algorithm works with the transaction history, not account
balances, so you can have an account with 0 total coins and the algorithm will
still continue with discovery.
===Address gap limit===
Address gap limit is currently set to 20. If the software hits 20 unused
addresses in a row, it expects there are no used addresses beyond this point
and stops searching the address chain. We scan just the external chains, because
internal chains receive only coins that come from the associated external chains.
Wallet software should warn when the user is trying to exceed the gap limit on
an external chain by generating a new address.
==Registered coin types==
These are the default registered coin types for usage in level 2 of BIP44
described in chapter "Coin type" above.
All these constants are used as hardened derivation.
{|
!index
!hexa
!coin
|-
|0
|0x80000000
|Bitcoin
|-
|1
|0x80000001
|Bitcoin Testnet
|}
This BIP is not a central directory for the registered coin types, please
visit SatoshiLabs that maintains the full list:
[[https://github.com/satoshilabs/slips/blob/master/slip-0044.md|SLIP-0044 : Registered coin types for BIP-0044]]
To register a new coin type, an existing wallet that implements the standard
is required and a pull request to the above file should be created.
==Examples==
{|
!coin
!account
!chain
!address
!path
|-
|Bitcoin
|first
|external
|first
|m / 44' / 0' / 0' / 0 / 0
|-
|Bitcoin
|first
|external
|second
|m / 44' / 0' / 0' / 0 / 1
|-
|Bitcoin
|first
|change
|first
|m / 44' / 0' / 0' / 1 / 0
|-
|Bitcoin
|first
|change
|second
|m / 44' / 0' / 0' / 1 / 1
|-
|Bitcoin
|second
|external
|first
|m / 44' / 0' / 1' / 0 / 0
|-
|Bitcoin
|second
|external
|second
|m / 44' / 0' / 1' / 0 / 1
|-
|Bitcoin
|second
|change
|first
|m / 44' / 0' / 1' / 1 / 0
|-
|Bitcoin
|second
|change
|second
|m / 44' / 0' / 1' / 1 / 1
|-
|Bitcoin Testnet
|first
|external
|first
|m / 44' / 1' / 0' / 0 / 0
|-
|Bitcoin Testnet
|first
|external
|second
|m / 44' / 1' / 0' / 0 / 1
|-
|Bitcoin Testnet
|first
|change
|first
|m / 44' / 1' / 0' / 1 / 0
|-
|Bitcoin Testnet
|first
|change
|second
|m / 44' / 1' / 0' / 1 / 1
|-
|Bitcoin Testnet
|second
|external
|first
|m / 44' / 1' / 1' / 0 / 0
|-
|Bitcoin Testnet
|second
|external
|second
|m / 44' / 1' / 1' / 0 / 1
|-
|Bitcoin Testnet
|second
|change
|first
|m / 44' / 1' / 1' / 1 / 0
|-
|Bitcoin Testnet
|second
|change
|second
|m / 44' / 1' / 1' / 1 / 1
|}
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
================================================
FILE: bip-0045.mediawiki
================================================
BIP: 45
Layer: Applications
Title: Structure for Deterministic P2SH Multisignature Wallets
Authors: Manuel Araoz
Ryan X. Charles
Matias Alejo Garcia
Status: Complete
Type: Specification
Assigned: 2014-04-25
==Abstract==
This BIP defines a structure for hierarchical deterministic P2SH multi-party
multi-signature wallets (HDPM wallets from now on) based on the algorithm
described in BIP-0032 (BIP32 from now on) and purpose scheme described in
BIP-0043 (BIP43 from now on).
This BIP is a particular application of BIP43.
==Motivation==
The structure proposed in this document allows for standard ways to create,
use, import, and store HDPM wallets. It allows to handle multiple parties sharing
an m-of-n wallet, on the following assumptions:
* n parties share an m-of-n wallet.
* Each party generates their master private keys independently.
* Multisig P2SH is used for all addresses.
* BIP32 is used to derive public keys, then create a multisig script, and the corresponding P2SH address for that script.
* Address generation should not require communication between parties. (Thus, all parties must be able to generate all public keys)
* Transaction creation and signing requires communication between parties.
This BIP will allow interoperability between various HDPM wallet implementations.
==Specification==
We define the following levels in BIP32 path:
m / purpose' / cosigner_index / change / address_index
Apostrophe in the path indicates that BIP32 hardened derivation is used.
Each level has special meaning described in the chapters below.
===Purpose===
Purpose is a constant set to 45, following the BIP43 recommendation.
It indicates that the subtree of this node is used according to this specification.
m / 45' / *
Hardened derivation is used at this level.
===Cosigner Index===
The index of the party creating a P2SH multisig address. The indices can
be determined independently by lexicographically sorting the purpose public
keys of each cosigner. Each cosigner creates addresses on its own branch,
even though they have independent extended master public key, as explained
in the "Address generation" section.
Note that the master public key is not shared amongst the cosigners. Only the
hardened purpose extended public key is shared, and this is what is used to
derive child extended public keys.
Software should only use indices corresponding to each of the N cosigners
sequentially. For example, for a 2-of-3 HDPM wallet, having the following
purpose public keys:
it should use m / 45 ' / 0 / * for
039863fb5f07b667d9b1ca68773c6e6cdbcac0088ffba9af46f6f6acd153d44463,
m / 45 ' / 1 / * for
03a473275a750a20b7b71ebeadfec83130c014da4b53f1c4743fcf342af6589a38,
and m / 45 ' / 2 / * for
03f76588e06c0d688617ef365d1e58a7f1aa84daa3801380b1e7f12acc9a69cd13,
as dictated by their lexicographical order.
Software needs to discover all used indexes when importing the seed from
an external source. Such algorithm is described in "Address discovery" chapter.
Non-hardened derivation is used at this level.
===Change===
Constant 0 is used for external chain and constant 1 for internal chain (also
known as change addresses). External chain is used for addresses that are meant
to be visible outside of the wallet (e.g. for receiving payments). Internal
chain is used for addresses which are not meant to be visible outside of the
wallet and is used for return transaction change.
For example, if cosigner 2 wants to generate a change address, he would use
m / 45 ' / 2 / 1 / *, and m / 45 ' / 2 / 0 / * for a receive
address.
Non-hardened derivation is used at this level.
===Address Index===
Addresses are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Non-hardened derivation is used at this level.
===HDPM Wallet High-level Description===
Each party generates their own extended master keypair and shares the
extended purpose' public key with the others, which is stored encrypted.
Each party can generate any of the other's derived public keys, but only
his own private keys.
===Address Generation Procedure===
When generating an address, each party can independently generate the N needed
public keys. They do this by deriving the public key in each of the different
trees, but using the same path. They can then generate the multisig script (by
lexicographically sorting the public keys) and the corresponding p2sh address.
In this way, each path corresponds to an address, but the public keys for that
address come from different trees.
====Receive address case====
Each cosigner generates addresses only on his own branch. One of the n
cosigners wants to receive a payment, and the others are offline. He
knows the last used index in his own branch, because only he generates
addresses there. Thus, he can generate the public keys for all of the
others using the next index, and calculate the needed script for the address.
Example: Cosigner #2 wants to receive a payment to the shared wallet. His last
used index on his own branch is 4. Then, the path for the next receive
address is m/45'/2/0/5. He uses this same path in all of the cosigners
trees to generate a public key for each one, and from that he gets the new
p2sh address.
====Change address case====
Again, each cosigner generates addresses only on his own branch. One of the
n cosigners wants to create an outgoing payment, for which he'll need a change
address. He generates a new address using the same procedure as above, but
using a separate index to track the used change addresses.
Example: Cosigner #5 wants to send a payment from the shared wallet, for which
he'll need a change address. His last used change index on his own branch is
11. Then, the path for the next change address is m/45'/5/1/12. He uses
this same path in all of the cosigners trees to generate a public key for each
one, and from that he gets the new p2sh address.
===Transaction creation and signing===
When creating a transaction, first one of the parties creates a Transaction
Proposal. This is a transaction that spends some output stored in any of the
p2sh multisig addresses (corresponding to any of the copayers' branches).
This proposal is sent to the other parties, who decide if they want to sign.
If they approve the proposal, they can generate their needed private key for
that specific address (using the same path that generated the public key in
that address, but deriving the private key instead), and sign it. Once the
proposal reaches m signatures, any cosigner can broadcast it to the network,
becoming final. The specifics of how this proposal is structured, and the
protocol to accept or reject it, belong to another BIP, in my opinion.
===Address discovery===
When the master seed is imported from an external source the software should
start to discover the addresses in the following manner:
# for each cosigner:
# derive the cosigner's node (m / 45' / cosigner_index)
# for both the external and internal chains on this node (m / 45' / cosigner_index / 0 and m / 45' / cosigner_index / 1):
# scan addresses of the chain; respect the gap limit described below
Please note that the algorithm uses the transaction history, not address
balances, so even if the address has 0 coins, the program should continue with discovery.
Opposite to BIP44, each cosigner branch needs to be checked,
even if the earlier ones don't have transactions
===Address gap limit===
Address gap limit is currently set to 20. If the software hits 20 unused
addresses (no transactions associated with that address) in a row, it expects
there are no used addresses beyond this point and stops searching the address chain.
Wallet software should warn when user is trying to exceed the gap limit on
an external chain by generating a new address.
===Rationale===
This structure provides a general way of doing HDPM wallets between m-of-n
parties. Here are some explanations about the design decisions made.
The reason for using separate branches for each cosigner is we don't want
two of them generating the same address and receiving simultaneous payments
to it. The ideal case is that each address receives at most one payment,
requested by the corresponding cosigner.
==Examples==
{|
!cosigner_index
!change
!address_index
!path
|-
|first
|receive
|first
| m / 45' / 0 / 0 / 0
|-
|first
|receive
|second
| m / 45' / 0 / 0 / 1
|-
|first
|receive
|fifth
| m / 45' / 0 / 0 / 4
|-
|first
|change
|first
| m / 45' / 0 / 1 / 0
|-
|first
|change
|second
| m / 45' / 0 / 1 / 1
|-
|second
|receive
|first
| m / 45' / 1 / 0 / 0
|-
|third
|change
|tenth
| m / 45' / 2 / 1 / 9
|}
==Compatible wallets==
* [[https://copay.io|Copay wallet]] ([[https://github.com/bitpay/copay|source]])
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[https://www.mail-archive.com/bitcoin-development@lists.sourceforge.net/msg05156.html|Original mailing list discussion]]
================================================
FILE: bip-0046.mediawiki
================================================
== Abstract ==
This BIP defines the derivation scheme for HD wallets which create timelocked addresses used for creating fidelity bonds. It also gives advice to wallet developers on how to use fidelity bonds to sign over messages, such as certificates, which are needed when using fidelity bonds that are stored offline.
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
== Motivation ==
Fidelity bonds are used to resist sybil attacks in certain decentralized anonymous protocols. They are created by locking up bitcoins using the `OP_CHECKLOCKTIMEVERIFY` opcode.
Having a common derivation scheme allows users of wallet software to have a backup of their fidelity bonds by storing only the HD seed and a reference to this BIP. Importantly the user does not need to backup any timelock values.
We largely use the same approach used in BIPs 49, 84 and 86 for ease of implementation.
This allows keeping the private keys of fidelity bonds in cold storage, which increases the sybil resistance of a system without hot wallet risk.
== Backwards Compatibility ==
This BIP is not backwards compatible by design as described in the Considerations section of [[bip-0049.mediawiki|BIP 49]]. An incompatible wallet will not discover fidelity bonds at all and the user will notice that something is wrong.
== Background ==
=== Fidelity bonds ===
A fidelity bond is a mechanism where bitcoin value is deliberately sacrificed to make a cryptographic identity expensive to obtain. A way to create a fidelity bond is to lock up bitcoins by sending them to a timelocked address. The valuable thing being sacrificed is the time-value-of-money.
The sacrifice must be done in a way that can be proven to a third party. This proof can be made by showing the UTXO outpoint, the address redeemscript and a signature which signs a message using the private key corresponding to the public key in the redeemscript.
The sacrificed value is an objective measurement that can't be faked and which can be verified by anybody (just like, for example PoW mining). Sybil attacks can be made very expensive by forcing a hypothetical sybil attacker to lock up many bitcoins for a long time. JoinMarket implements fidelity bonds for protection from sybil attackers. At the time of writing over 600 BTC in total have been locked up with some for many years. Their UTXOs and signatures have been advertised to the world as proof. We can calculate that for a sybil attacker to succeed in unmixing all the CoinJoins, they would have to lock up over 100k BTC for several years.
=== Fidelity bonds in cold storage ===
To allow for holding fidelity bonds in cold storage, there is an intermediate keypair called the certificate.
UTXO key ---signs---> certificate ---signs---> endpoint
Where the endpoint might be a IRC nickname or Tor onion hostname. The certificate keypair can be kept online and used to prove ownership of the fidelity bond. Even if the hot wallet private keys are stolen, the coins in the timelocked address will still be safe, although the thief will be able to impersonate the fidelity bond until the expiry.
== Rationale ==
It is useful for the user to avoid having to keep a record of the timelocks in the time-locked addresses. So only a limited small set of timelocks are defined by this BIP. This way the user must only store their seed phrase, and knowledge that they have coins stored using this BIP standard. The user doesn't need to remember or store any dates.
This standard is already implemented and deployed in JoinMarket. As most changes would require a protocol change of a live system, there is limited scope for changing this standard in review. This BIP is more about documenting something which already exists, warts and all.
== Specifications ==
This BIP defines the two needed steps to derive multiple deterministic addresses based on a [[bip-0032.mediawiki|BIP 32]] master private key. It also defines the format of the certificate that can be signed by the deterministic address key.
=== Public key derivation ===
To derive a public key from the root account, this BIP uses a similar account-structure as defined in BIP [[bip-0084.mediawiki|44]] but with change set to 2.
m / 84' / 0' / 0' / 2 / index
A key derived with this derivation path pattern will be referred to as derived_key further
in this document.
For index, addresses are numbered from 0 in a sequentially increasing manner with a fixed upper bound: The index only goes up to 959 inclusive. Only 960 addresses can be derived for a given BIP32 master key. Furthermore there is no concept of a gap limit, instead wallets must always generate all 960 addresses and check for all of them if they have a balance and history.
=== Timelock derivation ===
The timelock used in the time-locked address is derived from the index. The timelock is a unix time. It is always at the start of the first second at the beginning of the month (see [[#Test vectors|Test vectors]]). The index counts upwards the months from January 2020, ending in December 2099. At 12 months per year for 80 years this totals 960 timelocks. Note that care must be taken with the year 2038 problem on 32-bit systems.
year = 2020 + index // 12
month = 1 + index % 12
=== Address derivation ===
To derive the address from the above calculated public key and timelock, we create a witness script which locks the funds until the timelock, and then checks the signature of the derived_key. The witness script is hashed with SHA256 to produce a 32-byte hash value that forms the witness program in the output script of the P2WSH address.
witnessScript: OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG
witness:
scriptSig: (empty)
scriptPubKey: 0 <32-byte-hash>
(0x0020{32-byte-hash})
=== Message signing ===
In order to support signing of certificates, implementers should support signing ASCII messages.
The certificate message is defined as `"fidelity-bond-cert" || "|" || cert_pubkey || "|" || cert_expiry`.
The certificate expiry `cert_expiry` is the number of the 2016-block period after which the certificate is no longer valid. For example, if `cert_expiry` is 330 then the certificate will become invalid after block height 665280 (:=330x2016). The purpose of the expiry parameter is so that in case the certificate keypair is compromised, the attacker can only impersonate the fidelity bond for a limited amount of time.
A certificate message can be created by another application external to this standard. It is then prepended with the string `0x18 || "Bitcoin Signed Message:\n"` and a byte denoting the length of the certificate message. The whole thing is then signed with the private key of the derived_key. This part is identical to the "Sign Message" function which many wallets already implement.
Almost all wallets implementing this standard can use their already-existing "Sign Message" function to sign the certificate message. As the certificate message itself is always an ASCII string, the wallet may not need to specially implement this section at all but just rely on users copypasting their certificate message into the already-existing "Sign Message" user interface. This works as long as the wallet knows how to use the private key of the timelocked address for signing messages.
It is most important for wallet implementations of this standard to support creating the certificate signature. Verifying the certificate signature is less important.
== Test vectors ==
mnemonic = abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
rootpriv = xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu
rootpub = xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8
// First timelocked address = m/84'/0'/0'/2/0
derived private_key = L2tQBEdhC48YLeEWNg3e4msk94iKfyVa9hdfzRwUERabZ53TfH3d
derived public_key = 02a1b09f93073c63f205086440898141c0c3c6d24f69a18db608224bcf143fa011
unix locktime = 1577836800
string locktime = 2020-01-01 00:00:00
redeemscript = 0400e10b5eb1752102a1b09f93073c63f205086440898141c0c3c6d24f69a18db608224bcf143fa011ac
scriptPubKey = 0020bdee9515359fc9df912318523b4cd22f1c0b5410232dc943be73f9f4f07e39ad
address = bc1qhhhf29f4nlyalyfrrpfrknxj9uwqk4qsyvkujsa7w0ulfur78xkspsqn84
// Test certificate using the first timelocked address
// Note that as signatures contains a random nonce, it might not be exactly the same when your code generates it
// p2pkh address is the p2pkh address corresponding to the derived public key, it can be used to verify the message
// signature in any wallet that supports Verify Message.
// As mentioned before, it is more important for implementers of this standard to support signing such messages, not verifying them
message = fidelity-bond-cert|020000000000000000000000000000000000000000000000000000000000000001|375
address = bc1qhhhf29f4nlyalyfrrpfrknxj9uwqk4qsyvkujsa7w0ulfur78xkspsqn84
p2pkh address = 16vmiGpY1rEaYnpGgtG7FZgr2uFCpeDgV6
signature = H2b/90XcKnIU/D1nSCPhk8OcxrHebMCr4Ok2d2yDnbKDTSThNsNKA64CT4v2kt+xA1JmGRG/dMnUUH1kKqCVSHo=
// 2nd timelocked address = m/84'/0'/0'/2/1
derived private_key = KxctaFBzetyc9KXeUr6jxESCZiCEXRuwnQMw7h7hroP6MqnWN6Pf
derived public_key = 02599f6db8b33265a44200fef0be79c927398ed0b46c6a82fa6ddaa5be2714002d
unix locktime = 1580515200
string locktime = 2020-02-01 00:00:00
redeemscript = 0480bf345eb1752102599f6db8b33265a44200fef0be79c927398ed0b46c6a82fa6ddaa5be2714002dac
scriptPubKey = 0020b8f898643991608524ed04e0c6779f632a57f1ffa3a3a306cd81432c5533e9ae
address = bc1qhrufsepej9sg2f8dqnsvvaulvv490u0l5w36xpkds9pjc4fnaxhq7pcm4h
// timelocked address after the year 2038 = m/84'/0'/0'/2/240
derived private_key = L3SYqae23ZoDDcyEA8rRBK83h1MDqxaDG57imMc9FUx1J8o9anQe
derived public_key = 03ec8067418537bbb52d5d3e64e2868e67635c33cfeadeb9a46199f89ebfaab226
unix locktime = 2208988800
string locktime = 2040-01-01 00:00:00
redeemscript = 05807eaa8300b1752103ec8067418537bbb52d5d3e64e2868e67635c33cfeadeb9a46199f89ebfaab226ac
scriptPubKey = 0020e7de0ad2720ae1d6cc9b6ad91af57eb74646762cf594c91c18f6d5e7a873635a
address = bc1qul0q45njptsadnymdtv34at7karyva3v7k2vj8qc7m2702rnvddq0z20u5
// last timelocked address = m/84'/0'/0'/2/959
derived private_key = L5Z9DDMnj5RZMyyPiQLCvN48Xt7GGmev6cjvJXD8uz5EqiY8trNJ
derived public_key = 0308c5751121b1ae5c973cdc7071312f6fc10ab864262f0cbd8134f056166e50f3
unix locktime = 4099766400
string locktime = 2099-12-01 00:00:00
redeemscript = 0580785df400b175210308c5751121b1ae5c973cdc7071312f6fc10ab864262f0cbd8134f056166e50f3ac
scriptPubKey = 0020803268e042008737cf439748cbb5a4449e311da9aa64ae3ac56d84d059654f85
address = bc1qsqex3czzqzrn0n6rjayvhddygj0rz8df4fj2uwk9dkzdqkt9f7zs5c493u
// Test certificate and endpoint signing using the first timelocked address = m/84'/0'/0'/2/0 (see above)
bond private_key = L2tQBEdhC48YLeEWNg3e4msk94iKfyVa9hdfzRwUERabZ53TfH3d
bond p2pkh address = 16vmiGpY1rEaYnpGgtG7FZgr2uFCpeDgV6
certificate private_key = KyZpNDKnfs94vbrwhJneDi77V6jF64PWPF8x5cdJb8ifgg2DUc9d
certificate public_key = 0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c
certificate p2pkh address = 1JaUQDVNRdhfNsVncGkXedaPSM5Gc54Hso
certificate message = fidelity-bond-cert|0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c|375
certificate signature = INOP3cB9UW7F1e1Aglj8rI9QhnyxmgWDEPt+nOMvl7hJJne7rH/KCNDYvLiqNuB9qWaWUojutjRsgPJrvyDQ+0Y=
// example endpoint signing two IRC nicknames (used in JoinMarket)
endpoint message = J54LS6YyJPoseqFS|J55VZ6U6ZyFDNeuv
endpoint signature = H18WE4MugDNoWZIf9jU0njhQptdUyBDUf7lToG9bpMKmeJK0lOoABaDs5bKnohSuZ0e9gnSco5OL9lXdKU7gP5E=
Code generating these test vectors can be found here: https://github.com/chris-belcher/timelocked-addresses-fidelity-bond-bip-testvectors
== Reference ==
* [[https://gist.github.com/chris-belcher/18ea0e6acdb885a2bfbdee43dcd6b5af/|Design for improving JoinMarket's resistance to sybil attacks using fidelity bonds]]
* [[https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/fidelity-bonds.md|JoinMarket fidelity bonds doc page]]
* [[bip-0065.mediawiki|BIP65 - OP_CHECKLOCKTIMEVERIFY]]
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
* [[bip-0049.mediawiki|BIP49 - Derivation scheme for P2WPKH-nested-in-P2SH based accounts]]
* [[bip-0084.mediawiki|BIP84 - Derivation scheme for P2WPKH based accounts]]
* [[bip-0086.mediawiki|BIP86 - Key Derivation for Single Key P2TR Outputs]]
================================================
FILE: bip-0047.mediawiki
================================================
RECENT CHANGES:
* (15 Feb 2021) Finalize specification
* (28 Sep 2017) Adjust text to match test vectors
* (19 Apr 2016) Define version 2 payment codes
==Status==
This BIP can be considered final in terms of enabling compatibility with wallets that implement version 1 and version 2 reusable payment codes, however future developments of the reusable payment codes specification will not be distributed via the BIP process.
The Open Bitcoin Privacy Project RFC repo should be consulted for specifications related to version 3 or higher payment codes: https://github.com/OpenBitcoinPrivacyProject/rfc
==Abstract==
This BIP defines a technique for creating a payment code which can be publicly advertised and associated with a real-life identity without creating the loss of security or privacy inherent to P2PKH address reuse.
This BIP is a particular application of BIP43 and is intended to supplement HD wallets which implement BIP44.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
==Motivation==
Payment codes add identity information to transactions which is useful in a merchant-customer interaction while protecting the privacy of users. Payment codes provide the privacy benefits of Darkwallet-style Stealth Addresses to SPV clients without requiring the assistance of a trusted full node and while greatly reducing reliance on blockchain storage.
==Path levels==
We define the following 3 levels in BIP32 path:
m / purpose' / coin_type' / identity'
The child keys derived from an identity are used in different ways:
m / purpose' / coin_type' / identity' / 0
The 0th (non-hardened) child is the notification key.
m / purpose' / coin_type' / identity' / 0 through 2147483647
These (non-hardened) keypairs are used for ECDH to generate deposit addresses.
m / purpose' / coin_type' / identity' / 0' through 2147483647'
These (hardened) keypairs are ephemeral payment codes.
Apostrophe in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
===Purpose===
Purpose is a constant set to 47' (or 0x8000002F) following the BIP43 recommendation. It indicates that the subtree of this node is used according to this specification.
===Coin type===
The coin type field is identical to the same field in BIP44
Hardened derivation is used at this level.
===Identity===
The identity derivation level produces an extended public key and its associated extended private key.
When the extended public key at this level is combined with the metadata specified in the Representation section below, the resulting entity is called a "payment code."
This derivation level is equivalent to the Account level in BIP-44. Wallets SHOULD treat payment codes as intrinsically part of the BIP-44 account at the same index and create payment codes and accounts as pairs.
For example, the payment code created represented by (m / 47' / 0' / 0') is part of the account represented by (m / 44' / 0' / 0').
The second account in a wallet consists of the new account/payment code pair created by using an index of 1 in as the account/identity level of both paths.
Incoming payments received via this specification are equivalent to payments received to BIP-44 addresses, and unspent outputs from both types of addresses can be used as inputs in the same outgoing transaction.
Hardened derivation is used at this level.
Except where noted, all keys derived from a payment code use the public derivation method.
==Versions==
Payment codes contain a version byte which identifies a specific set of behavior.
Unless otherwise specified, payment codes of different versions are interoperable. If Alice uses a version x payment code, and Bob uses a version y payment code, they can still send and receive transactions between each other.
Currently specified versions:
* Version 1
** Address type: P2PKH
** Notification type: address
* Version 2
** Address type: P2PKH
** Notification type: bloom-multisig
===Recommended Versions===
* Wallets which have bloom filtering capabilities SHOULD create version 2 payment codes instead of version 1 payment codes.
* Version 1 payment codes are only recommended for wallets which lack access to bloom filtering capability.
==Version 1==
===Representation===
====Binary Serialization====
A payment code contains the following elements:
* Byte 0: version. required value: 0x01
* Byte 1: features bit field. All bits must be zero except where specified elsewhere in this specification
** Bit 0: Bitmessage notification
** Bits 1-7: reserved
* Byte 2: sign. required value: 0x02 or 0x03
* Bytes 3 - 34: x value, must be a member of the secp256k1 group
* Bytes 35 - 66: chain code
* Bytes 67 - 79: reserved for future expansion, zero-filled unless otherwise noted
====Base58 Serialization====
When a payment code is presented to the user, it SHOULD be presented encoded in Base58Check form.
* The version byte is: 0x47 (produces a "P" as the first character of the serialized form)
* The payload is the binary serialization of the payment code
===Protocol===
In the following examples, Alice and Bob are identities with a corresponding payment codes. Alice initiates a Bitcoin transaction, and Bob is the recipient of the transaction.
It is assumed that Alice can easily obtain Bob's payment code via a suitable method outside the scope of the payment code protocol.
====Definitions====
* Payment code: an extended public key and associated metadata which is associated with a particular identity/account
* Notification address: the P2PKH address associated with the 0th public key derived from a payment code
* Notification transaction: a transaction which sends an output to a notification address which includes an embedded payment code
* Designated input: the first input in the notification transaction which exposes an secp256k1 pubkey in either its signature script, or in the redeem script or pubkey script of the output being spent
* Designated pubkey: the first secp256k1 pubkey pushed to the stack during script execution for the designated input
* Outpoint: the specific output of a previous transaction which is being spent. See the Reference section for the binary serialization
====Notification Transaction====
Prior to the first time Alice initiates a transaction to Bob, Alice MUST inform Bob of her payment code via the following procedure:
Note: this procedure is used if Bob uses a version 1 payment code (regardless of the version of Alice's payment code). If Bob's payment code is not version 1, see the appropriate section in this specification.
# Alice constructs a transaction which sends a small quantity of bitcoins to Bob's notification address (notification transaction)
## The inputs selected for this transaction MUST NOT be easily associated with Alice's notification address
# Alice derives a unique shared secret using ECDH:
## Alice selects the private key corresponding to the designated pubkey:
a
## Alice selects the public key associated with Bob's notification address:
B, where B = bG
## Alice calculates a secret point:
S = aB
## Alice calculates a 64 byte blinding factor:
s = HMAC-SHA512(o, x)
### "x" is the x value of the secret point
### "o" is the outpoint being spent by the designated input
# Alice serializes her payment code in binary form.
# Alice renders her payment code (P) unreadable to anyone except Bob:
## Replace the x value with x':
x' = x XOR (first 32 bytes of s)
## Replace the chain code with c':
c' = c XOR (last 32 bytes of s)
# Alice adds an OP_RETURN output to her transaction which consists of P.
# Bob watches for any transactions which create an output at his notification address.
# When a transaction is received, the client examines it to determine if it contains a standard OP_RETURN output with an 80 byte payload (notification transactions).
# If the first byte of the payload in a notification transaction is 0x01:
## Bob selects the designated pubkey:
A, where A = aG
## Bob selects the private key associated with his notification address:
b
## Bob calculates a secret point:
S = bA
## Bob calculates the blinding factor:
s = HMAC-SHA512(x, o)
### "x" is the x value of the secret point
### "o" is the outpoint being spent by the designated input.
## Bob interprets the 80 byte payload as a payment code, except:
### Replace the x value with x':
x' = x XOR (first 32 bytes of s)
### Replace the chain code with c':
c' = c XOR (last 32 bytes of s)
## If the updated x value is a member of the secp256k1 group, the payment code is valid.
## If the updated x value is not a member of the secp256k1 group, the payment code is ignored.
Now that Bob's client has received Alice's payment code, it is possible for Alice to send payments (up to 232 payments) to Bob.
Alice will never again need to send a notification transaction to Bob.
Bitcoins received via notification transactions require special handling in order to avoid privacy leaks:
# The value of outputs received to notification addresses MUST NOT be displayed to the user as part of their spendable balance.
# Outputs received to notification addresses MUST NOT be used as inputs for any transaction that involve ECDH calculations using any of the user's payment codes.
# Outputs received to notification addresses MAY be passed through a mixing service before being added to the user's spendable balance.
# Outputs received to notification addresses MAY be donated to miners using dust-b-gone or an equivalent procedure.
=====Standard Notification Transaction Scripts=====
Alice SHOULD use an input script in one of the following standard forms to expose a public key, and compliant applications SHOULD recognize all of these forms.
* P2PK (pay to pubkey)
* P2PKH (pay to pubkey hash)
* Multisig (bare multisig, without P2SH)
* a script which spends any of the above script forms via P2SH (pay to script hash)
Compatible wallets MAY provide a method for a user to manually specify the public key associated with a notification transaction in order to recover payment codes sent via non-standard notification transactions.
=====Post-Notification Privacy Considerations=====
Incautious handling of change outputs from notification transactions may cause unintended loss of privacy.
The recipient of a transaction which spends a change output from a prior notification transaction will learn about the potential connection between the sender and the recipient of the notification transaction.
The following actions are recommended to reduce this risk:
* Wallets which support mixing SHOULD mix change outputs from notification transactions prior to spending them
* Wallets which do not support mixing MAY simulate mixing by creating a transaction which spends the change output to the next external BIP44 address
====Sending====
# Each time Alice wants to initiate a transaction to Bob, Alice derives a unique P2PKH address for the transaction using ECDH as follows:
## Alice selects the 0th private key derived from her payment code:
a
## Alice selects the next unused public key derived from Bob's payment code, starting from zero:
B, where B = bG
### The "next unused" public key is based on an index specific to the Alice-Bob context, not global to either Alice or Bob
## Alice calculates a secret point:
S = aB
## Alice calculates a scalar shared secret using the x value of S:
s = SHA256(Sx)
### If the value of s is not in the secp256k1 group, Alice MUST increment the index used to derive Bob's public key and try again.
## Alice uses the scalar shared secret to calculate the ephemeral public key used to generate the P2PKH address for this transaction:
B' = B + sG
# Bob is watching for incoming payments on B' ever since he received the notification transaction from Alice.
## Bob calculates n shared secrets with Alice, using the 0th public key derived from Alice's payment code, and private keys 0 - n derived from Bob's payment code, where n is his desired lookahead window.
## Bob calculates the ephemeral deposit addresses using the same procedure as Alice:
B' = B + sG
## Bob calculate the private key for each ephemeral address as:
b' = b + s
====Refunds====
Because Bob learns Alice's payment code as part of the process of receiving a payment, Bob has all the information he needs in order to send a refund to Alice.
A refund transaction is identical to a payment transactions, with only the roles of the participants switches.
Bob MUST send a notification transaction to Alice prior to the first time he sends funds to Alice, even if he has received transactions from her in the past.
====Anonymous Payments====
If Alice does not want her payment to Bob to be associated with her identity, she generates an ephemeral payment code to use for the transaction.
* Ephemeral payment codes are the hardened children of a payment code, starting from an index of zero.
* An ephemeral payment code SHOULD only be used for a single outgoing payment.
* The notification address of an ephemeral payment code MUST be monitored for notification transactions in order to detect incoming refund payments
* The correspondence between BIP44 accounts and ephemeral payment codes is 1:many
====Cold Storage====
* Unlike traditional watching-only wallets, those associated with payment codes held in cold storage can not detect incoming payments immediately.
* When the watching-only wallet detects an incoming notification transaction, it packages the transaction in an implementation-specific format suitable for transfer to the offline device.
* The offline device recovers the payment code, then pre-generates a large number of relevant keypairs (example: 10000) in order to minimize the need for air gap round trips.
* The offline device then packages the relevant public keys in an implementation-specific format suitable for transfer to the online device.
* The online device can then watch for incoming payments using a suitable lookahead window.
* If the lookahead window reaches the end of the pre-generated public keys, the user must generate more keys on the offline device and transfer them to the online device.
====Wallet Recovery====
Normal operation of a payment code-enabled wallet can be performed by an SPV client and does not require access to a complete copy of the blockchain.
Recovering a wallet from a seed, however, does require access to a fully-indexed blockchain.
The required data may be obtained from copy of the blockchain under the control of the user, or via a publicly-queryable blockchain explorer.
When querying a public blockchain explorer, wallets SHOULD connect to the explorer through Tor (or equivalent) and SHOULD avoid grouping queries in a manner that associates ephemeral addresses with each other.
Previously-spendable funds will generally not be lost or become inaccessible after a recovery from a seed, but all information regarding previous outgoing payments will be lost.
In order to recover received funds from a seed, the wallet must obtain every notification it has ever received to its notification address, including all spent transactions. It then re-establishes its lookahead window for each subchain by scanning every derived address sequentially until it locates a contiguous block of unused addresses of a user-specified length.
The metadata which a wallet must store to properly process outgoing transactions consists of:
# A list of every payment code to which the identity has sent a notification transaction.
## This list is lost if a wallet must be recovered from a seed.
## The recovered wallet MUST send notification transactions as if it was a newly-created wallet
# The index value corresponding to the next unused pubkey for each payment code on the previous list
## This value can be recovered by checking each ephemeral deposit address in sequence for transactions.
## Wallets MAY use a lookahead window capable of detecting gaps in the address sequence during this recovery operation.
# The index value of the next unused ephemeral payment code.
## Recovering all incoming funds associated with ephemeral payment codes with 100% certainty requires exhausting the entire 232 address space of potential ephemeral payment codes.
### In most cases, less than 100% certainty is acceptable as long as a fallback "deep scan" is available as an option to the user.
## The wallet checks the notification address for each ephemeral payment code for notification transactions in order to recover associated funds.
## Since most ephemeral payment codes will not receive a refund transaction wallets SHOULD use a large lookahead window for this recovery operation.
## The recovered value MUST be chosen as a number higher than any ephemeral payment code which has received a notification transaction.
===Wallet Sharing===
Wallets using payment codes generally should not be shared across multiple devices, given the need to synchronize metadata between each instance.
If wallets are shared between devices without a synchronization mechanism, undesirable address reuse can occur.
Wallets may perform an OPTIONAL check for existing transactions to an ephemeral deposit addresses prior to sending a transaction by checking a local copy of the blockchain or querying a public blockchain explorer via Tor or equivalent.
===Alternate Notification Methods===
In order to ensure that no funds will be lost in the event the recipient must recover their wallet from a seed, the sender MUST send a notification transaction the first time the sender interacts with a particular recipient.
A recipient MAY choose to designate alternate notification methods which the sender may use in addition to a notification transaction.
If the recipient specifies an alternate notification method, a compliant implementation MAY refrain from continually monitoring the notification address and SHOULD check the notification address periodically to detect payments sent by users who can not employ the alternate method.
A recipient specifies their preference for alternate notification by setting the appropriate bits in the feature byte of their payment code.
===Bitmessage Notification===
A recipient which prefers to receive notifications via Bitmessage indicates this preference by:
* Setting bit 0 of the features byte to 1
* Setting byte 67 of the serialized payment code to the desired Bitmessage address version
* Setting byte 68 of the serialized payment code to the desired Bitmessage stream number
The sender uses this information to construct a valid notification Bitmessage address:
# Derive a Bitmessage signing key as:
B = payment code / 0 / 0
# Initialize a counter at 1:
n
# Derive a candidate encryption key as:
B' = payment code / 0 / n
# If the combination of B and B` do not form a valid Bitmessage address, increment n by one and try again
# Use the address version, signing key, encryption key, and stream number to construct a Bitmessage address per the Bitmessage protocol
The sender transmits their payment code in base58 form to the calculated Bitmessage address.
In order to use Bitmessage notification, the recipient must have a Bitmessage client which listens at the address which the senders will derive and is capable of relaying received payment codes to the Bitcoin wallet.
==Version 2==
Version 2 payment codes behave identifically to version 1 payment codes, except as modified below.
===Representation===
====Binary Serialization====
* Byte 0: version. required value: 0x02
===Protocol===
====Definitions====
* Notification change output: the change output from a notification transaction which resides in the sender's wallet, but can be automatically located by the intended recipient
* Payment code identifier: a 33 byte representation of a payment code constructed by prepending 0x02 to the SHA256 hash of the binary serialization of the payment code
====Notification Transaction====
Note: this procedure is used if Bob uses a version 2 payment code (regardless of the version of Alice's payment code). If Bob's payment code is not version 2, see the appropriate section in this specification.
# Construct a notification transaction as per the version 1 instructions, except do not create the output to Bob's notification address
# Create a notification change address as follows:
## Obtain the pubkey corresponding to the next change address
## Construct a multisig output in the form:
OP_1 OP_2 OP_CHECKMULTISIG
The relative ordering of the payment code identifier and change address pubkey in the above script MAY be randomized
Bob detects notification transactions by adding his payment code identifier to his bloom filter.
# When the filter returns a notification transaction, the sender's payment code is unblinded using the same procedure as for version 1 notification transactions.
Alice's wallet should spend the notification change output at the next appropriate opportunity.
==Test Vectors==
* [[https://gist.github.com/SamouraiDev/6aad669604c5930864bd|BIP47 Reusable Payment Codes Test Vectors]]
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
* [[https://bitcoin.org/en/developer-reference#outpoint|Outpoint]]
* [[https://github.com/petertodd/dust-b-gone|dust-b-gone]]
* [[https://en.bitcoin.it/wiki/Base58Check_encoding|Base58Check encoding]]
* [[https://bitmessage.org/bitmessage.pdf|Bitmessage]]
* [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-April/007812.html|Mailing list discussion]]
================================================
FILE: bip-0048.mediawiki
================================================
BIP: 48
Layer: Applications
Title: Multi-Script Hierarchy for Multi-Sig Wallets
Authors: Fontaine
Status: Deployed
Type: Specification
Assigned: 2020-12-16
License: MIT
==Abstract==
This BIP defines a logical hierarchy for deterministic multi-sig wallets based on an algorithm
described in BIP-0067 (BIP67 from now on), BIP-0032 (BIP32 from now on), purpose scheme described in
BIP-0043 (BIP43 from now on), and multi-account hierarchy described in
BIP-0044 (BIP44 from now on).
This BIP is a particular application of BIP43.
==Copyright==
This BIP falls under the MIT License.
==Motivation==
The motivation of this BIP is to define the existing industry wide practice of utilizing m/48'
derivation paths in hierarchical deterministic multi-sig wallets so that other developers may
benefit from a standard. This BIP allows for future script types to easily be appended to the
specification so that a new BIP is not required for every future script type.
The hierarchy proposed in this paper is quite comprehensive. It allows the handling of
multiple accounts, external and internal chains per account, multiple script types and
millions of addresses per chain.
This paper was inspired from BIP44.
==Backwards compatibility==
Currently a number of wallets utilize the m/48' derivation scheme for HD multi-sig accounts.
This BIP is intended to maintain the *existing* real world use of the m/48' derivation.
No breaking changes are made so as to avoid "loss of funds" to existing users.
Wallets which currently support the m/48' derivation will not need to make any changes
to comply with this BIP.
==Specification==
===Key sorting===
Any wallet that supports BIP48 inherently supports deterministic key sorting as per BIP67 so that all possible
multi-signature addresses/scripts are derived from deterministically sorted public keys.
===Path levels===
We define the following 6 levels in BIP32 path:
h or ' in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
===Purpose===
Purpose is a constant set to 48' following the BIP43 recommendation.
It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
===Coin type===
One master node (seed) can be used for multiple Bitcoin networks.
Sharing the same space for various networks has some disadvantages.
Avoiding reusing addresses across networks and improving privacy issues.
Coin type 0 for mainnet and 1 for testnet.
Hardened derivation is used at this level.
===Account===
This level splits the key space into independent user identities, following the BIP44 pattern,
so the wallet never mixes the coins across different accounts.
Users can use these accounts to organize the funds in the same
fashion as bank accounts; for donation purposes (where all
addresses are considered public), for saving purposes,
for common expenses etc.
Accounts are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Hardened derivation is used at this level.
===Script===
This level splits the key space into two separate script_type(s). To provide
forward compatibility for future script types this specification can be easily extended.
Currently the only script types covered by this BIP are Native Segwit (p2wsh) and
Nested Segwit (p2sh-p2wsh).
The following path represents Nested Segwit (p2sh-p2wsh) mainnet, account 0:
1': Nested Segwit (p2sh-p2wsh) m/48'/0'/0'/1'
The following path represents Native Segwit (p2wsh) mainnet, account 0:
2': Native Segwit (p2wsh) m/48'/0'/0'/2'
The recommended default for wallets is pay to witness script hash m/48'/0'/0'/2'.
===Change===
Constant 0 is used for external chain and constant 1 for internal chain (also
known as change addresses). External chain is used for addresses that are meant
to be visible outside of the wallet (e.g. for receiving payments). Internal
chain is used for addresses which are not meant to be visible outside of the
wallet and is used for return transaction change.
Public derivation is used at this level.
===Index===
Addresses are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Public derivation is used at this level.
==Examples==
{|
|network
|account
|script
|chain
|address
|path
|-
|mainnet
|first
|p2sh-p2wsh
|external
|first
|m / 48' / 0' / 0' / 1' / 0 / 0
|-
|mainnet
|first
|p2wsh
|external
|first
|m / 48' / 0' / 0' / 2' / 0 / 0
|-
|mainnet
|first
|p2wsh
|external
|second
|m / 48' / 0' / 0' / 2' / 0 / 1
|-
|mainnet
|first
|p2wsh
|change
|first
|m / 48' / 0' / 0' / 2' / 1 / 0
|-
|mainnet
|first
|p2wsh
|change
|second
|m / 48' / 0' / 0' / 2' / 1 / 1
|-
|mainnet
|second
|p2wsh
|external
|first
|m / 48' / 0' / 1' / 2' / 0 / 0
|-
|mainnet
|second
|p2wsh
|external
|second
|m / 48' / 0' / 1' / 2' / 0 / 1
|-
|testnet
|first
|p2sh-p2wsh
|external
|first
|m / 48' / 1' / 0' / 1' / 0 / 0
|-
|testnet
|first
|p2wsh
|external
|second
|m / 48' / 1' / 0' / 2' / 0 / 1
|-
|testnet
|first
|p2wsh
|change
|first
|m / 48' / 1' / 0' / 2' / 1 / 0
|-
|testnet
|first
|p2wsh
|change
|second
|m / 48' / 1' / 0' / 2' / 1 / 1
|-
|testnet
|second
|p2wsh
|external
|first
|m / 48' / 1' / 1' / 2' / 0 / 0
|-
|testnet
|second
|p2wsh
|external
|second
|m / 48' / 1' / 1' / 2' / 0 / 1
|-
|testnet
|second
|p2wsh
|change
|first
|m / 48' / 1' / 1' / 2' / 1 / 0
|-
|testnet
|second
|p2wsh
|change
|second
|m / 48' / 1' / 1' / 2' / 1 / 1
|}
==Reference==
* [[bip-0067.mediawiki|BIP67 - Deterministic Pay-to-script-hash multi-signature addresses through public key sorting]]
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
================================================
FILE: bip-0049.mediawiki
================================================
BIP: 49
Layer: Applications
Title: Derivation scheme for P2WPKH-nested-in-P2SH based accounts
Authors: Daniel Weigl
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0049
Status: Deployed
Type: Specification
Assigned: 2016-05-19
License: PD
==Abstract==
This BIP defines the derivation scheme for HD wallets using the P2WPKH-nested-in-P2SH ([[bip-0141.mediawiki|BIP 141]]) serialization format for segregated witness transactions.
==Motivation==
With the usage of P2WPKH-nested-in-P2SH ([[bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh|BIP 141]]) transactions it is necessary to have a common derivation scheme.
It allows the user to use different HD wallets with the same masterseed and/or a single account seamlessly.
Thus the user needs to create dedicated segregated witness accounts, which ensures that only wallets compatible with this BIP
will detect the accounts and handle them appropriately.
===Considerations===
Two generally different approaches are possible for current BIP44 capable wallets:
1) Allow the user to use the same account(s) that they already use, but add segregated witness encoded addresses to it.
1.1) Use the same public keys as defined in BIP44, but in addition to the normal P2PKH address also derive the P2SH address from it.
1.2) Use the same account root, but branch off and derive different external and internal chain roots to derive dedicated public keys for the segregated witness addresses.
2) Create dedicated accounts used only for segregated witness addresses.
The solutions from point 1 have a common disadvantage: if a user imports/recovers a BIP49-compatible wallet masterseed into/in a non-BIP49-compatible wallet, the account might show up but also it might miss some UTXOs.
Therefore this BIP uses solution 2, which fails in a more visible way. Either the account shows up or not at all. The user does not have to check his balance after using the same seed in different wallets.
==Specifications==
This BIP defines the two needed steps to derive multiple deterministic addresses based on a [[bip-0032.mediawiki|BIP 32]] root account.
===Public key derivation===
To derive a public key from the root account, this BIP uses the same account-structure as defined in
[[bip-0044.mediawiki|BIP 44]], but only uses a different purpose value to indicate the different transaction
serialization method.
For the `purpose`-path level it uses `49'`. The rest of the levels are used as defined in BIP44.
===Address derivation===
To derive the P2SH address from the above calculated public key, we use the encapsulation defined in [[bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh|BIP 141]]:
witness:
scriptSig: <0 <20-byte-key-hash>>
(0x160014{20-byte-key-hash})
scriptPubKey: HASH160 <20-byte-script-hash> EQUAL
(0xA914{20-byte-script-hash}87)
===Extended Key Version===
When serializing extended keys, this scheme uses alternate version bytes. Extended public keys use 0x049d7cb2 to produce a "ypub" prefix, and private keys use 0x049d7878 to produce a "yprv" prefix. Testnet uses 0x044a5262 "upub" and 0x044a4e28 "uprv."
Additional registered version bytes are listed in [[https://github.com/satoshilabs/slips/blob/master/slip-0132.md|SLIP-0132]].
==Backwards Compatibility==
This BIP is not backwards compatible by design as described under [[#considerations|considerations]]. An incompatible wallet will not discover accounts at all and the user will notice that something is wrong.
==Test vectors==
==What went wrong==
A block that had a larger number of total transaction inputs than previously seen was mined and broadcasted. Bitcoin 0.8 nodes were able to handle this, but some pre-0.8 Bitcoin nodes rejected it, causing an unexpected fork of the blockchain. The pre-0.8-incompatible chain (from here on, the 0.8 chain) at that point had around 60% of the mining hash power ensuring the split did not automatically resolve (as would have occurred if the pre-0.8 chain outpaced the 0.8 chain in total work, forcing 0.8 nodes to reorganise to the pre-0.8 chain).
In order to restore a canonical chain as soon as possible, BTCGuild and Slush downgraded their Bitcoin 0.8 nodes to 0.7 so their pools would also reject the larger block. This placed majority hashpower on the chain without the larger block, thus eventually causing the 0.8 nodes to reorganise to the pre-0.8 chain.
During this time there was at least [https://bitcointalk.org/index.php?topic=152348.0 one large double spend]. However, it was done by someone experimenting to see if it was possible and was not intended to be malicious.
==What went right==
* The split was detected very quickly.
* The right people were online and available in IRC or could be contacted directly.
* Marek Palatinus (Slush) and Michael Marsee (Eleuthria of BTCGuild) quickly downgraded their nodes to restore a pre-0.8 chain as canonical, despite the fact that this caused them to sacrifice significant amounts of money.
* Deposits to the major exchanges and payments via BitPay were also suspended (and then un-suspended) very quickly.
* Fortunately, the only attack on a merchant was done by someone who was not intending to actually steal money.
==Root cause==
Bitcoin versions prior to 0.8 configure an insufficient number of Berkeley DB locks to process large but otherwise valid blocks. Berkeley DB locks have to be manually configured by API users depending on anticipated load. The manual says this:
:The recommended algorithm for selecting the maximum number of locks, lockers, and lock objects is to run the application under stressful conditions and then review the lock system's statistics to determine the maximum number of locks, lockers, and lock objects that were used. Then, double these values for safety.
With the insufficiently high BDB lock configuration, it implicitly had become a network consensus rule determining block validity (albeit an inconsistent and unsafe rule, since the lock usage could vary from node to node).
Because max-sized blocks had been successfully processed on the testnet, it did not occur to anyone that there could be blocks that were smaller but require more locks than were available. Prior to 0.7 unmodified mining nodes self-imposed a maximum block size of 500,000 bytes, which further prevented this case from being triggered. 0.7 made the target size configurable and miners had been encouraged to increase this target in the week prior to the incident.
Bitcoin 0.8 did not use Berkeley DB. It switched to LevelDB instead, which did not implement the same locking limits as BDB. Therefore it was able to process the forking block successfully.
Note that BDB locks are also required during processing of re-organizations. Versions prior to 0.8 may be unable to process some valid re-orgs.
This would be an issue even if the entire network was running version 0.7.2. It is theoretically possible for one 0.7.2 node to create a block that others are unable to validate, or for 0.7.2 nodes to create block re-orgs that peers cannot validate, because the contents of each node's blkindex.dat database is not identical, and the number of locks required depends on the exact arrangement of the blkindex.dat on disk (locks are acquired per-page).
==Action items==
===Immediately===
'''Done''': Release a version 0.8.1, forked directly from 0.8.0, that, for the next two months has the following new rules:
# Reject blocks that would probably cause more than 10,000 locks to be taken.
# Limit the maximum block-size created to 500,000 bytes
# Release a patch for older versions that implements the same rules, but also increases the maximum number of locks to 537,000
# Create a web page on bitcoin.org that will urge users to upgrade to 0.8.1, but will tell them how to set DB_CONFIG to 537,000 locks if they absolutely cannot.
# Over the next 2 months, send a series of alerts to users of older versions, pointing to the web page.
===Alert system===
'''Done''': Review who has access to the alert system keys, make sure they all have contact information for each other, and get good timezone overlap by people with access to the keys.
'''Done''': Implement a new bitcoind feature so services can get timely notification of alerts: -alertnotify= Run command when an AppliesToMe() alert is received.
'''Done''': Pre-generate 52 test alerts, and set a time every week when they are broadcast on -testnet (so -alertnotify scripts can be tested in as-close-to-real-world conditions as possible).
Idea from Michael Gronager: encourage merchants/exchanges (and maybe pools) to run new code behind a bitcoind running the network-majority version.
===Safe mode===
'''Done''': Perhaps trigger an alert if there is a long enough side chain detected, even if it is not the main chain. Pools could use this to automatically suspend payouts if a long side-chain suddenly appeared out of nowhere (it’s hard for an attacker to mine such a thing).
===Testing===
Start running bots on the testnet that grab some coins from a testnet faucet, generate large numbers of random transactions that split/recombine them and then send them back to the faucet. Randomized online testing on the testnet might have revealed the pathological block type earlier.
===Double spending===
A double spend attack was successful, despite that both sides of the chain heard about the transactions in the same order. The reason is most likely that the memory pools were cleared when the mining pool nodes were downgraded. A solution is for nodes to sync their mempools to each other at startup, however, this requires a memory pool expiry policy to be implemented as currently node restarts are the only way for unconfirmed transactions to be evicted from the system.
===Resolution===
On 16 August, 2013 block 252,451 (0x0000000000000024b58eeb1134432f00497a6a860412996e7a260f47126eed07) was accepted by the main network, forking unpatched nodes off the network.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0052.mediawiki
================================================
BIP: 52
Layer: Consensus (hard fork)
Title: Durable, Low Energy Bitcoin PoW
Authors: Michael Dubrovsky
Bogdan Penkovsky
Status: Draft
Type: Specification
Assigned: 2021-05-13
License: BSD-2-Clause OR OPUBL-1.0
== Simple Summary ==
Bitcoin's energy consumption is growing with its value (see Figure below).
Although scaling PoW is necessary to maintain the security of the network,
reliance on massive energy consumption has scaling drawbacks and leads to mining
centralization. A major consequence of the central role of local electricity
cost in mining is that today, most existing and potential participants in the
Bitcoin network cannot profitably mine Bitcoin even if they have the capital to
invest in mining hardware. From a practical perspective, Bitcoin adoption by
companies like Tesla (which recently rescinded its acceptance of Bitcoin as
payment) has been hampered by its massive energy consumption and perceived
environmental impact.
Figure. Bitcoin price and estimated Bitcoin energy consumption.
Data sources: [https://cbeci.org Cambridge Bitcoin Electricity Consumption Index], [https://www.coindesk.com CoinDesk].
We propose a novel proof-of-work paradigm for Bitcoin--Optical proof-of-work. It
is designed to decouple Bitcoin mining from energy and make it feasible outside
of regions with low electricity costs. ''Optical proof-of-work'' (oPoW) is a
modification of Hashcash that is most efficiently computed using a new class of
photonic processors. Without compromising the cryptographic or game-theoretical
security of Hashcash, oPoW shifts the operating expenses of mining (OPEX), to
capital expenses (CAPEX)--i.e. electricity to hardware. oPoW makes it possible
for billions of new miners to enter the market simply by investing in a
low-energy photonic miner. Shifting to a high-CAPEX PoW has the added benefit of
making the hashrate resilient to Bitcoin's price fluctuations - once low-OPEX
hardware is operating there is no reason to shut it down even if the value of
mining rewards diminishes. oPoW is hardware-compatible with GPUs, FPGAs, and
ASICs meaning that a transitional period of optical and traditional hardware
mining in parallel on the network is feasible
More information is available here: [https://www.powx.org/opow].
== Abstract ==
As Bitcoin gained utility and value over the preceding decade, the network incentivized the purchase of billions of dollars in mining equipment and electricity. With the growth of competition, home mining became unprofitable. Even the most sophisticated special-purpose hardware (ASIC miners) doesn’t cover its energy costs unless the miner also has direct access to very cheap electricity. This heavy reliance on energy makes it difficult for new miners to enter the market and leads to hashrate instability as miners shut off their machines when the price of Bitcoin falls. Additionally as the network stores ever more value, the percentage of world energy consumption that is associated with Bitcoin continues to grow, creating the potential for scaling failure and a general backlash. To ensure that Bitcoin can continue scaling and reach its full potential as a world currency and store of value, we propose a low-energy proof-of-work paradigm for Bitcoin. ''Optical proof of work (oPoW)'' is designed to decouple Bitcoin’s security from massive energy use and make bitcoin mining feasible outside of regions with low electricity costs. ''Optical proof-of-work'' is a modification of Hashcash that is most efficiently computed using a new class of photonic processors that has emerged as a leading solution for ultra-low energy computing over the last 5 years. oPoW shifts the operating expenses of mining (OPEX), to capital expenses (CAPEX)–i.e. electricity to hardware, without compromising the cryptographic or game-theoretical security of Hashcash. We provide an example implementation of oPoW, briefly discuss its cryptographic construction as well as the working principle of photonic processors. Additionally, we outline the potential benefits of oPoW to the bitcoin network, including geographic decentralization and democratization of mining as well as hashrate resilience to price fluctuations.
== Copyright ==
This BIP is dual-licensed under the Open Publication License and BSD 2-clause license.
== Motivation ==
As Bitcoin has grown over the past decade from a small network run by hobbyists to a global currency, the underlying Proof of Work protocol has not been updated. Initially pitched as a global decentralized network (“one CPU-one vote”), Bitcoin transactions today are secured by a small group of corporate entities. In practice, it is only feasible for [http://archive.is/YeDwh entities that can secure access to abundant, inexpensive energy]. The economics of mining limit profitability to places like Iceland, Texas, or Western China. Besides the negative environmental externalities, which may be significant, mining today is performed primarily with the consent (and in many cases, partnership) of large public utilities and the governments that control them. Although this may not be a problem in the short term, in the long term it stands to erode the censorship resistance and security of Bitcoin and other public blockchains through potential regulation or [https://arxiv.org/pdf/1605.07524.pdf partitioning attacks].
Recent events, such as the [https://twitter.com/MustafaYilham/status/1384278267067203590 ~25% hashrate crash due to coal-powered grid failure in china] and Tesla’s rescinding of its acceptance of Bitcoin as a form of payment, show that there are practical real-world downsides to Proof of Works’s massive reliance on energy.
Whether or not the Bitcoin community accepts this common criticism as entirely valid, it has real-world effects which will only get worse over time. Eliminating the exponentially growing energy use currently built into Bitcoin without eliminating the security of PoW would be ideal and should not be a partisan issue.
New consensus mechanisms have been proposed as a means of securing cryptocurrencies whilst reducing energy cost, such as various forms of Proof of Stake and Proof of Space-Time. While many of these alternative mechanisms offer compelling guarantees, they generally require new security assumptions, which have not been stress-tested by live deployments at any adequate scale. Consequently, we still have relatively little empirical understanding of their safety. Completely changing the Bitcoin paradigm is likely to introduce new unforeseen problems. We believe that the major issues discussed above can be resolved by improving rather than eliminating Bitcoin’s fundamental security layer—Proof of Work. Instead of devising a new consensus architecture to fix these issues, it is sufficient to shift the economics of PoW. The financial cost imposed on miners need not be primarily composed of electricity. The situation can be significantly improved by reducing the operating expense (OPEX)—energy—as a major mining component. Then, by shifting the cost towards capital expense (CAPEX)—mining hardware—the dynamics of the mining ecosystem becomes much less dependent on electricity prices, and much less electricity is consumed as a whole.
Moreover, a reduction in energy consumption automatically leads to
geographically distributed mining, as mining becomes profitable even in regions
with expensive electricity. Additionally, lower energy consumption will
eliminate heating issues experienced by today’s mining operations, which will
further decrease operating cost as well as noise associated with fans and
cooling systems. All of this means that individuals and smaller entities would
be able to enter the mining ecosystem simply for the cost of a miner, without
first gaining access to cheap energy or a dedicated, temperature-controlled data
center. To a degree, memory-hard PoW schemes like
[https://github.com/tromp/cuckoo Cuckoo Cycle], which increase the use of SRAM
in lieu of pure computation, push the CAPEX/OPEX ratio in the right direction by
occupying ASIC chip area with memory. To maximize the CAPEX to OPEX ratio of the
Optical Proof of Work algorithm, we developed
[https://assets.pubpub.org/xi9h9rps/01581688887859.pdf ''HeavyHash''] [1].
HeavyHash is a cryptographic construction that takes the place of SHA256 in
Hashcash. Our algorithm is hardware-compatible with ultra-energy-efficient photonic co-processors that have been developed for machine learning hardware accelerators.
HeavyHash uses a proven digital hash (SHA3) packaged with a large amount of MAC (Multiply-and-Accumulate) computation into a Proof of Work puzzle. Although HeavyHash can be computed on any standard digital hardware, it becomes hardware efficient only when a small digital core is combined with a low-power photonic co-processor for performing MAC operations. oPoW mining machines will have a small digital core flip-chipped onto a large, low-power photonic chip. This core will be bottlenecked by the throughput of the digital to analog and analog to digital converters. A prototype of such analogue optical matrix multiplier can be seen in the figure below.
Figure. TOP: Photonic Circuit Diagram, A. Laser input (1550nm, common telecom wavelength) B. Metal pads for controlling modulators to transduce electrical data to optical C. Metal pads for tuning mesh of directional couplers D. Optical signal exits here containing the results of the computation and is output to fibers via a grating coupler the terminus of each waveguide. E. Alignment circuit for aligning fiber coupling stage. Bottom: a photograph of a bare oPoW miner prototype chip before wire and fiber bonding. On the right side of the die are test structures (F).
The ''HeavyHash'' derives its name from the fact that it is bloated or weighted with additional computation. This means that a cost comparable oPoW miner will have a much lower nominal hashrate compared to a Bitcoin ASIC (HeavyHashes/second vs. SHA256 Hashes/second in equivalent ASIC). We provide the cryptographic security argument of the HeavyHash function in Section 3 in [https://assets.pubpub.org/xi9h9rps/01581688887859.pdf Towards Optical Proof of Work] [1]. In the article, we also provide a game-theoretic security argument for CAPEX-heavy PoW. For additional information, we recommend reading [https://uncommoncore.co/wp-content/uploads/2019/10/A-model-for-Bitcoins-security-and-the-declining-block-subsidy-v1.02.pdf this article].
While traditional digital hardware relies on electrical currents, optical
computing uses light as the basis for some of or all of its operations. Building
on the development and commercialization of silicon photonic chips for telecom
and datacom applications, modern photonic co-processors are silicon chips made
using well-established and highly scalable silicon CMOS processes. However,
unlike cutting edge electronics which require ever-smaller features (e.g. 5 nm),
fabricated by exponentially more complex and expensive machinery, silicon
photonics uses old fabrication nodes (90 nm). Due to the large de Broglie
wavelength of photons, as compared to electrons, there is no benefit to using
the small feature sizes. The result is that access to silicon photonic wafer
fabrication is readily available, in contrast to the notoriously difficult
process of accessing advanced nodes. Moreover, the overall cost of entry is
lower as lithography masks for silicon photonics processes are an order of
magnitude cheaper ($500k vs. $5M). Examples of companies developing optical
processors for AI, which will be hardware-compatible with oPoW include [https://lightmatter.co/ Lightmatter], [https://www.lightelligence.ai/ Lightelligence], [https://luminous.co/ Luminous], [https://www.intel.com/content/www/us/en/architecture-and-technology/silicon-photonics/silicon-photonics-overview.html Intel], and other more recent entrants.
== Specification ==
=== HeavyHash ===
The HeavyHash is performed in three stages:
# Keccak hash
# Matrix-vector multiplication
# Keccak of the result xored with the hashed input
Note that the most efficient matrix-vector multiplication is performed on a
photonic miner. However, this linear algebra operation can be performed on any
conventional computing hardware (CPU, GPU, etc.), therefore making the HeavyHash
hardware-compatible with any digital device.
The algorithm’s pseudo-code:
// M is a Matrix 64 x 64 of Unsigned 4 values
// 256-bitVector
x1 <- keccak(input)
// Reshape the obtained bitvector
// into a 64-vector of unsigned 4-bit values
x2 <- reshape(x1, 64)
// Perform a matrix-vector multiplication.
// The result is 64-vector of 14-bit unsigned.
x3 <- vector_matrix_mult(x2, M)
// Truncate all values to 4 most significant bits.
// This is due to the specifics of analog
// computing by the photonic accelerator.
// Obtain a 64-vector of 4-bit unsigned.
x4 <- truncate_to_msb(x3, 4)
// Interpret as a 256-bitvector
x5 <- flatten(x4)
// 256-bitVector
result <- keccak(xor(x5, x1))
Which in C can be implemented as:
static void heavyhash(const uint16_t matrix[64][64], void* pdata, size_t pdata_len, void* output)
{
uint8_t hash_first[32] __attribute__((aligned(32)));
uint8_t hash_second[32] __attribute__((aligned(32)));
uint8_t hash_xored[32] __attribute__((aligned(32)));
uint16_t vector[64] __attribute__((aligned(64)));
uint16_t product[64] __attribute__((aligned(64)));
sha3_256((uint8_t*) hash_first, 32, (const uint8_t*)pdata, pdata_len);
for (int i = 0; i < 32; ++i) {
vector[2*i] = (hash_first[i] >> 4);
vector[2*i+1] = hash_first[i] & 0xF;
}
for (int i = 0; i < 64; ++i) {
uint16_t sum = 0;
for (int j = 0; j < 64; ++j) {
sum += matrix[i][j] * vector[j];
}
product[i] = (sum >> 10);
}
for (int i = 0; i < 32; ++i) {
hash_second[i] = (product[2*i] << 4) | (product[2*i+1]);
}
for (int i = 0; i < 32; ++i) {
hash_xored[i] = hash_first[i] ^ hash_second[i];
}
sha3_256((uint8_t*)output, 32, (const uint8_t*)hash_xored, 32);
}
=== Random matrix generation ===
The random matrix M (which is a HeavyHash parameter) is obtained in a deterministic way and is changed every block. Matrix M coefficients are generated using a pseudo-random number generation algorithm (xoshiro) from the previous block header. If the matrix is not full rank, it is repeatedly generated again.
An example code to obtain the matrix M:
== Discussion ==
=== Geographic Distribution of Mining Relative to CAPEX-OPEX Ratio of Mining Costs ===
Below is a simple model showing several scenarios for the geographic distribution of mining activity relative to the CAPEX/OPEX ratio of the cost of operating a single piece of mining hardware. As the ratio of energy consumption to hardware cost decreases, geographic variations in energy cost cease to be a determining factor in miner distribution.
Underlying assumptions: 1. Electricity price y is fixed in time but varies geographically. 2. Every miner has access to the same hardware. 3. Each miner’s budget is limited by both the cost of mining equipment as well as the local cost of the electricity they consume
budget = a(p+ey),
where a is the number of mining machines, p is the machine price, e is the total energy consumption over machine lifetime, and y is electricity price.
Note that in locations where mining is not profitable, hashrate is zero.
An interactive version of this diagram can be found [https://www.powx.org/opow here].
=== Why does CAPEX to OPEX shift lead to lower energy consumption? ===
A common misconception about oPoW is that it makes mining “cheaper” by enabling energy-efficient hardware. There is no impact on the dollar cost of mining a block, rather the mix of energy vs. hardware investment changes from about 50/50 to 10/90 or better. We discuss this at length and rigorously in our paper[1].
=== Working Principles of Photonic Processors ===
Photonics accelerators are made by fabricating waveguides in silicon using standard lithography processes. Silicon is transparent to infrared light and can act as a tiny on-chip fiber optical cable. Silicon photonics found its first use during the 2000s in transceivers for sending and receiving optical signals via fiber and has advanced tremendously over the last decade.
By encoding a vector into optical intensities passing through a series of parallel waveguides, interfering these signals in a mesh of tunable interferometers (acting as matrix coefficients), and then detecting the output using on-chip Germanium photodetectors, a matrix-vector multiplication is achieved. A generalized discussion of matrix multiplication setups using photonics/interference can be found in [https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.73.58 Reck et al.] and [https://arxiv.org/abs/1506.06220 Russell et al.] A detailed discussion of several integrated photonic architectures for matrix multiplication and corresponding tuning algorithms can be found in [https://arxiv.org/pdf/1909.06179.pdf Pai et al.]
Below is a conceptual representation of a 3D-packaged oPoW mining chip. Note that the majority of the real estate and cost comes from the photonic die and the laser, with only a small digital SHA3 die needed (as opposed to a conventional miner of the same cost, which would have many copies of this die running in parallel).
=== Block Reward Considerations ===
Although it is out of the scope of this proposal, the authors strongly recommend the consideration of a change in the block reward schedule currently implemented in Bitcoin. There is no clear way to incentivize miners with transaction fees only, as has been successfully shown in [https://www.cs.princeton.edu/~smattw/CKWN-CCS16.pdf On the Instability of Bitcoin Without the Block Reward] and other publications, therefore looking a decade or two ahead it will be important to implement a fixed block reward or to slow the decay of the block reward to maintain the security of the network. Given that oPoW miners have low operating costs, once a large number of machines are running the reward level sufficient to keep them in operation and providing robust security can potentially be significantly smaller than in the case of the current SHA256 ASICs securing Bitcoin.
=== Implementation on the Bitcoin Network ===
A hard fork is not necessarily required for the Bitcoin network to test and eventually implement oPoW. It’s possible to add oPoW as a dual PoW to Bitcoin as a soft fork. Tuning the parameters to ensure that, for example, 99.9% of the security budget would be earned by miners via the SHA256 Hashcash PoW and 0.1% via oPoW would create sufficient incentive for oPoW to be stress-tested and to incentivize the manufacture of dedicated oPoW miners. If this test is successful, the parameters can be tuned continuously over time, e.g. oPoW share doubling at every halving, such that oPoW accounts for some target percentage (up to 100% in a complete SHA256 phase-out).
==== Reverse compatibility ====
Our understanding is that oPoW will not be reverse compatible.
=== ASICBOOST ===
Any new PoW algorithm carries the risk of hardware developers discovering and patenting an architecture with a significant speedup, as happened in the case of ASICBOOST for SHA256. HeavyHash is comprised of an SHA hash and 4-bit linear matrix-vector operations. The intent is for the matrix-vector multiplications to account for the majority of the work involved in computing a single HeavyHash operation. As we show in the Minimum Effective Hardness section of Towards Optical Proof of Work[1], there is no workaround to performing the matrix operations when computing HeavyHash, and since the SHA hashes are negligible, a true ASICBOOST-type speed up would require a speed up in linear matrix processing. Since matrix-vector multiplication is at the heart of neural networks and many other common computational workloads, it has been optimized very heavily and is generally very well understood. The acceleration of matrix-vector multiplication hardware (e.g. photonic coprocessors, memristors, etc.) is a very general problem and there are dozens of companies working on it, making it very unlikely for a single party to corner the market.
== Endnotes ==
With significant progress in optical and analog matrix-vector-multiplication chipsets over the last year, we hope to demonstrate commercial low-energy mining on our network in the next 6 months. The current generation of optical matrix processors under development is expected to have 10x better energy consumption per MAC operation than digital implementations, and we expect this to improve by another order of magnitude in future generations.
PoWx will also be publishing the designs of the current optical miner prototypes in the near term under an open-source hardware license.
== Acknowledgments ==
We thank all the members of the Bitcoin community who have already given us feedback over the last several years as well as others in the optical computing community and beyond that have given their input.
[1] M. Dubrovsky et al. Towards Optical Proof of Work, CES conference (2020) https://assets.pubpub.org/xi9h9rps/01581688887859.pdf
[2] https://sciencex.com/news/2020-05-powering-bitcoin-silicon-photonics-power.html
[3] KISS random number generator http://www.cse.yorku.ca/~oz/marsaglia-rng.html
================================================
FILE: bip-0053/64byte-tx-mainnet.txt
================================================
892f44a49de6f5b212cdbea514d09e692d9fed5d897f37bcef14bd0eedebf193
bbf71454857438c6dfd64c0d92a7c5360a8d8d57c9202f5806449e5b0d26b848
6713d61a83e3d095582211ea8d6db452ac7561e863decba7c4046fb9f6d88aa0
7f2efc6546011ad3227b2da678be0d30c7f4b08e2ce57b5edadd437f9e27a612
5302e01dc4b7e34314a34c7c3347107e612b9524be684d388cd4d2ca35ff1ec9
================================================
FILE: bip-0053/non-standard-hashlock-utxos.txt
================================================
af32bb06f12f2ae5fdb7face7cd272be67c923e86b7a66a76ded02d954c2f94d:0
faf8989ed87c5a667a1ead813aea718727e01767c124193297eaf409ff4645e5:1
c4b46c5d88327d7af6254820562327c5f11b6ee5449da04b7cfd3710b48b6f55:0
702c36851ed202495c2bec1dd0cefb448b50fafd3a5cdd5058c18ca53fc2c3d1:0
6f8a70aac37786b1f619d40250b8bca1a1f6da487146a7e81091f611068a23ef:0
fb01987b540ec286973aac248fab643de82813af452d958056fee8de9f4535ab:0
================================================
FILE: bip-0053.mediawiki
================================================
==Abstract==
[[BIP 0037]] introduced a new flag to version messages which says whether to relay new transaction messages to that node.
The protocol version was upgraded to 70001, and the (now accepted) BIP 0037 became implemented.
The implementation is problematic because the RelayTransactions flag is an optional part of the version message stream.
==Motivation==
One property of Bitcoin messages is their fixed number of fields. This keeps the format simple and easily understood. Adding optional fields to messages will cause deserialisation issues when other fields come after the optional one.
As an example, the length of version messages might be checked to ensure the byte stream is consistent. With optional fields, this checking is no longer possible. This is desirable to check for consistency inside internal deserialization code, and proper formatting of version messages originating from other nodes. In the future with diversification of the Bitcoin network, it will become desirable to enforce this kind of strict adherence to standard messages with field length compliance with every protocol version.
Another property of fixed-length field messages is the ability to pass stream operators around for deserialization. This property is also lost, as now the deserialisation code must know the remaining length of bytes to parse. The parser now requires an additional piece of information (remaining size of the stream) for parsing instead of being a dumb reader.
==Specification==
=== version ===
When a node creates an outgoing connection, it will immediately advertise its version. The remote node will respond with its version. No further communication is possible until both peers have exchanged their version.
Payload:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 4 || version || int32_t || Identifies protocol version being used by the node
|-
| 8 || services || uint64_t || bitfield of features to be enabled for this connection
|-
| 8 || timestamp || int64_t || standard UNIX timestamp in seconds
|-
| 26 || addr_recv || net_addr || The network address of the node receiving this message
|-
|colspan="4"| version >= 106
|-
| 26 || addr_from || net_addr || The network address of the node emitting this message
|-
| 8 || nonce || uint64_t || Node random nonce, randomly generated every time a version packet is sent. This nonce is used to detect connections to self.
|-
| ? || user_agent || var_str || [[bip-0014.mediawiki|User Agent]] (0x00 if string is 0 bytes long)
|-
| 4 || start_height || int32_t || The last block received by the emitting node
|-
| 1 || relay || bool || Whether the remote peer should announce relayed transactions or not, see [[bip-0037.mediawiki|BIP 0037]], since version >= 70001
|}
A "verack" packet shall be sent if the version packet was accepted.
The following services are currently assigned:
{|class="wikitable"
! Value !! Name !! Description
|-
| 1 || NODE_NETWORK || This node can be asked for full blocks instead of just headers.
|}
=== Code Updates ===
fRelayTx is added to the PushMessage() call inside PushVersion() (net.cpp)
Additionally the protocol version is increased from 70001 to 70002.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0061.mediawiki
================================================
BIP: 61
Layer: Peer Services
Title: Reject P2P message
Authors: Gavin Andresen
Comments-Summary: Controversial; some recommendation, and some discouragement
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0061
Status: Deployed
Type: Specification
Assigned: 2014-06-18
==Abstract==
This BIP describes a new message type for the Bitcoin peer-to-peer network.
==Motivation==
Giving peers feedback about why their blocks or transactions are rejected, or
why they are being banned for not following the protocol helps
interoperability between different implementations.
It also gives SPV (simplified payment verification) clients a hint that something
may be wrong when their transactions are rejected due to insufficient priority
or fees.
==Specification==
Data types in this specification are as described at https://en.bitcoin.it/wiki/Protocol_specification
===reject===
One new message type "reject" is introduced. It is sent directly to a peer in response to a "version", "tx" or "block" message.
For example, the message flow between two peers for a relayed transaction that is rejected for some reason would be:
--> inv
<-- getdata
--> tx
<-- reject
All implementations of the P2P protocol version 70,002 and later should support the reject message.
====common payload====
Every reject message begins with the following fields. Some messages append extra, message-specific data.
{|
| Field Size || Name || Data type || Comments
|-
| variable || response-to-msg || var_str || Message that triggered the reject
|-
| 1 || reject-code || uint8_t || 0x01 through 0x4f (see below)
|-
| variable || reason || var_string || Human-readable message for debugging
|}
The human-readable string is intended only for debugging purposes; in particular, different implementations may
use different strings. The string should not be shown to users or used for anything besides diagnosing
interoperability problems.
The following reject code categories are used; in the descriptions below, "server" is the peer generating
the reject message, "client" is the peer that will receive the message.
{|
| Range || Category
|-
| 0x01-0x0f || Protocol syntax errors
|-
| 0x10-0x1f || Protocol semantic errors
|-
| 0x40-0x4f || Server policy rule
|}
==== rejection codes common to all message types ====
{|
| Code || Description
|-
| 0x01 || Message could not be decoded
|}
==== reject version codes ====
Codes generated during the initial connection process in response to a "version" message:
{|
| Code || Description
|-
| 0x11 || Client is an obsolete, unsupported version
|-
| 0x12 || Duplicate version message received
|}
==== reject tx payload, codes ====
Transaction rejection messages extend the basic message with the transaction id hash:
{|
| Field Size || Name || Data type || Comments
|-
| 32 || hash || char[32] || transaction that is rejected
|}
The following codes are used:
{|
| Code || Description
|-
| 0x10 || Transaction is invalid for some reason (invalid signature, output value greater than input, etc.)
|-
| 0x12 || An input is already spent
|-
| 0x40 || Not mined/relayed because it is "non-standard" (type or version unknown by the server)
|-
| 0x41 || One or more output amounts are below the 'dust' threshold
|-
| 0x42 || Transaction does not have enough fee/priority to be relayed or mined
|}
==== payload, reject block ====
Block rejection messages extend the basic message with the block header hash:
{|
| Field Size || Name || Data type || Comments
|-
| 32 || hash || char[32] || block (hash of block header) that is rejected
|}
Rejection codes:
{|
| code || description
|-
| 0x10 || Block is invalid for some reason (invalid proof-of-work, invalid signature, etc)
|-
| 0x11 || Block's version is no longer supported
|-
| 0x43 || Inconsistent with a compiled-in checkpoint
|}
Note: blocks that are not part of the server's idea of the current best chain, but are otherwise valid, should not trigger reject messages.
== Compatibility ==
The reject message is backwards-compatible; older peers that do not recognize the reject message will ignore it.
== Implementation notes ==
Implementers must consider what happens if an attacker either sends them
reject messages for valid transactions/blocks or sends them random
reject messages, and should beware of possible denial-of-service attacks.
For example, notifying the user of every reject message received
would make it trivial for an attacker to mount an annoy-the-user attack.
Even merely writing every reject message to a debugging log could make
an implementation vulnerable to a fill-up-the-users-disk attack.
================================================
FILE: bip-0062.mediawiki
================================================
'''NOTICE: This document is a work in progress and is not complete, implemented, or otherwise suitable for deployment.'''
==Abstract==
This document specifies proposed changes to the Bitcoin transaction validity rules in order to make malleability of transactions impossible (at least when the sender doesn't choose to avoid it).
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
As of february 2014, Bitcoin transactions are malleable in multiple ways. This means a (valid) transaction can be modified in-flight, without invalidating it, but without access to the relevant private keys.
This is a problem for multiple reasons:
* The sender may not recognize his own transaction after being modified.
* The sender may create transactions that spend change created by the original transaction. In case the modified transaction gets mined, this becomes invalid.
* Modified transactions are effectively double-spends which can be created without malicious intent (of the sender), but can be used to make other attacks easier.
Several sources of malleability are known:
# '''Non-DER encoded ECDSA signatures''' Right now, the Bitcoin reference client uses OpenSSL to validate signatures. As OpenSSL accepts more than serializations that strictly adhere to the DER standard, this is a source of malleability. Since v0.8.0, non-DER signatures are no longer relayed already.
# '''Non-push operations in scriptSig''' Any sequence of script operations in scriptSig that results in the intended data pushes, but is not just a push of that data, results in an alternative transaction with the same validity.
# '''Push operations in scriptSig of non-standard size type''' The Bitcoin scripting language has several push operators (OP_0, single-byte pushes, data pushes of up to 75 bytes, OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4). As the latter ones have the same result as the former ones, they result in additional possibilities.
# '''Zero-padded number pushes''' In cases where scriptPubKey opcodes use inputs that are interpreted as numbers, they can be zero padded.
# '''Inherent ECDSA signature malleability''' ECDSA signatures themselves are already malleable: taking the negative of the number S inside (modulo the curve order) does not invalidate it.
# '''Superfluous scriptSig operations''' Adding extra data pushes at the start of scripts, which are not consumed by the corresponding scriptPubKey, is also a source of malleability.
# '''Inputs ignored by scripts''' If a scriptPubKey starts with an OP_DROP, for example, the last data push of the corresponding scriptSig will always be ignored.
# '''Sighash flags based masking''' Sighash flags can be used to ignore certain parts of a script when signing.
# '''New signatures by the sender''' The sender (or anyone with access to the relevant private keys) is always able to create new signatures that spend the same inputs to the same outputs.
The first six and part of the seventh can be fixed by extra consensus rules, but the last two can't. Not being able to fix #7 means that even with these new consensus rules, it will always be possible to create outputs whose spending transactions will all be malleable. However, when restricted to using a safe set of output scripts, extra consensus rules can make spending transactions optionally non-malleable (if the spender chooses to; as he can always bypass #8 and #9 himself).
==Specification==
===New rules===
Seven extra rules are introduced, to combat exactly the seven first sources of malleability listed above:
# '''Canonically encoded ECDSA signatures''' An ECDSA signature passed to OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG or OP_CHECKMULTISIGVERIFY must be encoded using strict DER encoding. To provide a compact way to deliberately create an invalid signature for OP_CHECKSIG and OP_CHECKMULTISIG, an empty byte array (i.e., the result of OP_0) is also allowed. Doing a verification with a non-DER signature makes the entire script evaluate to False (not just the signature verification). See reference: [[#der-encoding|DER encoding]].
# '''Non-push operations in scriptSig''' Only data pushes are allowed in scriptSig. Evaluating any other operation makes the script evaluate to false. See reference: [[#push-operators|Push operators]].
# '''Push operations in scriptSig of non-standard size type''' The smallest possible push operation must be used when possible. Pushing data using an operation that could be encoded in a shorter way makes the script evaluate to false. See reference: [[#push-operators|Push operators]].
# '''Zero-padded number pushes''' Any time a script opcode consumes a stack value that is interpreted as a number, it must be encoded in its shortest possible form. 'Negative zero' is not allowed. See reference: [[#numbers|Numbers]].
# '''Inherent ECDSA signature malleability''' We require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially restricting this value to its lower half range). See reference: [[#low-s-values-in-signatures|Low S values in signatures]].
# '''Superfluous scriptSig operations''' scriptPubKey evaluation will be required to result in a single non-zero value. If any extra data elements remain on the stack, the script evaluates to false.
# '''Inputs ignored by scripts''' The (unnecessary) extra stack element consumed by OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY must be the empty byte array (the result of OP_0). Anything else makes the script evaluate to false.
===Block validity===
To introduce these new rules in the network, we add both v3 blocks and v3 transactions. v2 is skipped for transactions to keep the version numbers between transaction and block rules in sync. v2 transactions are treated identically to v1 transactions.
The same mechanism as in BIP 0034 is used to introduce v3 blocks. When 75% of the past 1000 blocks are v3, a new consensus rule is activated:
* All transactions in v3 blocks are required to follow rules #1-#2.
* v3 (and higher) transactions in v3 blocks are required to follow rules #3-#7 as well.
When 95% of the past 1000 blocks are v3 or higher, v2 blocks become invalid entirely. Note however that v1 (and v2) transactions remain valid forever.
===References===
Below is a summary of the effects on signatures, their encoding and data pushes.
====Low S values in signatures====
The value S in signatures must be between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive). If S is too high, simply replace it by S' = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S.
Signatures produced by the OpenSSL library are not guaranteed to be consistent with this constraint. Version 0.9.3 of the reference client provides [https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/key.cpp#L202-L227 an example] for detection and correction.
The constraints on the value R are unchanged w.r.t. ECDSA, and values can be between 0x1 and 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364140 (inclusive).
====DER encoding====
For reference, here is how to encode signatures correctly in DER format.
0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash-type]
* total-length: 1-byte length descriptor of everything that follows, excluding the sighash byte.
* R-length: 1-byte length descriptor of the R value that follows.
* R: arbitrary-length big-endian encoded R value. It cannot start with any 0x00 bytes, unless the first byte that follows is 0x80 or higher, in which case a single 0x00 is required.
* S-length: 1-byte length descriptor of the S value that follows.
* S: arbitrary-length big-endian encoded S value. The same rules apply as for R.
* sighash-type: 1-byte hashtype flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed).
This is already enforced by the reference client as of version 0.8.0 (only as relay policy, not as a consensus rule).
This rule, combined with the low S requirement above, results in S-length being at most 32 (and R-length at most 33), and the total signature size being at most 72 bytes (and on average 71.494 bytes).
====Push operators====
* Pushing an empty byte sequence must use OP_0.
* Pushing a 1-byte sequence of byte 0x01 through 0x10 must use OP_n.
* Pushing the byte 0x81 must use OP_1NEGATE.
* Pushing any other byte sequence up to 75 bytes must use the normal data push (opcode byte n, with n the number of bytes, followed n bytes of data being pushed).
* Pushing 76 to 255 bytes must use OP_PUSHDATA1.
* Pushing 256 to 520 bytes must use OP_PUSHDATA2.
* OP_PUSHDATA4 can never be used, as pushes over 520 bytes are not allowed, and those below can be done using other operators.
* Any other operation is not considered to be a push.
====Numbers====
The native data type of stack elements is byte arrays, but some operations interpret arguments as integers. The used encoding is little endian with an explicit sign bit (the highest bit of the last byte). The shortest encodings for numbers are (with the range boundaries encodings given in hex between ()).
* 0: OP_0; (00)
* 1..16: OP_1..OP_16; (51)..(60)
* -1: OP_1NEGATE; (79)
* -127..-2 and 17..127: normal 1-byte data push; (01 FF)..(01 82) and (01 11)..(01 7F)
* -32767..-128 and 128..32767: normal 2-byte data push; (02 FF FF)..(02 80 80) and (02 80 00)..(02 FF 7F)
* -8388607..-32768 and 32768..8388607: normal 3-byte data push; (03 FF FF FF)..(03 00 80 80) and (03 00 80 00)..(03 FF FF 7F)
* -2147483647..-8388608 and 8388608..2147483647: normal 4-byte data push; (04 FF FF FF FF)..(04 00 00 80 80) and (04 00 00 80 00)..(04 FF FF FF 7F)
* Any other numbers cannot be encoded.
In particular, note that zero could be encoded as (01 80) (negative zero) if using the non-shortest form is allowed.
==Compatibility==
'''Relay of transactions''' A new node software version is released which makes v3 transactions standard, and relays them when their scriptSigs satisfy the above rules. Relaying of v1 transactions is unaffected. A v1 transaction spending an output created by a v3 transaction is also unaffected.
'''Wallet updates''' As v3 transactions are non-standard currently, it is not possible to start creating them immediately. Software can be checked to confirm to the new rules of course, but using v3 should only start when a significant part of the network's nodes has upgraded to compatible code. Its intended meaning is "I want this transaction protected from malleability", and remains a choice of the wallet software.
================================================
FILE: bip-0064.mediawiki
================================================
==Abstract==
This document describes a small P2P protocol extension that performs UTXO lookups given a set of outpoints.
==Motivation==
All full Bitcoin nodes maintain a database called the unspent transaction output set. This set is
how double spending is checked for: to be valid a transaction must identify unspent outputs in this
set using an identifier called an "outpoint", which is merely the hash of the output's containing
transaction plus an index.
The ability to query this can sometimes be useful for a lightweight/SPV client which does not have
the full UTXO set at hand. For example, it can be useful in applications implementing assurance
contracts to do a quick check when a new pledge becomes visible to test whether that pledge was
already revoked via a double spend. Although this message is not strictly necessary because e.g.
such an app could be implemented by fully downloading and storing the block chain, it is useful for
obtaining acceptable performance and resolving various UI cases.
Another example of when this data can be useful is for performing floating fee calculations in an
SPV wallet. This use case requires some other changes to the Bitcoin protocol however, so we will
not dwell on it here.
==Specification==
Two new messages are defined. The "getutxos" message has the following structure:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 1 || check mempool || bool || Whether to apply mempool transactions during the calculation, thus exposing their UTXOs and removing outputs that they spend.
|-
| ? || outpoints || vector || The list of outpoints to be queried. Each outpoint is serialized in the same way it is in a tx message.
|}
The response message "utxos" has the following structure:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 4 || chain height || uint32 || The height of the chain at the moment the result was calculated.
|-
| 32 || chain tip hash || uint256 || Block hash of the top of the chain at the moment the result was calculated.
|-
| ? || hit bitmap || byte[] || An array of bytes encoding one bit for each outpoint queried. Each bit indicates whether the queried outpoint was found in the UTXO set or not.
|-
| ? || result utxos || result[] || A list of result objects (defined below), one for each outpoint that is unspent (i.e. has a bit set in the bitmap).
|}
The result object is defined as:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 4 || tx version || uint32 || The version number of the transaction the UTXO was found in.
|-
| 4 || height || uint32 || The height of the block containing the defining transaction, or 0x7FFFFFFF if the tx is in the mempool.
|-
| ? || output || CTxOut || The output itself, serialized in the same way as in a tx message.
|}
==Backward compatibility==
Nodes indicate support by advertising a protocol version above 70003 and by setting a new
NODE_GETUTXO flag in their nServices field, which has a value of 2 (the second bit of the field).
==Authentication==
The UTXO set is not currently authenticated by anything. There are proposals to resolve this by
introducing a new consensus rule that commits to a root hash of the UTXO set in blocks, however this
feature is not presently available in the Bitcoin protocol. Once it is, the utxos message could be
upgraded to include Merkle branches showing inclusion of the UTXOs in the committed sets.
If the requesting client is looking up outputs for a signed transaction that they have locally, the
client can partly verify the returned output by running the input scripts with it. Currently this
verifies only that the script is correct. A future version of the Bitcoin protocol is likely to also
allow the value to be checked in this way. It does not show that the output is really unspent or was
ever actually created in the block chain however. Additionally, the form of the provided scriptPubKey
should be checked before execution to ensure the remote peer doesn't just set the script to OP_TRUE.
If the requesting client has a mapping of chain heights to block hashes in the best chain e.g.
obtained via getheaders, then they can obtain a proof that the output did at one point exist by
requesting the block and searching for the output within it. When combined with Bloom filtering this
can be reasonably efficient.
Note that even when the outputs are being checked against something this protocol has the same
security model as Bloom filtering: a remote node can lie through omission by claiming the requested
UTXO does not exist / was already spent (they are the same, from the perspective of a full node).
Querying multiple nodes and combining their answers can be a partial solution to this, although as
nothing authenticates the Bitcoin P2P network a man in the middle could still yield incorrect
results.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/4351/files
================================================
FILE: bip-0065.mediawiki
================================================
==Abstract==
This BIP describes a new opcode (OP_CHECKLOCKTIMEVERIFY) for the Bitcoin
scripting system that allows a transaction output to be made unspendable until
some point in the future.
==Summary==
CHECKLOCKTIMEVERIFY redefines the existing NOP2 opcode. When executed, if
any of the following conditions are true, the script interpreter will terminate
with an error:
* the stack is empty; or
* the top item on the stack is less than 0; or
* the lock-time type (height vs. timestamp) of the top stack item and the nLockTime field are not the same; or
* the top stack item is greater than the transaction's nLockTime field; or
* the nSequence field of the txin is 0xffffffff;
Otherwise, script execution will continue as if a NOP had been executed.
The nLockTime field in a transaction prevents the transaction from being mined
until either a certain block height, or block time, has been reached. By
comparing the argument to CHECKLOCKTIMEVERIFY against the nLockTime field, we
indirectly verify that the desired block height or block time has been reached;
until that block height or block time has been reached the transaction output
remains unspendable.
==Motivation==
The nLockTime field in transactions can be used to prove that it is
''possible'' to spend a transaction output in the future, by constructing a
valid transaction spending that output with the nLockTime field set.
However, the nLockTime field can't prove that it is ''impossible'' to spend a
transaction output until some time in the future, as there is no way to know if
a valid signature for a different transaction spending that output has been
created.
===Escrow===
If Alice and Bob jointly operate a business they may want to
ensure that all funds are kept in 2-of-2 multisig transaction outputs that
require the co-operation of both parties to spend. However, they recognise that
in exceptional circumstances such as either party getting "hit by a bus" they
need a backup plan to retrieve the funds. So they appoint their lawyer, Lenny,
to act as a third-party.
With a standard 2-of-3 CHECKMULTISIG at any time Lenny could conspire with
either Alice or Bob to steal the funds illegitimately. Equally Lenny may prefer
not to have immediate access to the funds to discourage bad actors from
attempting to get the secret keys from him by force.
However, with CHECKLOCKTIMEVERIFY the funds can be stored in scriptPubKeys of
the form:
IF
CHECKLOCKTIMEVERIFY DROP
CHECKSIGVERIFY
1
ELSE
2
ENDIF
2 CHECKMULTISIG
At any time the funds can be spent with the following scriptSig:
0 0
After 3 months have passed Lenny and one of either Alice or Bob can spend the
funds with the following scriptSig:
0 1
===Non-interactive time-locked refunds===
There exist a number of protocols where a transaction output is created that
requires the co-operation of both parties to spend the output. To ensure the
failure of one party does not result in the funds becoming lost, refund
transactions are setup in advance using nLockTime. These refund transactions
need to be created interactively, and additionally, are currently vulnerable to
transaction malleability. CHECKLOCKTIMEVERIFY can be used in these protocols,
replacing the interactive setup with a non-interactive setup, and additionally,
making transaction malleability a non-issue.
====Two-factor wallets====
Services like GreenAddress store bitcoins with 2-of-2 multisig scriptPubKey's
such that one keypair is controlled by the user, and the other keypair is
controlled by the service. To spend funds the user uses locally installed
wallet software that generates one of the required signatures, and then uses a
2nd-factor authentication method to authorize the service to create the second
SIGHASH_NONE signature that is locked until some time in the future and sends
the user that signature for storage. If the user needs to spend their funds and
the service is not available, they wait until the nLockTime expires.
The problem is there exist numerous occasions the user will not have a valid
signature for some or all of their transaction outputs. With
CHECKLOCKTIMEVERIFY rather than creating refund signatures on demand
scriptPubKeys of the following form are used instead:
IF
CHECKSIGVERIFY
ELSE
CHECKLOCKTIMEVERIFY DROP
ENDIF
CHECKSIG
Now the user is always able to spend their funds without the co-operation of
the service by waiting for the expiry time to be reached.
====Payment Channels====
Jeremy Spilman style payment channels first setup a deposit controlled by
2-of-2 multisig, tx1, and then adjust a second transaction, tx2, that spends
the output of tx1 to payor and payee. Prior to publishing tx1 a refund
transaction is created, tx3, to ensure that should the payee vanish the payor
can get their deposit back. The process by which the refund transaction is
created is currently vulnerable to transaction malleability attacks, and
additionally, requires the payor to store the refund. Using the same
scriptPubKey form as in the Two-factor wallets example solves both these issues.
===Trustless Payments for Publishing Data===
The PayPub protocol makes it possible to pay for information in a trustless way
by first proving that an encrypted file contains the desired data, and secondly
crafting scriptPubKeys used for payment such that spending them reveals the
encryption keys to the data. However the existing implementation has a
significant flaw: the publisher can delay the release of the keys indefinitely.
This problem can be solved interactively with the refund transaction technique;
with CHECKLOCKTIMEVERIFY the problem can be non-interactively solved using
scriptPubKeys of the following form:
IF
HASH160 EQUALVERIFY
CHECKSIG
ELSE
CHECKLOCKTIMEVERIFY DROP
CHECKSIG
ENDIF
The buyer of the data is now making a secure offer with an expiry time. If the
publisher fails to accept the offer before the expiry time is reached the buyer
can cancel the offer by spending the output.
===Proving sacrifice to miners' fees===
Proving the sacrifice of some limited resource is a common technique in a
variety of cryptographic protocols. Proving sacrifices of coins to mining fees
has been proposed as a ''universal public good'' to which the sacrifice could
be directed, rather than simply destroying the coins. However doing so is
non-trivial, and even the best existing technique - announce-commit sacrifices
- could encourage mining centralization. CHECKLOCKTIMEVERIFY can be used to
create outputs that are provably spendable by anyone (thus to mining fees
assuming miners behave optimally and rationally) but only at a time
sufficiently far into the future that large miners can't profitably sell the
sacrifices at a discount.
===Freezing Funds===
In addition to using cold storage, hardware wallets, and P2SH multisig outputs
to control funds, now funds can be frozen in UTXOs directly on the blockchain.
With the following scriptPubKey, nobody will be able to spend the encumbered
output until the provided expiry time. This ability to freeze funds reliably may
be useful in scenarios where reducing duress or confiscation risk is desired.
CHECKLOCKTIMEVERIFY DROP DUP HASH160 EQUALVERIFY CHECKSIG
===Replacing the nLockTime field entirely===
As an aside, note how if the SignatureHash() algorithm could optionally cover
part of the scriptSig the signature could require that the scriptSig contain
CHECKLOCKTIMEVERIFY opcodes, and additionally, require that they be executed.
(the CODESEPARATOR opcode came very close to making this possible in v0.1 of
Bitcoin) This per-signature capability could replace the per-transaction
nLockTime field entirely as a valid signature would now be the proof that a
transaction output ''can'' be spent.
==Detailed Specification==
Refer to the reference implementation, reproduced below, for the precise
semantics and detailed rationale for those semantics.
case OP_NOP2:
{
// CHECKLOCKTIMEVERIFY
//
// (nLockTime -- nLockTime )
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
break; // not enabled; treat as a NOP
if (stack.size() < 1)
return false;
// Note that elsewhere numeric opcodes are limited to
// operands in the range -2**31+1 to 2**31-1, however it is
// legal for opcodes to produce results exceeding that
// range. This limitation is implemented by CScriptNum's
// default 4-byte limit.
//
// If we kept to that limit we'd have a year 2038 problem,
// even though the nLockTime field in transactions
// themselves is uint32 which only becomes meaningless
// after the year 2106.
//
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums, which are good until 2**32-1, the
// same limit as the nLockTime field itself.
const CScriptNum nLockTime(stacktop(-1), 5);
// In the rare event that the argument may be < 0 due to
// some arithmetic being done first, you can always use
// 0 MAX CHECKLOCKTIMEVERIFY.
if (nLockTime < 0)
return false;
// There are two types of nLockTime: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
// nLockTime < LOCKTIME_THRESHOLD.
//
// We want to compare apples to apples, so fail the script
// unless the type of nLockTime being tested is the same as
// the nLockTime in the transaction.
if (!(
(txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
))
return false;
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nLockTime > (int64_t)txTo.nLockTime)
return false;
// Finally the nLockTime feature can be disabled and thus
// CHECKLOCKTIMEVERIFY bypassed if every txin has been
// finalized by setting nSequence to maxint. The
// transaction would be allowed into the blockchain, making
// the opcode ineffective.
//
// Testing if this vin is not final is sufficient to
// prevent this condition. Alternatively we could test all
// inputs, but testing just this input minimizes the data
// required to prove correct CHECKLOCKTIMEVERIFY execution.
if (txTo.vin[nIn].IsFinal())
return false;
break;
}
https://github.com/petertodd/bitcoin/commit/ab0f54f38e08ee1e50ff72f801680ee84d0f1bf4
==Deployment==
We reuse the double-threshold IsSuperMajority() switchover mechanism used in
BIP66 with the same thresholds, but for nVersion = 4. The new rules are
in effect for every block (at height H) with nVersion = 4 and at least
750 out of 1000 blocks preceding it (with heights H-1000..H-1) also
have nVersion >= 4. Furthermore, when 950 out of the 1000 blocks
preceding a block do have nVersion >= 4, nVersion < 4 blocks become
invalid, and all further blocks enforce the new rules.
It should be noted that BIP9 involves permanently setting a high-order bit to
1 which results in nVersion >= all prior IsSuperMajority() soft-forks and thus
no bits in nVersion are permanently lost.
===SPV Clients===
While SPV clients are (currently) unable to validate blocks in general,
trusting miners to do validation for them, they are able to validate block
headers and thus can validate a subset of the deployment rules. SPV clients
should reject nVersion < 4 blocks if 950 out of 1000 preceding blocks have
nVersion >= 4 to prevent false confirmations from the remaining 5% of
non-upgraded miners when the 95% threshold has been reached.
==Credits==
Thanks goes to Gregory Maxwell for suggesting that the argument be compared
against the per-transaction nLockTime, rather than the current block height and
time.
==References==
PayPub
* https://github.com/unsystem/paypub
Jeremy Spilman Payment Channels
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2013-April/002433.html
==Implementations==
Python / python-bitcoinlib
* https://github.com/petertodd/checklocktimeverify-demos
JavaScript / Node.js / bitcore
* https://github.com/mruddy/bip65-demos
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0066.mediawiki
================================================
==Abstract==
This document specifies proposed changes to the Bitcoin transaction validity rules to restrict signatures to strict DER encoding.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
Bitcoin's reference implementation currently relies on OpenSSL for signature validation, which means it is implicitly defining Bitcoin's block validity rules. Unfortunately, OpenSSL is not designed for consensus-critical behaviour (it does not guarantee bug-for-bug compatibility between versions), and thus changes to it can - and have - affected Bitcoin software.
One specifically critical area is the encoding of signatures. Until recently, OpenSSL's releases would accept various deviations from the DER standard and accept signatures as valid. When this changed in OpenSSL 1.0.0p and 1.0.1k, it made some nodes reject the chain.
This document proposes to restrict valid signatures to exactly what is mandated by DER, to make the consensus rules not depend on OpenSSL's signature parsing. A change like this is required if implementations would want to remove all of OpenSSL from the consensus code.
==Specification==
Every signature passed to OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, or OP_CHECKMULTISIGVERIFY, to which ECDSA verification is applied, must be encoded using strict DER encoding (see further).
These operators all perform ECDSA verifications on pubkey/signature pairs, iterating from the top of the stack backwards. For each such verification, if the signature does not pass the IsValidSignatureEncoding check below, the entire script evaluates to false immediately. If the signature is valid DER, but does not pass ECDSA verification, opcode execution continues as it used to, causing opcode execution to stop and push false on the stack (but not immediately fail the script) in some cases, which potentially skips further signatures (and thus does not subject them to IsValidSignatureEncoding).
===DER encoding reference===
The following code specifies the behaviour of strict DER checking. Note that this function tests a signature byte vector which includes the 1-byte sighash flag that Bitcoin adds, even though that flag falls outside of the DER specification, and is unaffected by this proposal. The function is also not called for cases where the length of sig is 0, in order to provide a simple, short and efficiently-verifiable encoding for deliberately invalid signatures.
DER is specified in https://www.itu.int/rec/T-REC-X.690/en .
bool static IsValidSignatureEncoding(const std::vector &sig) {
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
// * total-length: 1-byte length descriptor of everything that follows,
// excluding the sighash byte.
// * R-length: 1-byte length descriptor of the R value that follows.
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
// possible encoding for a positive integers (which means no null bytes at
// the start, except a single one when the next byte has its highest bit set).
// * S-length: 1-byte length descriptor of the S value that follows.
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
// * sighash: 1-byte value indicating what data is hashed (not part of the DER
// signature)
// Minimum and maximum size constraints.
if (sig.size() < 9) return false;
if (sig.size() > 73) return false;
// A signature is of type 0x30 (compound).
if (sig[0] != 0x30) return false;
// Make sure the length covers the entire signature.
if (sig[1] != sig.size() - 3) return false;
// Extract the length of the R element.
unsigned int lenR = sig[3];
// Make sure the length of the S element is still inside the signature.
if (5 + lenR >= sig.size()) return false;
// Extract the length of the S element.
unsigned int lenS = sig[5 + lenR];
// Verify that the length of the signature matches the sum of the length
// of the elements.
if ((size_t)(lenR + lenS + 7) != sig.size()) return false;
// Check whether the R element is an integer.
if (sig[2] != 0x02) return false;
// Zero-length integers are not allowed for R.
if (lenR == 0) return false;
// Negative numbers are not allowed for R.
if (sig[4] & 0x80) return false;
// Null bytes at the start of R are not allowed, unless R would
// otherwise be interpreted as a negative number.
if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
// Check whether the S element is an integer.
if (sig[lenR + 4] != 0x02) return false;
// Zero-length integers are not allowed for S.
if (lenS == 0) return false;
// Negative numbers are not allowed for S.
if (sig[lenR + 6] & 0x80) return false;
// Null bytes at the start of S are not allowed, unless S would otherwise be
// interpreted as a negative number.
if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false;
return true;
}
===Examples===
Notation: P1 and P2 are valid, serialized, public keys. S1 and S2 are valid signatures using respective keys P1 and P2. S1' and S2' are non-DER but otherwise valid signatures using those same keys. F is any invalid but DER-compliant signature (including 0, the empty string). F' is any invalid and non-DER-compliant signature.
# S1' P1 CHECKSIG fails (changed)
# S1' P1 CHECKSIG NOT fails (unchanged)
# F P1 CHECKSIG fails (unchanged)
# F P1 CHECKSIG NOT can succeed (unchanged)
# F' P1 CHECKSIG fails (unchanged)
# F' P1 CHECKSIG NOT fails (changed)
# 0 S1' S2 2 P1 P2 2 CHECKMULTISIG fails (changed)
# 0 S1' S2 2 P1 P2 2 CHECKMULTISIG NOT fails (unchanged)
# 0 F S2' 2 P1 P2 2 CHECKMULTISIG fails (unchanged)
# 0 F S2' 2 P1 P2 2 CHECKMULTISIG NOT fails (changed)
# 0 S1' F 2 P1 P2 2 CHECKMULTISIG fails (unchanged)
# 0 S1' F 2 P1 P2 2 CHECKMULTISIG NOT can succeed (unchanged)
Note that the examples above show that only additional failures are required by this change, as required for a soft forking change.
==Deployment==
We reuse the double-threshold switchover mechanism from BIP 34, with the same thresholds, but for nVersion = 3. The new rules are in effect for every block (at height H) with nVersion = 3 and at least 750 out of 1000 blocks preceding it (with heights H-1000..H-1) also have nVersion = 3. Furthermore, when 950 out of the 1000 blocks preceding a block do have nVersion = 3, nVersion = 2 blocks become invalid, and all further blocks enforce the new rules.
==Compatibility==
The requirement to have signatures that comply strictly with DER has been enforced as a relay policy by the reference client since v0.8.0, and very few transactions violating it are being added to the chain as of January 2015. In addition, every non-compliant signature can trivially be converted into a compliant one, so there is no loss of functionality by this requirement. This proposal has the added benefit of reducing transaction malleability (see BIP 62).
==Implementation==
An implementation for the reference client is available at https://github.com/bitcoin/bitcoin/pull/5713
==Acknowledgements==
This document is extracted from the previous BIP62 proposal, which had input from various people, in particular Greg Maxwell and Peter Todd, who gave feedback about this document as well.
==Disclosures==
* Subsequent to the network-wide adoption and enforcement of this BIP, the author [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-July/009697.html disclosed] that strict DER signatures provided an indirect solution to a consensus bug he had previously discovered.
================================================
FILE: bip-0067.mediawiki
================================================
BIP: 67
Layer: Applications
Title: Deterministic Pay-to-script-hash multi-signature addresses through public key sorting
Authors: Thomas Kerin
Jean-Pierre Rupp
Ruben de Vries
Status: Complete
Type: Specification
Assigned: 2015-02-08
License: PD
==Abstract==
This BIP describes a method to deterministically generate multi-signature pay-to-script-hash transaction scripts. It focuses on defining how the public keys must be encoded and sorted so that the redeem script and corresponding P2SH address are always the same for a given set of keys and number of required signatures.
==Motivation==
Pay-to-script-hash (BIP-0011[https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki BIP-0011]) is a transaction type that allows funding of arbitrary scripts, where the recipient carries the cost of fee's associated with using longer, more complex scripts.
Multi-signature pay-to-script-hash transactions are defined in BIP-0016[https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki BIP-0016]. The redeem script does not require a particular ordering or encoding for public keys. This means that for a given set of keys and number of required signatures, there are as many as 2(n!) possible standard redeem scripts, each with its separate P2SH address. Adhering to an ordering and key encoding would ensure that a multi-signature “account” (set of public keys and required signature count) has a canonical P2SH address.
By adopting a sorting and encoding standard, compliant wallets will always produce the same P2SH address for the same given set of keys and required signature count, making it easier to recognize transactions involving that multi-signature account. This is particularly attractive for multisignature hierarchical-deterministic wallets, as less state is required to setup multi-signature accounts: only the number of required signatures and master public keys of participants need to be shared, and all wallets will generate the same addresses.
While most web wallets do not presently facilitate the setup of multisignature accounts with users of a different service, conventions which ensure cross-compatibility should make it easier to achieve this.
Many wallet as a service providers use a 2of3 multi-signature schema where the user stores 1 of the keys (offline) as backup while using the other key for daily use and letting the service cosign his transactions.
This standard will help in enabling a party other than the service provider to recover the wallet without any help from the service provider.
==Specification==
For a set of public keys, ensure that they have been received in compressed form:
022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da
03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9
021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18
Sort them lexicographically according to their binary representation:
021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18
022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da
03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9
..before using the resulting list of keys in a standard multisig redeem script:
OP_2 021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18 022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da 03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9 OP_3 OP_CHECKMULTISIG
Hash the redeem script according to BIP-0016 to get the P2SH address.
3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba
==Compatibility==
* Uncompressed keys are incompatible with this specification. A compatible implementation should not automatically compress keys. Receiving an uncompressed key from a multisig participant should be interpreted as a sign that the user has an incompatible implementation.
* P2SH addresses do not reveal information about the script that is receiving the funds. For this reason it is not technically possible to enforce this BIP as a rule on the network. Also, it would cause a hard fork.
* Implementations that do not conform with this BIP will have compatibility issues with strictly-compliant wallets.
* Implementations which do adopt this standard will be cross-compatible when choosing multisig addresses.
* If a group of users were not entirely compliant, there is the possibility that a participant will derive an address that the others will not recognize as part of the common multisig account.
==Test vectors==
Two signatures are required in each of these test vectors.
Vector 1
* List
** 02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8
** 02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f
* Sorted
** 02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f
** 02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8
* Script
** 522102fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f2102ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f852ae
* Address
** 39bgKC7RFbpoCRbtD5KEdkYKtNyhpsNa3Z
Vector 2 (Already sorted, no action required)
* List:
** 02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed0
** 027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e77
** 02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404
* Sorted:
** 02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed0
** 027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e77
** 02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404
* Script
** 522102632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed021027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e772102e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b40453ae
* Address
** 3CKHTjBKxCARLzwABMu9yD85kvtm7WnMfH
Vector 3:
* List:
** 030000000000000000000000000000000000004141414141414141414141414141
** 020000000000000000000000000000000000004141414141414141414141414141
** 020000000000000000000000000000000000004141414141414141414141414140
** 030000000000000000000000000000000000004141414141414141414141414140
* Sorted:
** 020000000000000000000000000000000000004141414141414141414141414140
** 020000000000000000000000000000000000004141414141414141414141414141
** 030000000000000000000000000000000000004141414141414141414141414140
** 030000000000000000000000000000000000004141414141414141414141414141
* Script
** 522102000000000000000000000000000000000000414141414141414141414141414021020000000000000000000000000000000000004141414141414141414141414141210300000000000000000000000000000000000041414141414141414141414141402103000000000000000000000000000000000000414141414141414141414141414154ae
* Address
** 32V85igBri9zcfBRVupVvwK18NFtS37FuD
Vector 4: (from bitcore)
* List:
** 022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da
** 03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9
** 021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18
* Sorted:
** 021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18
** 022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da
** 03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9
* Script
** 5221021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc1821022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da2103e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e953ae
* Address
** 3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba
==Acknowledgements==
The authors wish to thank BtcDrak and Luke-Jr for their involvement & contributions in the early discussions of this BIP.
==Usage & Implementations==
* [[https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki#address-generation-procedure|BIP-0045]] - Structure for Deterministic P2SH Multisignature Wallets
* [[https://github.com/bitpay/bitcore/blob/50a868cb8cdf2be04bb1c5bf4bcc064cc06f5888/lib/script/script.js#L541|Bitcore]]
* [[https://github.com/haskoin/haskoin-core/blob/b41b1deb0989334a7ead6fc993fb8b02f0c00810/haskoin-core/Network/Haskoin/Script/Parser.hs#L112-L122|Haskoin]] - Bitcoin implementation in Haskell
* [[https://github.com/etotheipi/BitcoinArmory/blob/268db0f3fa20c989057bd43343a43b2edbe89aeb/armoryengine/ArmoryUtils.py#L1441|Armory]]
* [[https://github.com/bitcoinj/bitcoinj/blob/f7ea0b92a619800c143b0142dc70306da33119a9/core/src/main/java/org/bitcoinj/script/ScriptBuilder.java#L331|BitcoinJ]]
== References ==
== Copyright ==
This document is placed in the public domain.
================================================
FILE: bip-0068.mediawiki
================================================
BIP: 68
Layer: Consensus (soft fork)
Title: Relative lock-time using consensus-enforced sequence numbers
Authors: Mark Friedenbach
BtcDrak
Nicolas Dorier
kinoshitajona
Status: Deployed
Type: Specification
Assigned: 2015-05-28
==Abstract==
This BIP introduces relative lock-time (RLT) consensus-enforced semantics of the sequence number field to enable a signed transaction input to remain invalid for a defined period of time after confirmation of its corresponding outpoint.
==Motivation==
Bitcoin transactions have a sequence number field for each input. The original idea appears to have been that a transaction in the mempool would be replaced by using the same input with a higher sequence value. Although this was not properly implemented, it assumes miners would prefer higher sequence numbers even if the lower ones were more profitable to mine. However, a miner acting on profit motives alone would break that assumption completely. The change described by this BIP repurposes the sequence number for new use cases without breaking existing functionality. It also leaves room for future expansion and other use cases.
The transaction nLockTime is used to prevent the mining of a transaction until a certain date. nSequence will be repurposed to prevent mining of a transaction until a certain age of the spent output in blocks or timespan. This, among other uses, allows bi-directional payment channels as used in [https://github.com/ElementsProject/lightning/raw/master/doc/miscellaneous/deployable-lightning.pdf Hashed Timelock Contracts (HTLCs)] and [https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki#Bidirectional_Payment_Channels BIP112].
==Specification==
This specification defines the meaning of sequence numbers for transactions with an nVersion greater than or equal to 2 for which the rest of this specification relies on.
All references to median-time-past (MTP) are as defined by BIP113.
If bit (1 << 31) of the sequence number is set, then no consensus meaning is applied to the sequence number and can be included in any block under all currently possible circumstances.
If bit (1 << 31) of the sequence number is not set, then the sequence number is interpreted as an encoded relative lock-time.
The sequence number encoding is interpreted as follows:
Bit (1 << 22) determines if the relative lock-time is time-based or block based: If the bit is set, the relative lock-time specifies a timespan in units of 512 seconds granularity. The timespan starts from the median-time-past of the output’s previous block, and ends at the MTP of the previous block. If the bit is not set, the relative lock-time specifies a number of blocks.
The flag (1<<22) is the highest order bit in a 3-byte signed integer for use in bitcoin scripts as a 3-byte PUSHDATA with OP_CHECKSEQUENCEVERIFY (BIP 112).
This specification only interprets 16 bits of the sequence number as relative lock-time, so a mask of 0x0000ffff MUST be applied to the sequence field to extract the relative lock-time. The 16-bit specification allows for a year of relative lock-time and the remaining bits allow for future expansion.
For time based relative lock-time, 512 second granularity was chosen because bitcoin blocks are generated every 600 seconds. So when using block-based or time-based, the same amount of time can be encoded with the available number of bits. Converting from a sequence number to seconds is performed by multiplying by 512 = 2^9, or equivalently shifting up by 9 bits.
When the relative lock-time is time-based, it is interpreted as a minimum block-time constraint over the input's age. A relative time-based lock-time of zero indicates an input which can be included in any block. More generally, a relative time-based lock-time n can be included into any block produced 512 * n seconds after the mining date of the output it is spending, or any block thereafter.
The mining date of the output is equal to the median-time-past of the previous block which mined it.
The block produced time is equal to the median-time-past of its previous block.
When the relative lock-time is block-based, it is interpreted as a minimum block-height constraint over the input's age. A relative block-based lock-time of zero indicates an input which can be included in any block. More generally, a relative block lock-time n can be included n blocks after the mining date of the output it is spending, or any block thereafter.
The new rules are not applied to the nSequence field of the input of the coinbase transaction.
==Implementation==
A reference implementation is provided by the following pull request
https://github.com/bitcoin/bitcoin/pull/7184
enum {
/* Interpret sequence numbers as relative lock-time constraints. */
LOCKTIME_VERIFY_SEQUENCE = (1 << 0),
};
/* Setting nSequence to this value for every input in a transaction
* disables nLockTime. */
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
/* Below flags apply in the context of BIP 68*/
/* If this flag set, CTxIn::nSequence is NOT interpreted as a
* relative lock-time. */
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
/* If CTxIn::nSequence encodes a relative lock-time and this flag
* is set, the relative lock-time has units of 512 seconds,
* otherwise it specifies blocks with a granularity of 1. */
static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
/* If CTxIn::nSequence encodes a relative lock-time, this mask is
* applied to extract that lock-time from the sequence field. */
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
/* In order to use the same number of bits to encode roughly the
* same wall-clock duration, and because blocks are naturally
* limited to occur every 600s on average, the minimum granularity
* for time-based relative lock-time is fixed at 512 seconds.
* Converting from CTxIn::nSequence to seconds is performed by
* multiplying by 512 = 2^9, or equivalently shifting up by
* 9 bits. */
static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
/**
* Calculates the block height and previous block's median time past at
* which the transaction will be considered final in the context of BIP 68.
* Also removes from the vector of input heights any entries which did not
* correspond to sequence locked inputs as they do not affect the calculation.
*/
static std::pair CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block)
{
assert(prevHeights->size() == tx.vin.size());
// Will be set to the equivalent height- and time-based nLockTime
// values that would be necessary to satisfy all relative lock-
// time constraints given our view of block chain history.
// The semantics of nLockTime are the last invalid height/time, so
// use -1 to have the effect of any height or time being valid.
int nMinHeight = -1;
int64_t nMinTime = -1;
// tx.nVersion is signed integer so requires cast to unsigned otherwise
// we would be doing a signed comparison and half the range of nVersion
// wouldn't support BIP 68.
bool fEnforceBIP68 = static_cast(tx.nVersion) >= 2
&& flags & LOCKTIME_VERIFY_SEQUENCE;
// Do not enforce sequence numbers as a relative lock time
// unless we have been instructed to
if (!fEnforceBIP68) {
return std::make_pair(nMinHeight, nMinTime);
}
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
// Sequence numbers with the most significant bit set are not
// treated as relative lock-times, nor are they given any
// consensus-enforced meaning at this point.
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
// The height of this input is not relevant for sequence locks
(*prevHeights)[txinIndex] = 0;
continue;
}
int nCoinHeight = (*prevHeights)[txinIndex];
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) {
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast();
// NOTE: Subtract 1 to maintain nLockTime semantics
// BIP 68 relative lock times have the semantics of calculating
// the first block or time at which the transaction would be
// valid. When calculating the effective block time or height
// for the entire transaction, we switch to using the
// semantics of nLockTime which is the last invalid block
// time or height. Thus we subtract 1 from the calculated
// time or height.
// Time-based relative lock-times are measured from the
// smallest allowed timestamp of the block containing the
// txout being spent, which is the median time past of the
// block prior.
nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1);
} else {
nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1);
}
}
return std::make_pair(nMinHeight, nMinTime);
}
static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair lockPair)
{
assert(block.pprev);
int64_t nBlockTime = block.pprev->GetMedianTimePast();
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime)
return false;
return true;
}
bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block)
{
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block));
}
bool CheckSequenceLocks(const CTransaction &tx, int flags)
{
AssertLockHeld(cs_main);
AssertLockHeld(mempool.cs);
CBlockIndex* tip = chainActive.Tip();
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
// height based locks because when SequenceLocks() is called within
// ConnectBlock(), the height of the block *being*
// evaluated is what is used.
// Thus if we want to know if a transaction can be part of the
// *next* block, we need to use one more than chainActive.Height()
index.nHeight = tip->nHeight + 1;
// pcoinsTip contains the UTXO set for chainActive.Tip()
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
std::vector prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
const CTxIn& txin = tx.vin[txinIndex];
CCoins coins;
if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
return error("%s: Missing input", __func__);
}
if (coins.nHeight == MEMPOOL_HEIGHT) {
// Assume all mempool transactions are confirmed in the next block
prevheights[txinIndex] = tip->nHeight + 1;
} else {
prevheights[txinIndex] = coins.nHeight;
}
}
std::pair lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
return EvaluateSequenceLocks(index, lockPair);
}
==Acknowledgments==
Credit goes to Gregory Maxwell for providing a succinct and clear description of the behavior of this change, which became the basis of this BIP text.
This BIP was edited by BtcDrak, Nicolas Dorier and kinoshitajona.
==Deployment==
This BIP is to be deployed by "versionbits" BIP9 using bit 0.
For Bitcoin '''mainnet''', the BIP9 '''starttime''' will be midnight 1st May 2016 UTC (Epoch timestamp 1462060800) and BIP9 '''timeout''' will be midnight 1st May 2017 UTC (Epoch timestamp 1493596800).
For Bitcoin '''testnet''', the BIP9 '''starttime''' will be midnight 1st March 2016 UTC (Epoch timestamp 1456790400) and BIP9 '''timeout''' will be midnight 1st May 2017 UTC (Epoch timestamp 1493596800).
This BIP must be deployed simultaneously with BIP112 and BIP113 using the same deployment mechanism.
==Compatibility==
The only use of sequence numbers by the Bitcoin Core reference client software is to disable checking the nLockTime constraints in a transaction. The semantics of that application are preserved by this BIP.
As can be seen from the specification section, a number of bits are undefined by this BIP to allow for other use cases by setting bit (1 << 31) as the remaining 31 bits have no meaning under this BIP. Additionally, bits (1 << 23) through (1 << 30) inclusive have no meaning at all when bit (1 << 31) is unset.
Additionally, this BIP specifies only 16 bits to actually encode relative lock-time meaning a further 6 are unused (1 << 16 through 1 << 21 inclusive). This allows the possibility to increase granularity by soft-fork, or for increasing the maximum possible relative lock-time in the future.
The most efficient way to calculate sequence number from relative lock-time is with bit masks and shifts:
BIP: 69
Layer: Applications
Title: Lexicographical Indexing of Transaction Inputs and Outputs
Authors: Kristov Atlas
Editor: Daniel Cousens
Status: Complete
Type: Informational
Assigned: 2015-06-12
License: PD
==Abstract==
Currently there is no standard for bitcoin wallet clients when ordering transaction inputs and outputs.
As a result, wallet clients often have a discernible blockchain fingerprint, and can leak private information about their users.
By contrast, a standard for non-deterministic sorting could be difficult to audit.
This document proposes deterministic lexicographical sorting, using hashes of previous transactions and output indices to sort transaction inputs, as well as values and scriptPubKeys to sort transaction outputs.
==Copyright==
This BIP is in the public domain.
==Motivation==
Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs.
Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances.
For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation.
Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers.
Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud.
A researcher recently demonstrated this principle when he detected that Bitstamp leaked information when creating exchange transactions, enabling potential espionage among traders. [1]
One way to address these privacy weaknesses is by randomizing the order of inputs and outputs. [2]
After all, the order of inputs and outputs does not impact the function of the transaction they belong to, making random sorting viable.
Unfortunately, it can be difficult to prove that this sorting process is genuinely randomly sorted based on code or run-time analysis, especially if the software is closed source.
A malicious software developer can abuse the ordering of inputs and outputs as a side channel of leaking information.
For example, if an attacker can patch a victim’s HD wallet client to order inputs and outputs based on the bits of a master private key, then the attacker can eventually steal all of the victim’s funds by monitoring the blockchain.
Non-deterministic methods of sorting are difficult to audit because they are not repeatable.
The lack of standardization between wallet clients when ordering inputs and outputs can yield predictable quirks that characterize particular wallet clients or services.
Such quirks create unique fingerprints that a privacy attacker can employ through simple passive blockchain observation.
The solution is to create an algorithm for sorting transaction inputs and outputs that is deterministic.
Since it is deterministic, it should also be unambiguous — that is, given a particular transaction, the proper order of inputs and outputs should be obvious.
To make this standard as widely applicable as possible, it should rely on information that is downloaded by both full nodes (with or without typical efficiency techniques such as pruning) and SPV nodes.
In order to ensure that it does not leak confidential data, it must rely on information that is publicly accessible through the blockchain.
The use of public blockchain information also allows a transaction to be sorted even when it is a multi-party transaction, such as in the example of a CoinJoin.
==Specification==
===Applicability===
This BIP applies to any transaction for which the order of its inputs and outputs does not impact the transaction’s function.
Currently, this refers to any transaction that employs the SIGHASH_ALL signature hash type, in which signatures commit to the exact order of inputs and outputs.
Transactions that use SIGHASH_ANYONECANPAY and/or SIGHASH_NONE may include inputs and/or outputs that are not signed; however, compliant software should still emit transactions with lexicographically sorted inputs and outputs, even though they may later be modified by others.
In the event that future protocol upgrades introduce new signature hash types, compliant software should apply the lexicographical ordering principle analogously.
While out of scope of this BIP, protocols that do require a specified order of inputs/outputs (e.g. due to use of SIGHASH_SINGLE) should consider the goals of this BIP and how best to adapt them to the specific needs of those protocols.
===Lexicographical Ordering===
Lexicographical ordering is an algorithm for comparison used to sort two sets based on their cartesian order within their common superset.
Lexicographic order is also often known as alphabetical order, or dictionary order.
Common implementations include:
* `std::lexicographical_compare` in C++ [5]
* `cmp` in Python 2.7
* `memcmp` in C [6]
* `Buffer.compare` in Node.js [7]
For more information, see the wikipedia entry on Lexicographical order. [8]
N.B. All comparisons do not need to operate in constant time since they are not processing secret information.
===Transaction Inputs===
Transaction inputs are defined by the hash of a previous transaction, the output index of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3]
For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique.
For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
Previous transaction hashes (in reversed byte-order) are to be sorted in ascending order, lexicographically.
In the event of two matching transaction hashes, the respective previous output indices will be compared by their integer value, in ascending order.
If the previous output indices match, the inputs are considered equal.
Transaction malleability will not negatively impact the correctness of this process.
Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash.
===Transaction Outputs===
A transaction output is defined by its scriptPubKey and amount. [3]
For the sake of efficiency, amounts should be compared first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4]
Transaction output amounts (as 64-bit unsigned integers) are to be sorted in ascending order.
In the event of two matching output amounts, the respective output scriptPubKeys (as a byte-array) will be compared lexicographically, in ascending order.
If the scriptPubKeys match, the outputs are considered equal.
===Examples===
Transaction 0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3:
Inputs:
0: 0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57[0]
1: 26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024[1]
2: 28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2[0]
3: 381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d[1]
4: 3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2[0]
5: 402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a[1]
6: 54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a[1]
7: 643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa[0]
8: 6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1[1]
9: 7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191[0]
10: 7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4[1]
11: a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086[0]
12: b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8[0]
13: bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85[0]
14: de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9[1]
15: f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45[0]
16: f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60[0]
Outputs:
0: 400057456 76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac
1: 40000000000 76a9145be32612930b8323add2212a4ec03c1562084f8488ac
Transaction 28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f
Inputs:
0: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[0]
1: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[1]
Outputs:
0: 100000000 41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac
1: 2400000000 41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac
==Discussion==
* [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/008484.html|[Bitcoin-development] Lexicographical Indexing of Transaction Inputs and Outputs]]
* [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/008487.html|[Bitcoin-development] [RFC] Canonical input and output ordering in transactions]]
==References==
* [[https://bitcoinmagazine.com/20273/bitstamp-exchange-activity-trackable-due-multisig-wallet-implementation/|1: Bitstamp Info Leak]]
* [[https://github.com/OpenBitcoinPrivacyProject/wallet-ratings/blob/5a7e2e1555e91bb48edeca3aa710272777d98c2a/2015-1/criteria.md|2: OBPP Random Indexing as Countermeasure]]
* [[https://github.com/aantonop/bitcoinbook/blob/develop/ch05.asciidoc|3: Mastering Bitcoin]]
* [[https://en.bitcoin.it/wiki/Script|4: Bitcoin Wiki on Script]]
* [[http://www.cplusplus.com/reference/algorithm/lexicographical_compare|5: std::lexicographical_compare]]
* [[http://www.cplusplus.com/reference/cstring/memcmp|6: memcmp]]
* [[https://nodejs.org/api/buffer.html#buffer_class_method_buffer_compare_buf1_buf2|7: Buffer.compare]]
* [[https://en.wikipedia.org/wiki/Lexicographical_order|8: Lexicographical order]]
==Implementations==
* [[https://github.com/spesmilo/electrum/blob/2af670ea2b92e835919b745d94afcb8b4ec32fda/lib/transaction.py#L648|Electrum]]
* [[https://github.com/bitcoinjs/bip69/blob/master/index.js|BitcoinJS]]
* [[https://github.com/bitcoinjs/bip69/blob/master/test/fixtures.json|BitcoinJS Test Fixtures]]
* [[https://www.npmjs.com/package/bip69|NodeJS]]
* [[https://github.com/blockchain/My-Wallet-V3/blob/v3.8.0/src/transaction.js#L120-L142|Blockchain.info public beta]]
* [[https://github.com/btcsuite/btcd/blob/master/btcutil/txsort/txsort.go|Btcsuite]]
==Acknowledgements==
Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP.
A similar proposal was submitted to the Bitcoin-dev mailing list independently by Rusty Russell <rusty@rustcorp.com.au>
================================================
FILE: bip-0070/extensions.mediawiki
================================================
==BIP70 Extensions==
Add your extension below using tags starting at 1000 and submit a pull-req.
{|
| Field Number || Extension Name || Field Name || Description
|-
| 1000 || [[https://example.com|(unassigned)]] || (unassigned) || (unassigned)
|}
================================================
FILE: bip-0070/paymentrequest.proto
================================================
//
// Simple Bitcoin Payment Protocol messages
//
// Use fields 1000+ for extensions;
// to avoid conflicts, register extensions via pull-req at
// https://github.com/bitcoin/bips/blob/master/bip-0070/extensions.mediawiki
//
package payments;
option java_package = "org.bitcoin.protocols.payments";
option java_outer_classname = "Protos";
// Generalized form of "send payment to this/these bitcoin addresses"
message Output {
optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
required bytes script = 2; // usually one of the standard Script forms
}
message PaymentDetails {
optional string network = 1 [default = "main"]; // "main" or "test"
repeated Output outputs = 2; // Where payment should be sent
required uint64 time = 3; // Timestamp; when payment request created
optional uint64 expires = 4; // Timestamp; when this request should be considered invalid
optional string memo = 5; // Human-readable description of request for the customer
optional string payment_url = 6; // URL to send Payment and get PaymentACK
optional bytes merchant_data = 7; // Arbitrary data to include in the Payment message
}
message PaymentRequest {
optional uint32 payment_details_version = 1 [default = 1];
optional string pki_type = 2 [default = "none"]; // none / x509+sha256 / x509+sha1
optional bytes pki_data = 3; // depends on pki_type
required bytes serialized_payment_details = 4; // PaymentDetails
optional bytes signature = 5; // pki-dependent signature
}
message X509Certificates {
repeated bytes certificate = 1; // DER-encoded X.509 certificate chain
}
message Payment {
optional bytes merchant_data = 1; // From PaymentDetails.merchant_data
repeated bytes transactions = 2; // Signed transactions that satisfy PaymentDetails.outputs
repeated Output refund_to = 3; // Where to send refunds, if a refund is necessary
optional string memo = 4; // Human-readable message for the merchant
}
message PaymentACK {
required Payment payment = 1; // Payment message that triggered this ACK
optional string memo = 2; // human-readable message for customer
}
================================================
FILE: bip-0070.mediawiki
================================================
==Abstract==
This BIP describes a protocol for communication between a merchant and their customer, enabling
both a better customer experience and better security against man-in-the-middle attacks on
the payment process.
==Motivation==
The current, minimal Bitcoin payment protocol operates as follows:
# Customer adds items to an online shopping basket, and decides to pay using Bitcoin.
# Merchant generates a unique payment address, associates it with the customer's order, and asks the customer to pay.
# Customer copies the Bitcoin address from the merchant's web page and pastes it into whatever wallet they are using OR follows a bitcoin: link and their wallet is launched with the amount to be paid.
# Customer authorizes payment to the merchant's address and broadcasts the transaction through the Bitcoin p2p network.
# Merchant's server detects payment and after sufficient transaction confirmations considers the transaction final.
This BIP extends the above protocol to support several new features:
# Human-readable, secure payment destinations-- customers will be asked to authorize payment to "example.com" instead of an inscrutable, 34-character bitcoin address.
# Secure proof of payment, which the customer can use in case of a dispute with the merchant.
# Resistance from man-in-the-middle attacks that replace a merchant's bitcoin address with an attacker's address before a transaction is authorized with a hardware wallet.
# Payment received messages, so the customer knows immediately that the merchant has received, and has processed (or is processing) their payment.
# Refund addresses, automatically given to the merchant by the customer's wallet software, so merchants do not have to contact customers before refunding overpayments or orders that cannot be fulfilled for some reason.
==Protocol==
This BIP describes payment protocol messages encoded using Google's Protocol
Buffers, authenticated using X.509 certificates, and communicated over
http/https. Future BIPs might extend this payment protocol to other
encodings, PKI systems, or transport protocols.
The payment protocol consists of three messages; PaymentRequest, Payment,
and PaymentACK, and begins with the customer somehow indicating that
they are ready to pay and the merchant's server responding with a
PaymentRequest message:
==Messages==
The Protocol Buffers messages are defined in [[bip-0070/paymentrequest.proto|paymentrequest.proto]].
===Output===
Outputs are used in PaymentRequest messages to specify where a payment (or
part of a payment) should be sent. They are also used in Payment messages
to specify where a refund should be sent.
{|
| amount || Number of satoshis (0.00000001 BTC) to be paid
|-
| script || a "TxOut" script where payment should be sent. This will normally be one of the standard Bitcoin transaction scripts (e.g. pubkey OP_CHECKSIG). This is optional to enable future extensions to this protocol that derive Outputs from a master public key and the PaymentRequest data itself.
|}
===PaymentDetails/PaymentRequest===
Payment requests are split into two messages to support future extensibility.
The bulk of the information is contained in the PaymentDetails message. It is
wrapped inside a PaymentRequest message, which contains meta-information
about the merchant and a digital signature.
{|
| network || either "main" for payments on the production Bitcoin network, or "test" for payments on test network. If a client receives a PaymentRequest for a network it does not support it must reject the request.
|-
| outputs || one or more outputs where Bitcoins are to be sent. If the sum of outputs.amount is zero, the customer will be asked how much to pay, and the bitcoin client may choose any or all of the Outputs (if there are more than one) for payment. If the sum of outputs.amount is non-zero, then the customer will be asked to pay the sum, and the payment shall be split among the Outputs with non-zero amounts (if there are more than one; Outputs with zero amounts shall be ignored).
|-
| time || Unix timestamp (seconds since 1-Jan-1970 UTC) when the PaymentRequest was created.
|-
| expires || Unix timestamp (UTC) after which the PaymentRequest should be considered invalid.
|-
| memo || UTF-8 encoded, plain-text (no formatting) note that should be displayed to the customer, explaining what this PaymentRequest is for.
|-
| payment_url || Secure (usually https) location where a Payment message (see below) may be sent to obtain a PaymentACK.
|-
| merchant_data || Arbitrary data that may be used by the merchant to identify the PaymentRequest. May be omitted if the merchant does not need to associate Payments with PaymentRequest or if they associate each PaymentRequest with a separate payment address.
|}
The payment_url specified in the PaymentDetails should remain valid at least until the PaymentDetails
expires (or as long as possible if the PaymentDetails does not expire). Note that this is irrespective of
any state change in the underlying payment request; for example cancellation of an order should not
invalidate the payment_url, as it is important that the merchant's server can record mis-payments
in order to refund the payment.
A PaymentRequest is PaymentDetails optionally tied to a merchant's identity:
{|
| payment_details_version || See below for a discussion of versioning/upgrading.
|-
| pki_type || public-key infrastructure (PKI) system being used to identify the merchant. All implementation should support "none", "x509+sha256" and "x509+sha1".
|-
| pki_data || PKI-system data that identifies the merchant and can be used to create a digital signature. In the case of X.509 certificates, pki_data contains one or more X.509 certificates (see Certificates section below).
|-
| serialized_payment_details || A protocol-buffer serialized PaymentDetails message.
|-
| signature || digital signature over a hash of the protocol buffer serialized variation of the PaymentRequest message,
with all serialized fields serialized in numerical order (all current protocol buffer implementations serialize
fields in numerical order) and signed using the private key that corresponds to the public key in pki_data. Optional fields that are not set
are not serialized (however, setting a field to its default value will cause it to be serialized and will affect
the signature). Before serialization, the signature field must be set to an empty value so that the field is included in the signed PaymentRequest hash but contains no data.
|}
When a Bitcoin wallet application receives a PaymentRequest, it must authorize payment by doing the following:
# Validate the merchant's identity and signature using the PKI system, if the pki_type is not "none".
# Validate that customer's system unix time (UTC) is before PaymentDetails.expires. If it is not, then the payment request must be rejected.
# Display the merchant's identity and ask the customer if they would like to submit payment (e.g. display the "Common Name" in the first X.509 certificate).
PaymentRequest messages larger than 50,000 bytes should be rejected by
the wallet application, to mitigate denial-of-service attacks.
===Payment===
Payment messages are sent after the customer has authorized payment:
{|
| merchant_data || copied from PaymentDetails.merchant_data. Merchants may use invoice numbers or any other data they require to match Payments to PaymentRequests. Note that malicious clients may modify the merchant_data, so should be authenticated in some way (for example, signed with a merchant-only key).
|-
| transactions || One or more valid, signed Bitcoin transactions that fully pay the PaymentRequest
|-
| refund_to || One or more outputs where the merchant may return funds, if necessary. The merchant may return funds using these outputs for up to 2 months
after the time of the payment request. After that time has expired, parties must negotiate if returning of funds becomes necessary.
|-
| memo || UTF-8 encoded, plain-text note from the customer to the merchant.
|}
If the customer authorizes payment, then the Bitcoin client:
# Creates and signs one or more transactions that satisfy (pay in full) PaymentDetails.outputs
# Validate that customer's system unix time (UTC) is still before PaymentDetails.expires. If it is not, the payment should be cancelled.
# Broadcast the transactions on the Bitcoin p2p network.
# If PaymentDetails.payment_url is specified, POST a Payment message to that URL. The Payment message is serialized and sent as the body of the POST request.
Errors communicating with the payment_url server should be communicated to the user.
In the scenario where the merchant's server receives multiple identical Payment
messages for an individual PaymentRequest, it must acknowledge each. The second
and further PaymentACK messages sent from the merchant's server may vary by memo
field to indicate current state of the Payment (for example number of confirmations
seen on the network). This is required in order to ensure that in case of a transport
level failure during transmission, recovery is possible by the Bitcoin client
re-sending the Payment message.
PaymentDetails.payment_url should be secure against man-in-the-middle
attacks that might alter Payment.refund_to (if using HTTP, it must be
TLS-protected).
Wallet software sending Payment messages via HTTP must set appropriate
Content-Type and Accept headers, as specified in BIP 71:
When the merchant's server receives the Payment message, it must
determine whether or not the transactions satisfy conditions of
payment. If and only if they do, it should broadcast the
transaction(s) on the Bitcoin p2p network.
Payment messages larger than 50,000 bytes should be rejected by
the merchant's server, to mitigate denial-of-service attacks.
===PaymentACK===
PaymentACK is the final message in the payment protocol; it is sent
from the merchant's server to the bitcoin wallet in response to a
Payment message:
{|
| payment || Copy of the Payment message that triggered this PaymentACK. Clients may ignore this if they implement another way of associating Payments with PaymentACKs.
|-
| memo || UTF-8 encoded note that should be displayed to the customer giving the status of the transaction (e.g. "Payment of 1 BTC for eleven tribbles accepted for processing.")
|}
PaymentACK messages larger than 60,000 bytes should be rejected by
the wallet application, to mitigate denial-of-service attacks. This
is larger than the limits on Payment and PaymentRequest messages
as PaymentACK contains a full Payment message within it.
==Localization==
Merchants that support multiple languages should generate
language-specific PaymentRequests, and either associate the language
with the request or embed a language tag in the request's
merchant_data. They should also generate a language-specific
PaymentACK based on the original request.
For example: A greek-speaking customer browsing the Greek version of a
merchant's website clicks on a "Αγορά τώρα" link, which generates a
PaymentRequest with merchant_data set to "lang=el&basketId=11252". The
customer pays, their bitcoin client sends a Payment message, and the
merchant's website responds with PaymentACK.message "σας ευχαριστούμε".
==Certificates==
The default PKI system is X.509 certificates (the same system used to
authenticate web servers). The format of pki_data when pki_type is
"x509+sha256" or "x509+sha1" is a protocol-buffer-encoded certificate
chain:
If pki_type is "x509+sha256", then the PaymentRequest message is hashed using
the SHA256 algorithm to produce the message digest that is
signed. If pki_type is "x509+sha1", then the SHA1 algorithm is
used.
Each certificate is a DER [ITU.X690.1994] PKIX certificate value. The
certificate containing the public key of the entity that digitally
signed the PaymentRequest must be the first certificate. This MUST be
followed by additional certificates, with each subsequent certificate
being the one used to certify the previous one, up to (but not
including) a trusted root authority. The trusted root authority MAY be
included. The recipient must verify the certificate chain according to
[RFC5280] and reject the PaymentRequest if any validation failure
occurs.
Trusted root certificates may be obtained from the operating system;
if validation is done on a device without an operating system, the
[https://www.mozilla.org/about/governance/policies/security-group/certs/policy/ Mozilla root store] is recommended.
==Extensibility==
The protocol buffers serialization format is designed to be
extensible. In particular, new, optional fields can be added to a
message and will be ignored (but saved/re-transmitted) by old
implementations.
PaymentDetails messages may be extended with new optional fields and
still be considered "version 1." Old implementations will be able to
validate signatures against PaymentRequests containing the new fields,
but (obviously) will not be able to display whatever information is
contained in the new, optional fields to the user.
If it becomes necessary at some point in the future for merchants to
produce PaymentRequest messages that are accepted *only* by new
implementations, they can do so by defining a new PaymentDetails
message with version=2. Old implementations should let the user know
that they need to upgrade their software when they get an up-version
PaymentDetails message.
Implementations that need to extend messages in this specification shall use
tags starting at 1000, and shall update the
[[bip-0070/extensions.mediawiki|extensions page]] via pull-req to avoid
conflicts with other extensions.
==References==
[[bip-0071.mediawiki|BIP 0071]] : Payment Protocol mime types
[[bip-0072.mediawiki|BIP 0072]] : Payment Protocol bitcoin: URI extensions
Public-Key Infrastructure (X.509) working group :
http://datatracker.ietf.org/wg/pkix/charter/
Protocol Buffers : https://developers.google.com/protocol-buffers/
==Reference implementation==
Create Payment Request generator : https://developer.bitcoin.org/examples/payment_processing.html ([[https://github.com/gavinandresen/paymentrequest|source]])
BitcoinJ : https://bitcoinj.github.io/payment-protocol#introduction
==See Also==
Javascript Object Signing and Encryption working group :
http://datatracker.ietf.org/wg/jose/
Wikipedia's page on Invoices: http://en.wikipedia.org/wiki/Invoice
especially the list of Electronic Invoice standards
sipa's payment protocol proposal: https://gist.github.com/sipa/1237788
ThomasV's "Signed Aliases" proposal : http://ecdsa.org/bitcoin_URIs.html
Homomorphic Payment Addresses and the Pay-to-Contract Protocol :
http://arxiv.org/abs/1212.3257
================================================
FILE: bip-0071.mediawiki
================================================
==Abstract==
This BIP defines a MIME (RFC 2046) Media Type for Bitcoin payment
request messages.
==Motivation==
Wallet or server software that sends payment protocol messages over
email or http should follow Internet standards for properly
encapsulating the messages.
==Specification==
The Media Type (Content-Type in HTML/email headers) for bitcoin
protocol messages shall be:
{|
| Message || Type/Subtype
|-
| PaymentRequest || application/bitcoin-paymentrequest
|-
| Payment || application/bitcoin-payment
|-
| PaymentACK || application/bitcoin-paymentack
|}
Payment protocol messages are encoded in binary.
==Example==
A web server generating a PaymentRequest message to initiate the
payment protocol would precede the binary message data with the
following headers:
BIP: 72
Layer: Applications
Title: bitcoin: uri extensions for Payment Protocol
Authors: Gavin Andresen
Status: Deployed
Type: Specification
Assigned: 2013-07-29
==Abstract==
This BIP describes an extension to the bitcoin: URI scheme (BIP 21) to
support the payment protocol (BIP 70).
==Motivation==
Allow users to click on a link in a web page or email to initiate the
payment protocol, while being backwards-compatible with existing
bitcoin wallets.
==Specification==
The bitcoin: URI scheme is extended with an additional, optional
"r" parameter, whose value is a URL from which a PaymentRequest
message should be fetched (characters not allowed within the scope
of a query parameter must be percent-encoded as described in RFC 3986
and bip-0021).
If the "r" parameter is provided and backwards compatibility
is not required, then the bitcoin address portion of the URI may be
omitted (the URI will be of the form: bitcoin:?r=... ).
When Bitcoin wallet software that supports this BIP receives a
bitcoin: URI with a request parameter, it should ignore the bitcoin
address/amount/label/message in the URI and instead fetch a
PaymentRequest message and then follow the payment protocol, as
described in BIP 70.
Bitcoin wallets must support fetching PaymentRequests via http and
https protocols; they may support other protocols. Wallets must
include an "Accept" HTTP header in HTTP(s) requests (as defined
in RFC 2616):
Accept: application/bitcoin-paymentrequest
If a PaymentRequest cannot be obtained (perhaps the server is
unavailable), then the customer should be informed that the merchant's
payment processing system is unavailable. In the case of an HTTP
request, status codes which are neither success nor error (such as
redirect) should be handled as outlined in RFC 2616.
==Compatibility==
Wallet software that does not support this BIP will simply ignore the
r parameter and will initiate a payment to bitcoin address.
==Examples==
A backwards-compatible request:
BIP: 73
Layer: Applications
Title: Use "Accept" header for response type negotiation with Payment Request URLs
Authors: Stephen Pair
Status: Deployed
Type: Specification
Assigned: 2013-08-27
==Abstract==
This BIP describes an enhancement to the payment protocol ([[bip-0070.mediawiki|BIP 70]])
that addresses the need for short URLs when scanning from QR codes. It
generalizes the specification for the behavior of a payment request URL in a
way that allows the client and server to negotiate the content of the
response using the HTTP Accept: header field. Specifically, the client
can indicate to the server whether it prefers to receive a bitcoin URI or
a payment request.
Implementation of this BIP does not require full payment request ([[bip-0070.mediawiki|BIP 70]]) support.
==Motivation==
The payment protocol augments the bitcoin: uri scheme with an additional
"payment" parameter that specifies a URL where a payment request can be
downloaded. This creates long URIs that, when rendered as a QR code, have
a high information density. Dense QR codes can be difficult to scan resulting
in a more frustrating user experience. The goal is to create a standard that
would allow QR scanning wallets to use less dense QR codes. It also makes
general purpose QR code scanners more usable with bitcoin accepting
websites.
==Specification==
QR scanning wallets will consider a non bitcoin URI scanned from a QR code to
be an end point where either a bitcoin URI or a payment request can be obtained.
A wallet client uses the Accept: HTTP header to specify whether it can accept
a payment request, a URI, or both. A media type of text/uri-list specifies that
the client accepts a bitcoin URI. A media type of application/bitcoin-paymentrequest
specifies that the client can process a payment request. In the absence of an
Accept: header, the server is expected to respond with text/html suitable for
rendering in a browser. An HTML response will ensure that QR codes scanned
by non Bitcoin wallet QR scanners are useful (they could render an HTML page
with a payment link that when clicked would open a wallet on the device).
It is not required that the client and server support the full semantics of an
HTTP Accept header. If application/bitcoin-paymentrequest is specified in the
header, the server should send a payment request regardless of anything else
specified in the Accept header. If text/uri-list is specified (but not
application/bitcoin-paymentrequest), a valid Bitcoin URI should be returned. If
neither is specified, the server can return an HTML page. When a uri-list is returned
only the first item in the list is used (and expected to be a bitcoin URI), any additional
URIs should be ignored.
==Compatibility==
Only QR scanning wallets that implement this BIP will be able to process QR
codes containing payment request URLs. There are two possible workarounds for QR
scanning wallets that do not implement this BIP: 1) the server gives the user an
option to change the QR code to a bitcoin: URI or 2) the user scans the code with
a generic QR code scanner.
In the second scenario, if the server responds with a webpage containing a link
to a bitcoin URI, the user can complete the payment by clicking that link provided
the user has a wallet installed on their device and it supports bitcoin URIs. If the
wallet/device does not have support for bitcoin URIs, the user can fall back on
address copy/paste.
This BIP should be fully compatible with BIP 70 assuming it is required that wallets
implementing BIP 70 make use of the Accept: HTTP header when retrieving a
payment request.
==Examples==
The first image below is of a bitcoin URI with an amount and payment request
specified (note, this is a fairly minimal URI as it does not contain a
label and the request URL is of moderate size). The second image is a QR
code with only the payment request url specified.
================================================
FILE: bip-0074.mediawiki
================================================
BIP: 74
Layer: Applications
Title: Allow zero value OP_RETURN in Payment Protocol
Authors: Toby Padilla
Comments-Summary: Unanimously Discourage for implementation
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0074
Status: Closed
Type: Specification
Assigned: 2016-01-29
License: PD
==Abstract==
This BIP alters the Payment Protocol to allow for zero value OP_RETURN outputs in serialized PaymentRequests.
==Motivation==
The Payment Protocol (defined in BIP70) gives merchants a way to build sophisticated transactions by serializing one or more outputs in the form of a PaymentRequest. The PaymentRequest is then served over http/https to a customer's wallet where the serialized transaction can be executed.
While the Payment Protocol allows for any valid script in its outputs, it also ignores outputs with zero value. This means BIP70 implementations can encode an OP_RETURN script but must provide a greater than dust value for that output. The end result is a successful PaymentRequest transaction with an OP_RETURN but the value assigned to that output is lost forever.
This BIP allows for zero value OP_RETURN outputs in serialized PaymentRequests. The change means that OP_RETURN scripts will work as they were originally intended from within PaymentRequests without permanently destroying Bitcoin value. Zero value non-OP_RETURN scripts should continue to be ignored.
In addition to fixing the issue of destroyed value, this change opens up new use cases that were previously impossible.
While storing data on the blockchain is controversial, when used responsibly OP_RETURN provides a powerful mechanism for attaching metadata to a transaction. This BIP effectively decouples the creation of transactions containing OP_RETURN data from the execution of those transactions. The result are positive benefits for both merchants and wallets/customers.
By supporting this BIP, wallets can participate in current and future, unforeseen use cases that benefit from metadata stored in OP_RETURN. Until now OP_RETURN transactions have typically been created and submitted by custom software. If a wallet can process a PaymentRequest with OP_RETURN data as proposed by this BIP, it will support potentially sophisticated Bitcoin applications without the wallet developer having to have prior knowledge of that application.
An example might be a merchant that adds the hash of a plain text invoice to the checkout transaction. The merchant could construct the PaymentRequest with the invoice hash in an OP_RETURN and pass it to the customer's wallet. The wallet could then submit the transaction, including the invoice hash from the PaymentRequest. The wallet will have encoded a proof of purchase to the blockchain without the wallet developer having to coordinate with the merchant software or add features beyond this BIP.
Merchants and Bitcoin application developers benefit from this BIP because they can now construct transactions that include OP_RETURN data in a keyless environment. Again, prior to this BIP, transactions that used OP_RETURN (with zero value) needed to be constructed and executed in the same software. By separating the two concerns, this BIP allows merchant software to create transactions with OP_RETURN metadata on a server without storing public or private Bitcoin keys. This greatly enhances security where OP_RETURN applications currently need access to a private key to sign transactions.
==Specification==
The specification for this BIP is straightforward. BIP70 should be fully implemented with the following changes:
* Outputs where the script is an OP_RETURN and the value is zero should be accepted by the wallet.
BIP70 has special handling for the case with multiple zero value outputs:
If the sum of outputs.amount is zero, the customer will be asked how much to pay, and the bitcoin client may choose any or all of the Outputs (if there are more than one) for payment. If the sum of outputs.amount is non-zero, then the customer will be asked to pay the sum, and the payment shall be split among the Outputs with non-zero amounts (if there are more than one; Outputs with zero amounts shall be ignored).
This behavior should be retained with the exception of OP_RETURN handling. In the case of a multiple output transaction where the sum of the output values is zero, the user should be prompted for a value and that value should be distributed over any or all outputs ''except'' the OP_RETURN output. In the case where the sum of outputs.amount is non-zero then any OP_RETURN outputs should not be ignored but no value should be assigned to them.
Payment requests also must contain at least one payable output (i.e. no payment requests with ''just'' an OP_RETURN).
==Rationale==
As with the discussion around vanilla OP_RETURN, the practice of storing data on the blockchain is controversial. While blockchain and network bloat is an undeniable issue, the benefits that come from attaching metadata to transactions has proven to be too powerful to dismiss entirely. In the absence of OP_RETURN support the Bitcoin ecosystem has seen alternative, less elegant and more wasteful methods employed for Blockchain data storage.
As it exists today, BIP70 allows for OP_RETURN data storage at the expense of permanently destroyed Bitcoin. Even fully removing support for OP_RETURN values in the Payment Protocol would still leave the door open to suboptimal data encoding via burning a larger than dust value to an output with a false address designed to encode data.
This BIP offers all of the same benefits that come from the OP_RETURN compromise. Mainly that OP_RETURN scripts are provably unspendable and thus can be pruned from the UTXO pool. Without supporting this BIP, wallets that support BIP70 will allow for wasteful data storage.
==Compatibility==
Since this BIP still supports OP_RETURN statements with a greater than zero value, it should be fully backwards compatible with any existing implementations.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0075/paymentrequest.proto
================================================
//
// Simple Bitcoin Payment Protocol messages
//
// Use fields 1000+ for extensions;
// to avoid conflicts, register extensions via pull request to update
// https://github.com/bitcoin/bips/blob/master/bip-0070/extensions.mediawiki
//
package payments;
option java_package = "org.bitcoin.protocols.payments";
option java_outer_classname = "Protos";
// Generalized form of "send payment to this/these bitcoin addresses"
message Output {
optional uint64 amount = 1 [default = 0]; // amount is integer-number-of-satoshis
required bytes script = 2; // usually one of the standard Script forms
}
message PaymentDetails {
optional string network = 1 [default = "main"]; // "main" or "test"
repeated Output outputs = 2; // Where payment should be sent
required uint64 time = 3; // Timestamp; when payment request created
optional uint64 expires = 4; // Timestamp; when this request should be considered invalid
optional string memo = 5; // Human-readable description of request for the customer
optional string payment_url = 6; // URL to send Payment and get PaymentACK
optional bytes merchant_data = 7; // Arbitrary data to include in the Payment message
}
message PaymentRequest {
optional uint32 payment_details_version = 1 [default = 1];
optional string pki_type = 2 [default = "none"]; // none / x509+sha256 / x509+sha1
optional bytes pki_data = 3; // depends on pki_type
required bytes serialized_payment_details = 4; // PaymentDetails
optional bytes signature = 5; // pki-dependent signature
}
message X509Certificates {
repeated bytes certificate = 1; // DER-encoded X.509 certificate chain
}
message Payment {
optional bytes merchant_data = 1; // From PaymentDetails.merchant_data
repeated bytes transactions = 2; // Signed transactions that satisfy PaymentDetails.outputs
repeated Output refund_to = 3; // Where to send refunds, if a refund is necessary
optional string memo = 4; // Human-readable message for the merchant
}
message PaymentACK {
required Payment payment = 1; // Payment message that triggered this ACK
optional string memo = 2; // Human-readable message for customer
}
// BIP-IR Extensions
message InvoiceRequest {
required bytes sender_public_key = 1; // Sender's DER-Encoded EC Public Key
optional uint64 amount = 2 [default = 0]; // amount is integer-number-of-satoshis
optional string pki_type = 3 [default = "none"]; // none / x509+sha256
optional bytes pki_data = 4; // Depends on pki_type
optional string memo = 5; // Human-readable description of invoice request for the receiver
optional string notification_url = 6; // URL to notify on EncryptedPaymentRequest ready
optional bytes signature = 7; // PKI-dependent signature
}
enum ProtocolMessageType {
UNKNOWN_MESSAGE_TYPE = 0;
INVOICE_REQUEST = 1;
PAYMENT_REQUEST = 2;
PAYMENT = 3;
PAYMENT_ACK = 4;
}
message ProtocolMessage {
required uint64 version = 1 [default = 1]; // Protocol version number
required uint64 status_code = 2 [default = 1]; // Payment Protocol Status Code (Default: 1 "OK")
required ProtocolMessageType message_type = 3; // Message Type of serialized_message
required bytes serialized_message = 4; // Serialized Payment Protocol Message
optional string status_message = 5; // Human-readable Payment Protocol status message
required bytes identifier = 6; // Unique key to identify this entire exchange on the server. Default value SHOULD be SHA256(Serialized Initial InvoiceRequest + Current Epoch Time in Seconds as a String)
}
message EncryptedProtocolMessage {
required uint64 version = 1 [default = 1]; // Protocol version number
required uint64 status_code = 2 [default = 1]; // Payment Protocol Status Code (Default: 1 "OK")
required ProtocolMessageType message_type = 3; // Message Type of Decrypted encrypted_message
required bytes encrypted_message = 4; // AES-256-GCM Encrypted (as defined in BIP75) Payment Protocol Message
required bytes receiver_public_key = 5; // Receiver's DER-encoded EC Public Key
required bytes sender_public_key = 6; // Sender's DER-encoded EC Public Key
required uint64 nonce = 7; // Microseconds since epoch
required bytes identifier = 8; // Unique key to identify this entire exchange on the server. Default value SHOULD be SHA256(Serialized Initial InvoiceRequest + Current Epoch Time in Seconds as a String)
optional string status_message = 9; // Human-readable Payment Protocol status message
optional bytes signature = 10; // Signature over the full EncryptedProtocolMessage with EC Key Belonging to Sender / Receiver, respectively
}
================================================
FILE: bip-0075.mediawiki
================================================
BIP: 75
Layer: Applications
Title: Out of Band Address Exchange using Payment Protocol Encryption
Authors: Justin Newton
Matt David
Aaron Voisine
James MacWhyte
Comments-Summary: Recommended for implementation (one person)
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0075
Status: Deployed
Type: Specification
Assigned: 2015-11-20
License: CC-BY-4.0
==Abstract==
This BIP is an extension to BIP 70 that provides two enhancements to the existing Payment Protocol.
# It allows the requester (Sender) of a PaymentRequest to voluntarily sign the original request and provide a certificate to allow the payee to know the identity of who they are transacting with.
# It encrypts the PaymentRequest that is returned, before handing it off to the SSL/TLS layer to prevent man in the middle viewing of the Payment Request details.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in RFC 2119.
==Copyright==
This work is licensed under a [[http://creativecommons.org/licenses/by/4.0/|Creative Commons Attribution 4.0 International License]].
==Definitions==
{| class="wikitable"
| Sender || Entity wishing to transfer value that they control
|-
| Receiver || Entity receiving a value transfer
|}
==Motivation==
The motivation for defining this extension to the [[bip-0070.mediawiki|BIP70]] Payment Protocol is to allow two parties to exchange payment information in a permissioned and encrypted way, such that wallet address communication can become a more automated process. This extension also expands the types of PKI (public-key infrastructure) data that is supported, and allows it to be shared by both parties (with [[bip-0070.mediawiki|BIP70]], only the receiver could provide PKI information). This allows for automated creation of off-blockchain transaction logs that are human readable, now including information about the sender and not just the recipient.
The motivation for this extension to [[bip-0070.mediawiki|BIP70]] is threefold:
# Ensure that the payment details can only be seen by the participants in the transaction, and not by any third party.
# Enhance the Payment Protocol to allow for store and forward servers in order to allow, for example, mobile wallets to sign and serve Payment Requests.
# Allow a sender of funds the option of sharing their identity with the receiver. This information could then be used to:
#* Make Bitcoin logs (wallet transaction history) more human readable
#* Give the user the ability to decide whether or not they share their Bitcoin address and other payment details when requested
#* Allow for an open standards based way for businesses to keep verifiable records of their financial transactions, to better meet the needs of accounting practices or other reporting and statutory requirements
#* Automate the active exchange of payment addresses, so static addresses and BIP32 X-Pubs can be avoided to maintain privacy and convenience
In short we wanted to make Bitcoin more human, while at the same time improving transaction privacy.
==Example Use Cases==
1. Address Book
A Bitcoin wallet developer would like to offer the ability to store an "address book" of payees, so users could send multiple payments to known entities without having to request an address every time. Static addresses compromise privacy, and address reuse is considered a security risk. BIP32 X-Pubs allow the generation of unique addresses, but watching an X-Pub chain for each person you wish to receive funds from is too resource-intensive for mobile applications, and there is always a risk of unknowingly sending funds to an X-Pub address after the owner has lost access to the corresponding private key.
With this BIP, Bitcoin wallets could maintain an "address book" that only needs to store each payee's public key. Adding an entry to one's address book could be done by using a Wallet Name, scanning a QR code, sending a URI through a text message or e-mail, or searching a public repository. When the user wishes to make a payment, their wallet would do all the work in the background to communicate with the payee's wallet to receive a unique payment address. If the payee's wallet has been lost, replaced, or destroyed, no communication will be possible, and the sending of funds to a "dead" address is prevented.
2. Individual Permissioned Address Release
A Bitcoin wallet developer would like to allow users to view a potential sending party's identifying information before deciding whether or not to share payment information with them. Currently, [[bip-0070.mediawiki|BIP70]] shares the receiver’s payment address and identity information with anyone who requests it.
With this BIP, Bitcoin wallets could use the sender’s identifying information to make a determination of whether or not to share their own information. This gives the receiving party more control over who receives their payment and identity information. Additionally, this could be used to automatically provide new payment addresses to whitelisted senders, or to protect users’ privacy from unsolicited payment requests.
3. Using Store & Forward Servers
A Bitcoin wallet developer would like to use a public Store & Forward service for an asynchronous address exchange. This is a common case for mobile and offline wallets.
With this BIP, returned payment information is encrypted with an ECDH-computed shared key before sending to a Store & Forward service. In this case, a successful attack against a Store & Forward service would not be able to read or modify wallet address or payment information, only delete encrypted messages.
==Modifying BIP70 pki_type==
This BIP adds additional possible values for the pki_type variable in the PaymentRequest message. The complete list is now as follows:
{| class="wikitable"
! pki_type !! Description
|-
| x509+sha256 || A x.509 certificate, as described in BIP70
|-
| pgp+sha256 || An [[https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP|OpenPGP]] certificate
|-
| ecdsa+sha256 || A [[https://en.bitcoin.it/wiki/Secp256k1|secp256k1]] [[https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm|ECDSA]] public key
|}
'''NOTE''': Although SHA1 was supported in BIP70, it has been deprecated and BIP75 only supports SHA256. The hashing algorithm is still specified in the values listed above for forward and backwards compatibility.
==New Messages==
Updated [/bip-0075/paymentrequest.proto paymentrequest.proto] contains the existing PaymentRequest Protocol Buffer messages as well as the messages newly defined in this BIP.
'''NOTE''': Public keys from both parties must be known to each other in order to facilitate encrypted communication. Although including both public keys in every message may get redundant, it provides the most flexibility as each message is completely self-contained.
===InvoiceRequest===
The '''InvoiceRequest''' message allows a Sender to send information to the Receiver such that the Receiver can create and return a PaymentRequest.
{| class="wikitable"
! Field Name !! Description
|-
| sender_public_key || Sender's SEC-encoded EC public key
|-
| amount || amount is integer-number-of-satoshis (default: 0)
|-
| pki_type || none / x509+sha256 / pgp+sha256 / ecdsa+sha256 (default: "none")
|-
| pki_data || Depends on pki_type
|-
| memo || Human-readable description of invoice request for the receiver
|-
| notification_url || Secure (usually TLS-protected HTTP) location where an [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] SHOULD be sent when ready
|-
| signature || PKI-dependent signature
|}
===ProtocolMessageType Enum===
This enum is used in the newly defined [[#ProtocolMessage|ProtocolMessage]] and [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] messages to define the serialized message type. The '''ProtocolMessageType''' enum is defined in an extensible way to allow for new message type additions to the Payment Protocol.
===ProtocolMessage===
The '''ProtocolMessage''' message is an encapsulating wrapper for any Payment Protocol message. It allows two-way, non-encrypted communication of Payment Protocol messages. The message also includes a status code and a status message that is used for error communication such that the protocol does not rely on transport-layer error handling.
{| class="wikitable"
! Field Name !! Description
|-
|version || Protocol version number (Currently 1)
|-
|status_code || Payment Protocol Status Code
|-
|message_type || Message Type of serialized_message
|-
|serialized_message || Serialized Payment Protocol Message
|-
|status_message || Human-readable Payment Protocol status message
|-
|identifier || Unique key to identify this entire exchange on the server. Default value SHOULD be SHA256(Serialized Initial InvoiceRequest + Current Epoch Time in Seconds as a String)
|}
===Versioning===
This BIP introduces version 1 of this protocol. All messages sent using these base requirements MUST use a value of 1 for the version number. Any future BIPs that modify this protocol (encryption schemes, etc) MUST each increment the version number by 1.
When initiating communication, the version field of the first message SHOULD be set to the highest version number the sender understands. All clients MUST be able to understand all version numbers less than the highest number they support. If a client receives a message with a version number higher than they understand, they MUST send the message back to the sender with a status code of 101 ("version too high") and the version field set to the highest version number the recipient understands. The sender must then resend the original message using the same version number returned by the recipient or abort.
===EncryptedProtocolMessage===
The '''EncryptedProtocolMessage''' message is an encapsulating wrapper for any Payment Protocol message. It allows two-way, authenticated and encrypted communication of Payment Protocol messages in order to keep their contents secret. The message also includes a status code and status message that is used for error communication such that the protocol does not rely on transport-layer error handling.
{| class="wikitable"
! Field Name !! Description
|-
| version || Protocol version number
|-
| status_code || Payment Protocol Status Code
|-
| message_type || Message Type of Decrypted encrypted_message
|-
| encrypted_message || AES-256-GCM Encrypted (as defined in BIP75) Payment Protocol Message
|-
| receiver_public_key || Receiver's SEC-encoded EC Public Key
|-
| sender_public_key || Sender's SEC-encoded EC Public Key
|-
| nonce || Microseconds since epoch
|-
| identifier || Unique key to identify this entire exchange on the server. Default value SHOULD be SHA256(Serialized Initial InvoiceRequest + Current Epoch Time in Seconds as a String)
|-
| status_message || Human-readable Payment Protocol status message
|-
| signature || DER-encoded Signature over the full EncryptedProtocolMessage with EC Key Belonging to Sender / Receiver, respectively
|}
==Payment Protocol Process with InvoiceRequests==
The full process overview for using '''InvoiceRequests''' in the Payment Protocol is defined below.
All Payment Protocol messages MUST be encapsulated in either a [[#ProtocolMessage|ProtocolMessage]] or [[#EncryptedProtocolMessage|EncryptedProtocolMessage]]. Once the process begins using [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] messages, all subsequent communications MUST use [[#EncryptedProtocolMessage|EncryptedProtocolMessages]].
All Payment Protocol messages SHOULD be communicated using [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] encapsulating messages with the exception that an [[#InvoiceRequest|InvoiceRequest]] MAY be communicated using the [[#ProtocolMessage|ProtocolMessage]] if the receiver's public key is unknown.
The process of creating encrypted Payment Protocol messages is enumerated in [[#Sending_Encrypted_Payment_Protocol_Messages_using_EncryptedProtocolMessages|Sending Encrypted Payment Protocol Messages using EncryptedProtocolMessages]], and the process of decrypting encrypted messages can be found under [[#Validating_and_Decrypting_Payment_Protocol_Messages_using_EncryptedProtocolMessages|Validating and Decrypting Payment Protocol Messages using EncryptedProtocolMessages]].
A standard exchange from start to finish would look like the following:
# Sender creates InvoiceRequest
# Sender encapsulates InvoiceRequest in (Encrypted)ProtocolMessage
# Sender sends (Encrypted)ProtocolMessage to Receiver
# Receiver retrieves InvoiceRequest in (Encrypted)ProtocolMessage from Sender
# Receiver creates PaymentRequest
# Receiver encapsulates PaymentRequest in EncryptedProtocolMessage
# Receiver transmits EncryptedProtocolMessage to Sender
# Sender validates PaymentRequest retrieved from the EncryptedProtocolMessage
# The PaymentRequest is processed according to [[bip-0070.mediawiki|BIP70]], including optional Payment and PaymentACK messages encapsulated in EncryptedProtocolMessage messages.
'''NOTE:''' See [[#Initial_Public_Key_Retrieval_for_InvoiceRequest_Encryption|Initial Public Key Retrieval for InvoiceRequest Encryption]] for possible options to retrieve Receiver's public key.
==Message Interaction Details==
===HTTP Content Types for New Message Types===
When communicated via '''HTTP''', the listed messages MUST be transmitted via TLS-protected HTTP using the appropriate Content-Type header as defined here per message:
{| class="wikitable"
! Message Type !! Content Type
|-
| ProtocolMessage || application/bitcoin-paymentprotocol-message
|-
| EncryptedProtocolMessage || application/bitcoin-encrypted-paymentprotocol-message
|}
===Payment Protocol Status Communication===
Every [[#ProtocolMessage|ProtocolMessage]] or [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] MUST include a status code which conveys information about the last message received, if any (for the first message sent, use a status of 1 "OK" even though there was no previous message). In the case of an error that causes the Payment Protocol process to be stopped or requires that message be retried, a ProtocolMessage or EncryptedProtocolMessage SHOULD be returned by the party generating the error. The content of the message MUST contain the same '''serialized_message''' or '''encrypted_message''' and identifier (if present) and MUST have the status_code set appropriately.
The status_message value SHOULD be set with a human readable explanation of the status code.
====Payment Protocol Status Codes====
{| class="wikitable"
! Status Code !! Description
|-
| 1 || OK
|-
| 2 || Cancel
|-
| 100 || General / Unknown Error
|-
| 101 || Version Too High
|-
| 102 || Authentication Failed
|-
| 103 || Encrypted Message Required
|-
| 200 || Amount Too High
|-
| 201 || Amount Too Low
|-
| 202 || Amount Invalid
|-
| 203 || Payment Does Not Meet PaymentRequest Requirements
|-
| 300 || Certificate Required
|-
| 301 || Certificate Expired
|-
| 302 || Certificate Invalid for Transaction
|-
| 303 || Certificate Revoked
|-
| 304 || Certificate Not Well Rooted
|-
|}
+==Canceling A Message==+
If a participant to a transaction would like to inform the other party that a previous message should be canceled, they can send the same message with a status code of 2 ("Cancel") and, where applicable, an updated nonce. How recipients make use of the "Cancel" message is up to developers. For example, wallet developers may want to offer users the ability to cancel payment requests they have sent to other users, and have that change reflected in the recipient's UI. Developers using the non-encrypted ProtocolMessage may want to ignore "Cancel" messages, as it may be difficult to authenticate that the message originated from the same user.
===Transport Layer Communication Errors===
Communication errors MUST be communicated to the party that initiated the communication via the communication layer's existing error messaging facilities. In the case of TLS-protected HTTP, this SHOULD be done through standard HTTP Status Code messaging ([https://tools.ietf.org/html/rfc7231 RFC 7231 Section 6]).
==Extended Payment Protocol Process Details==
This BIP extends the Payment Protocol as defined in [[bip-0070.mediawiki|BIP70]].
For the following we assume the Sender already knows the Receiver's public key, and the exchange is being facilitated by a Store & Forward server which requires valid signatures for authentication.
'''nonce''' MUST be set to a non-repeating number '''and''' MUST be chosen by the encryptor. The current epoch time in microseconds SHOULD be used, unless the creating device doesn't have access to a RTC (in the case of a smart card, for example). The service receiving the message containing the '''nonce''' MAY use whatever method to make sure that the '''nonce''' is never repeated.
===InvoiceRequest Message Creation===
* Create an [[#InvoiceRequest|InvoiceRequest]] message
* '''sender_public_key''' MUST be set to the public key of an EC keypair
* '''amount''' is optional. If the amount is not specified by the [[#InvoiceRequest|InvoiceRequest]], the Receiver MAY specify the amount in the returned PaymentRequest. If an amount is specified by the [[#InvoiceRequest|InvoiceRequest]] and a PaymentRequest cannot be generated for that amount, the [[#InvoiceRequest|InvoiceRequest]] SHOULD return the same [[#InvoiceRequest|InvoiceRequest]] in a [[#ProtocolMessage|ProtocolMessage]] or [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] with the status_code and status_message fields set appropriately.
* '''memo''' is optional. This MAY be set to a human readable description of the InvoiceRequest
* Set '''notification_url''' to URL that the Receiver will submit completed PaymentRequest (encapsulated in an [[#EncryptedProtocolMessage|EncryptedProtocolMessage]]) to
* If NOT including certificate, set '''pki_type''' to "none"
* If including certificate:
** Set '''pki_type''' to "x509+sha256"
** Set '''pki_data''' as it would be set in BIP-0070 ([https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#Certificates Certificates])
** Sign [[#InvoiceRequest|InvoiceRequest]] with signature = "" using the X509 Certificate's private key
** Set '''signature''' value to the computed signature
===InvoiceRequest Validation===
* Validate '''sender_public_key''' is a valid EC public key
* Validate '''notification_url''', if set, contains characters deemed valid for a URL (avoiding XSS related characters, etc).
* If '''pki_type''' is None, [[#InvoiceRequest|InvoiceRequest]] is VALID
* If '''pki_type''' is x509+sha256 and '''signature''' is valid for the serialized [[#InvoiceRequest|InvoiceRequest]] where signature is set to "", [[#InvoiceRequest|InvoiceRequest]] is VALID
===Sending Encrypted Payment Protocol Messages using EncryptedProtocolMessages===
* Encrypt the serialized Payment Protocol message using AES-256-GCM setup as described in [[#ECDH_Point_Generation_and_AES256_GCM_Mode_Setup|ECDH Point Generation and AES-256 (GCM Mode) Setup]]
* Create [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] message
* Set '''encrypted_message''' to be the encrypted value of the Payment Protocol message
* '''version''' SHOULD be set to the highest version number the client understands (currently 1)
* '''sender_public_key''' MUST be set to the public key of the Sender's EC keypair
* '''receiver_public_key''' MUST be set to the public key of the Receiver's EC keypair
* '''nonce''' MUST be set to the nonce used in the AES-256-GCM encryption operation
* Set '''identifier''' to the identifier value received in the originating InvoiceRequest's ProtocolMessage or EncryptedProtocolMessage wrapper message
* Set '''signature''' to ""
* Sign the serialized [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] message with the communicating party's EC public key
* Set '''signature''' to the result of the signature operation above
'''SIGNATURE NOTE:''' [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] messages are signed with the public keys of the party transmitting the message. This allows a Store & Forward server or other transmission system to prevent spam or other abuses. For those who are privacy conscious and don't want the server to track the interactions between two public keys, the Sender can generate a new public key for each interaction to keep their identity anonymous.
===Validating and Decrypting Payment Protocol Messages using EncryptedProtocolMessages===
* The '''nonce''' MUST not be repeated. The service receiving the [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] MAY use whatever method to make sure that the nonce is never repeated.
* Decrypt the serialized Payment Protocol message using AES-256-GCM setup as described in [[#ECDH_Point_Generation_and_AES256_GCM_Mode_Setup|ECDH Point Generation and AES-256 (GCM Mode) Setup]]
* Deserialize the serialized Payment Protocol message
===ECDH Point Generation and AES-256 (GCM Mode) Setup===
'''NOTE''': AES-256-GCM is used because it provides authenticated encryption facilities, thus negating the need for a separate message hash for authentication.
* Generate the '''secret point''' using [https://en.wikipedia.org/wiki/Elliptic_curve_Diffie–Hellman ECDH] using the local entity's private key and the remote entity's public key as inputs
* Initialize [http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf HMAC_DRBG]
** Use '''SHA512(secret point's X value in Big-Endian bytes)''' for Entropy
** Use the given message's '''nonce''' field for Nonce, converted to byte string (Big Endian)
* Initialize AES-256 in GCM Mode
** Initialize HMAC_DRBG with Security Strength of 256 bits
** Use HMAC_DRBG.GENERATE(32) as the Encryption Key (256 bits)
** Use HMAC_DRBG.GENERATE(12) as the Initialization Vector (IV) (96 bits)
====AES-256 GCM Authentication Tag Use====
The 16 byte authentication tag resulting from the AES-GCM encrypt operation MUST be prefixed to the returned ciphertext. The decrypt operation will use the first 16 bytes of the ciphertext as the GCM authentication tag and the remainder of the ciphertext as the ciphertext in the decrypt operation.
====AES-256 GCM Additional Authenticated Data====
When either '''status_code''' OR '''status_message''' are present, the AES-256 GCM authenticated data used in both the encrypt and decrypt operations MUST be: STRING(status_code) || status_message. Otherwise, there is no additional authenticated data. This provides that, while not encrypted, the status_code and status_message are authenticated.
===Initial Public Key Retrieval for InvoiceRequest Encryption===
Initial public key retrieval for [[#InvoiceRequest|InvoiceRequest]] encryption via [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] encapsulation can be done in a number of ways including, but not limited to, the following:
# Wallet Name public key asset type resolution - DNSSEC-validated name resolution returns Base64 encoded DER-formatted EC public key via TXT Record [https://www.ietf.org/rfc/rfc5480.txt RFC 5480]
# Key Server lookup - Key Server lookup (similar to PGP's pgp.mit.edu) based on key server identifier (i.e., e-mail address) returns Base64 encoded DER-formatted EC public key [https://www.ietf.org/rfc/rfc5480.txt RFC 5480]
# QR Code - Use of QR-code to encode SEC-formatted EC public key [https://www.ietf.org/rfc/rfc5480.txt RFC 5480]
# Address Service Public Key Exposure
==Payment / PaymentACK Messages with a HTTP Store & Forward Server==
If a Store & Forward server wishes to protect themselves from spam or abuse, they MAY enact whatever rules they deem fit, such as the following:
* Once an InvoiceRequest or PaymentRequest is received, all subsequent messages using the same identifier must use the same Sender and Receiver public keys.
* For each unique identifier, only one message each of type InvoiceRequest, PaymentRequest, and PaymentACK may be submitted. Payment messages may be submitted/overwritten multiple times. All messages submitted after a PaymentACK is received will be rejected.
* Specific messages are only saved until they have been verifiably received by the intended recipient or a certain amount of time has passed, whichever comes first.
Clients SHOULD keep in mind Receivers can broadcast a transaction without returning an ACK. If a Payment message needs to be updated, it SHOULD include at least one input referenced in the original transaction to prevent the Receiver from broadcasting both transactions and getting paid twice.
==Public Key & Signature Encoding==
* All x.509 certificates included in any message defined in this BIP MUST be DER [ITU.X690.1994] encoded.
* All EC public keys ('''sender_public_key''', '''receiver_public_key''') in any message defined in this BIP MUST be [[SECP256k1|http://www.secg.org/sec2-v2.pdf]] ECDSA Public Key ECPoints encoded using [[SEC 2.3.3 Encoding|http://www.secg.org/sec1-v2.pdf]]. Encoding MAY be compressed.
* All ECC signatures included in any message defined in this BIP MUST use the SHA-256 hashing algorithm and MUST be DER [ITU.X690.1994] encoded.
* All OpenPGP certificates must follow [[https://tools.ietf.org/html/rfc4880|RFC4880]], sections 5.5 and 12.1.
==Implementation==
A reference implementation for a Store & Forward server supporting this proposal can be found here:
[https://github.com/netkicorp/addressimo Addressimo]
A reference client implementation can be found in the InvoiceRequest functional testing for Addressimo here:
[https://github.com/netkicorp/addressimo/blob/master/functest/functest_bip75.py BIP75 Client Reference Implementation]
==BIP70 Extension==
The following flowchart is borrowed from [[bip-0070.mediawiki|BIP70]] and expanded upon in order to visually describe how this BIP is an extension to [[bip-0070.mediawiki|BIP70]].
==Mobile to Mobile Examples==
===Full Payment Protocol===
The following diagram shows a sample flow in which one mobile client is sending value to a second mobile client with the use of an InvoiceRequest, a Store & Forward server, PaymentRequest, Payment and PaymentACK. In this case, the PaymentRequest, Payment and PaymentACK messages are encrypted using [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] '''and''' the Receiver submits the transaction to the Bitcoin network.
===Encrypting Initial InvoiceRequest via EncryptedProtocolMessage===
The following diagram shows a sample flow in which one mobile client is sending value to a second mobile client using an [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] to transmit the InvoiceRequest using encryption, Store & Forward server, and PaymentRequest. In this case, all Payment Protocol messages are encrypting using [[#EncryptedProtocolMessage|EncryptedProtocolMessage]] '''and''' the Sender submits the transaction to the Bitcoin network.
==References==
* [[bip-0070.mediawiki|BIP70 - Payment Protocol]]
* [https://en.wikipedia.org/wiki/Elliptic_curve_Diffie–Hellman ECDH]
* [http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf HMAC_DRBG]
* [http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf NIST Special Publication 800-38D - Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC]
* [https://tools.ietf.org/html/rfc6979 RFC6979]
* [https://en.bitcoin.it/wiki/Address_reuse Address Reuse]
* [http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf FIPS 180-4 (Secure Hash Standard)]
================================================
FILE: bip-0077.md
================================================
```
BIP: 77
Layer: Applications
Title: Async Payjoin
Authors: Dan Gould
Yuval Kogman
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0077
Status: Draft
Type: Specification
Assigned: 2023-08-08
License: BSD-2-Clause
Discussion: https://github.com/bitcoin/bips/pull/1483
https://gnusha.org/pi/bitcoindev/7B11AE34-27A7-46ED-95BF-66CA13BA26F3@ngould.dev/#t
https://gnusha.org/pi/bitcoindev/3C0A6E4C-444E-4E75-829C-1A21D8EE40E0@ngould.dev/#t
Version: 0.2.0
Requires: 21, 78, 173, 174
```
## Copyright
This BIP is licensed under the 2-clause BSD license.
## Abstract
Payjoin lets Bitcoin senders and receivers interact to make batched
transactions.
This document proposes a second, backwards-compatible, asynchronous version of
the Payjoin protocol ("Version 2") relative to and described in [BIP 78](bip-0078.mediawiki) ("Version 1"). An untrusted
third-party "directory server" replaces the requirement
for a receiver to host a secure public endpoint for interactions. HTTP clients
access the directory server using an asynchronous protocol and authenticated,
encrypted payloads. The design preserves complete Payjoin receiver
functionality, including payment
output substitution. Authenticated encryption depends only on cryptographic
primitives available in Bitcoin Core. Requests use [Oblivious
HTTP](https://www.ietf.org/rfc/rfc9458.html) (OHTTP) to
prevent the directory and other Payjoin clients from linking requests to client
IP addresses.
## Motivation
Satoshi Nakamoto pointed out one specific privacy risk in the
[whitepaper](https://bitcoin.org/en/bitcoin-paper),
that transactions with multiple inputs "necessarily reveal that
their inputs were owned by the same owner."
Payjoin addresses that risk, the _common-input-ownership heuristic_,
by making it practical to spend inputs owned by multiple parties
in one transaction.
While addressing Bitcoin's primal privacy risk, Payjoin *input* batching
also improves on the widespread non-interactive *output* batching practice
deployed by exchanges. When combined, the same movement of funds can use
less block weight and save fees.
A natural application of Payjoin would be to combine
getting paid with consolidating UTXOs into one transaction. But Payjoin
can also secure [transaction
cut-through](https://bitcointalk.org/index.php?topic=281848.0),
allowing a sender to transfer funds to a receiver who also transfers
funds to a third party in the same transaction. For example, deposits to an
exchange may "cut through" in a single transaction that also satisfies
withdrawals instead of with a second transaction that spends the deposited
funds. Payjoin enables more blockspace-efficient transactions that
reduce fees while addressing privacy risks.
However, BIP 78's requirements for Payjoin Version 1 have proven to be an
obstacle to adoption. Version 1 receivers must host a secured
public-facing HTTP server. Mobile and web environments limit the ability
to fulfil such a requirement. Version 1 also requires synchronous
communication. Both sender and receiver must be online simultaneously.
Wallet developers [
regard](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html)
these requirements as barriers to Payjoin adoption.
To address these limitations, our goal is to specify a practical
coordination mechanism suitable for widespread implementation. This proposal
leverages mature solutions to common problems, building on established web
standards and proven Bitcoin primitives.
## Overview
A Payjoin *sender* and *receiver* interact so that they may both contribute to a
transaction. In this proposal, they exchange asynchronous end-to-end
encrypted messages by relaying them to a store-and-forward *directory* server
using OHTTP.
Before initiating the protocol, the receiver must secure communications with
the directory by [bootstrapping](#ohttp-bootstrapping).
- The receiver [initiates a Payjoin Session](#session-initiation)
by sharing a [Payjoin URI](#payjoin-uri) that includes the URL of an
ephemeral mailbox hosted on the directory, where it can receive a message
from the sender.
- The sender [posts a message](#sender-original-psbt-messaging)
containing a fully signed fallback transaction, known as the *Original PSBT*,
to the mailbox.
- The receiver gets this message and
[posts a message containing a *Proposal
PSBT*](#receiver-proposal-psbt-messaging)
to the sender's ephemeral mailbox, by updating the Original PSBT with
appropriate inputs and/or outputs.
- The sender gets the Proposal PSBT, [checks it, signs, and
broadcasts](#sender-signing-and-broadcast) the final transaction.
At any point, either party may choose to broadcast the
fallback transaction described by the Original PSBT instead of proceeding.
Because the Original PSBT and Proposal PSBT spend the same input(s) they are
mutually exclusive and only one can be confirmed.
Messages are buffered in the directory, allowing both parties to tolerate
temporary disconnections and resume communication by polling.
### Async Payjoin Directory Mediated Sequence Diagram
```text
+----------+ +------------+ +----------+ +----------+
| Receiver | | Directory | | Sender | | Network |
+----+-----+ +-----+------+ +----+-----+ +----+-----+
| | | |
| Payjoin URI (BIP21), out-of-band | |
+------------------------------------------------>| |
| | | |
| Poll GET: original PSBT (repeat until available) |
+- - - - - - - - - - - ->+ | |
| # POST: original PSBT | |
| #<-----------------------+ |
| 200 OK: original PSBT # | |
|<-----------------------+ | |
| | | |
| | Poll GET: proposal PSBT (repeat until available)
| +<- - - - - - - - - - - -+ |
| POST: proposal PSBT # | |
+-----------------------># | |
| # 200 OK: proposal PSBT | |
| +----------------------->| |
| | | |
| | | Broadcast payjoin |
| | +---------------------->|
| | | |
```
## Specification
### OHTTP Bootstrapping
Before initiating a Payjoin Session a receiver must first discover the
directory's
[OHTTP Key Configuration](https://www.ietf.org/rfc/rfc9458.html#section-3.1),
via an authenticated
bootstrap mechanism. The key configuration contains information to establish
[Hybrid Public Key Encryption](#secp256k1-hybrid-public-key-encryption) (HPKE) in order to secure communications between the client and the directory in
lieu of TLS.
The bootstrap mechanism may vary by implementation but must
follow [OHTTP Consistency
Requirements](https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-key-consistency-01)
and should not reveal a receiver IP address to the directory. Some
examples of suitable mechanisms include getting a key configuration
from a Payjoin URI, a trusted application binary, or fetching using https-in-http
CONNECT method, https-in-WebSocket, Tor, or a VPN.
Directory OHTTP Gateways MUST support [RFC 9540 Key Configuration
Fetching](https://www.rfc-editor.org/rfc/rfc9540.html#name-key-configuration-fetching)
via GET request. RFC 9540 defines the
gateway location as `/.well-known/ohttp-gateway`.
### Session Initiation
A receiver initiates a session by sharing a Payjoin URI. Because a URI
contains sensitive information, such as a receiver address, it should be shared
over a confidential channel.
#### Payjoin URI
Bitcoin URIs ([BIP
21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki)
or [BIP
321](https://github.com/bitcoin/bips/blob/master/bip-0321.mediawiki))
are a standard way to request bitcoin.
A Payjoin URI is a Bitcoin URI that contains a `pj` parameter. The `pj`
parameter value is a URL in both BIP 78 and BIP 77.
Senders that understand Bitcoin URI but don't support Payjoin will just
ignore the `pj` parameter and proceed to typical address-based
transaction flows.
A `req-pj` parameter may be used as a [BIP 21 forwards compatibility `reqparam`](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki#forward-compatibility) instead of
`pj` to signal that Payjoin is required.
The parameter value must be [uppercased and the parameter should be placed last in the URI](#uppercase-url).
Since BIP 78 payloads are neither encrypted nor authenticated,
a directory used for backwards-compatible payloads is known
as an ["unsecured payjoin server" in BIP 78
parlance](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#unsecured-payjoin-server).
Backwards-compatible receivers MUST disable output substitution
by setting `pjos=0` to prevent modification by a malicious directory.
##### Mailbox endpoint
In this proposal the URL in the `pj` parameter value is the mailbox
endpoint URL. Mailboxes are shared HTTP resources hosted by the
directory and serve as OHTTP Target Resources. Clients use these endpoints
to relay encrypted messages. They `POST` messages to and `GET` messages from
mailbox endpoints via OHTTP.
Senders that support BIP 78 but not this proposal may POST messages directly to
mailbox endpoints for [backwards compatibility](#backwards-compatibility).
###### Short ID
A Short ID identifies a mailbox based on its associated public key. The Short
ID is the path component of the mailbox endpoint. One is derived by hashing the
33-byte compressed public key encoding with SHA-256, truncating it to
[8 bytes (64 bits)](#64-bit-short-id-length), and encoding it in
[uppercase](#uppercase-url) using the bech32 character set (like a bech32 string without the HRP, separator and checksum).
##### Receiver fragment parameters
This proposal introduces session-specific parameters which the
receiver shares encoded in the URI.
Instead of defining new Bitcoin URI parameters, the session-specific
parameters are encoded in the [
fragment](https://datatracker.ietf.org/doc/html/rfc3986#section-3.5)
of the mailbox endpoint URL.
The `#` fragment separator character must be [RFC 3986
percent-encoded](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1)
as `%23`, because it separates the
fragment of the mailbox endpoint URL included in the `pj` parameter, not the
fragment of the Bitcoin URI.
These session-specific parameters use a bech32-inspired encoding.
The HRP is used as the parameter key, followed by the '1' separator,
followed by the parameter value encoded using the bech32 character set in
[uppercase](#uppercase-url). No checksum is used. Parameters are separated
by a `-` character.
The following parameters are defined, and must be provided in lexicographical
order:
- `EX`: specifies a [session
expiration](#session-expiration) in [unix
time](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16).
- `OH`: encodes an alternate format of the OHTTP Key Configuration of
the directory. It consists of a 33-byte compressed public key of the
directory's OHTTP Gateway, prefixed by the 2-byte Key Identifier. A [
RFC 9458 Key
Configuration](https://www.ietf.org/rfc/rfc9458.html#section-3.1)
is reconstructed by assuming the HPKE KEM ID and Symmetric Algorithms
are [fixed](#secp256k1-hybrid-public-key-encryption).
- `RK`: encodes the *receiver key* as a 33-byte compressed public key.
Senders will initiate HPKE with the receiver using this key.
For example, a properly encoded endpoint Bitcoin URI looks like this
`bitcoin:tb1q6q6de88mj8qkg0q5lupmpfexwnqjsr4d2gvx2p?amount=0.00666666&pjos=0&pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23EX1WKV8CEC-OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ-RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ6EDSF6AKEWQG758JPS2EV`
Until 2026 implementations SHOULD also accept `+` as a fragment parameter
separator and not enforce parameter ordering requirements, for compatibility
with the [previous version of this document](#changelog).
### Sender Original PSBT Messaging
The sender constructs the fallback transaction, a typical transaction
spending funds to the receiver's address specified in the Payjoin URI.
This transaction is serialized as a BIP 174 PSBTv0, satisfying
[the receiver checklist](#receivers-original-psbt-checklist).
The Original PSBT MUST:
- Include complete UTXO data.
- Be fully signed.
- Exclude unnecessary fields such as global xpubs or keypath
information.
- Be broadcastable.
The Original PSBT MAY:
- Include outputs unrelated to the sender-receiver transfer for batching
purposes.
This *Original PSBT* is encoded as base64, followed by the query
parameter string on a new line containing [optional sender
parameters](#optional-sender-parameters).
The sender generates an ephemeral mailbox key. The corresponding public key is
known as the *reply key*, and it is prepended to the base64 plaintext string,
serialized in compressed form as 33 bytes.
This plaintext string is encrypted to the receiver key according to [HPKE Base
mode](https://www.rfc-editor.org/rfc/rfc9180.html#name-encryption-to-a-public-key).
The HPKE `info` string, used for domain separation, is `PjV2MsgA`. The
ciphertext ensures message secrecy and integrity when passed to the receiver
using the mailbox endpoint. The 16-byte authentication tag is appended to the
ciphertext.
RFC 9180 [does not
specify](https://www.rfc-editor.org/rfc/rfc9180.html#section-10) the wire format
encoding of HPKE messages. To construct an HPKE payload, the secp256k1 public
key from the DHKEM is encoded using ElligatorSwift in 64 bytes. Note that
ElligatorSwift is only the wire format; when deriving shared secrets, the curve
point is re-serialized in uncompressed form.
```
PjV2MsgA Byte Representation (7168 bytes total)
+---------------------------------------------------------------------------------------+
| ElligatorSwift | Ciphertext |
| (64 bytes) | (7104 bytes) |
| +-----------------------+---------------------------------+------------+
| | Reply Key | Padded Plaintext | AEAD Tag |
| | (33 bytes) | (7055 bytes = 7168-64-33-16) | (16 bytes) |
+---------------------------------------------------------------------------------------+
```
The resulting HPKE payload is the body of a POST request to the
receiver's mailbox. This request is then [
encapsulated](#clientdirectory-interactions) according to
Oblivious HTTP to the directory's OHTTP Gateway. OHTTP serializes the
inner request as BHTTP, and provides another layer of HPKE encryption,
between the client and directory.
Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP
request and handles the inner POST request at the receiver's mailbox
endpoint, which stores the HPKE encrypted payload to be forwarded to the
receiver.
The sender then polls OHTTP encapsulated GET requests to the sender's
mailbox endpoint until it receives a response from the directory
containing the receiver's *Proposal PSBT*, and proceeds to
[sign and broadcast](#sender-signing-and-broadcast).
It stops polling after expiration.
#### Optional sender parameters
[BIP 78's optional sender parameters](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#optional-parameters)
may be used in this proposal, but must be included in
the body as part of the ciphertext rather than as a query string.
HPKE binds ciphertexts to application-specific `info` strings. Because
of this domain separation, BIP 78's `v` parameter is redundant and
should be omitted for this proposal.
### Receiver Proposal PSBT Messaging
After sharing the Payjoin URI with the sender, the receiver polls via
OHTTP encapsulated GET requests to the receiver's mailbox endpoint. So
long as the mailbox contains no message, the directory responds with
status 202 ACCEPTED. Once a mailbox contains a message, the directory
returns it in the response body with status 200 OK.
Upon receiving an encapsulated 200 OK response, the receiver decrypts
the payload and checks the *Original PSBT* therein according to the
[receiver checklist](#receivers-original-psbt-checklist).
The receiver then updates the *Original PSBT* to include new signed
inputs and outputs, invalidating the sender's signature(s). The receiver
may also adjust the transaction fee. The result, called the *Proposal
PSBT*, must satisfy the [sender checklist](#senders-proposal-psbt-checklist)
The Proposal PSBT MUST:
- Include complete UTXO data.
- Include all inputs from the Original PSBT.
- Include all outputs which do not belong to the receiver from the
Original PSBT.
- Use a random index if additional inputs or outputs are added.
The Proposal PSBT sender MAY:
- Add inputs at random indices.
- Add outputs at random indices.
- Remove or modify Original PSBT outputs under the control of the
receiver (i.e. not sender change).
The Proposal PSBT MUST NOT:
- Shuffle the order of inputs or outputs contained in the Original PSBT.
- Decrease the absolute fee of the Original PSBT.
The receiver encrypts the *Proposal PSBT* to the sender's reply key according to
[HPKE Auth
mode](https://www.rfc-editor.org/rfc/rfc9180.html#name-authentication-using-an-asy),
using the receiver's key for authentication. The HPKE `info` string is
`PjV2MsgB`. The HPKE wire format is the same as in the [sender's
message](#sender-original-psbt-messaging).
```
PjV2MsgB Byte Representation (7168 bytes total)
+---------------------------------------------------------------------------------------+
| ElligatorSwift | Ciphertext |
| (64 bytes) | (7104 bytes) |
| +---------------------------------------------------------+------------+
| | Padded Plaintext | AEAD Tag |
| | (7088 bytes = 7168-64-16) | (16 bytes) |
+---------------------------------------------------------------------------------------+
```
The receiver makes the resulting HPKE payload the body of a POST request to the
sender's mailbox whose Short ID is derived from the sender's reply key. This request is then [
encapsulated](#clientdirectory-interactions) according to
Oblivious HTTP to the directory's OHTTP Gateway. OHTTP serializes the
inner request as BHTTP, and provides another layer of HPKE encryption,
between the client and directory.
Once the receiver makes this request, they wait for either transaction from the
Original PSBT or Proposal PSBT to be broadcast to the Bitcoin network.
#### Receiver's Original PSBT checklist
The receiver checklist is the same as [the BIP 78 receiver
checklist](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-checklist).
### Sender signing and broadcast
The sender validates the *Proposal PSBT* it receives against a
checklist. If the checks pass, it may sign and broadcast the resulting
Payjoin transaction.
#### Sender's Proposal PSBT checklist
This proposal's sender checklist is the same as [the BIP 78 sender
checklist](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#senders-payjoin-proposal-checklist).
### Client/Directory interactions
The Payjoin Directory provides a rendezvous point for senders and
receivers to exchange messages. The directory stores Payjoin payloads to
support asynchronous communication. Async Payjoin requests must be
submitted as encapsulated messages to the directory's OHTTP Gateway.
The wire format OHTTP request is specified in [RFC
9458](https://www.ietf.org/rfc/rfc9458.html#name-hpke-encapsulation). HPKE
requires the directory's OHTTP key configuration. The plaintext is a binary
encoded HTTP request ([RFC 9292](https://www.rfc-editor.org/rfc/rfc9292.html))
intended for the OHTTP target resource, usually a mailbox endpoint, padded to
8104 bytes with [random data](#random-padding).
```
OHTTP Encapsulated Request Byte Representation (8192 bytes total)
+--------------+-------------------------+------------------------------------------+
| OHTTP Header | HPKE KEM | Ciphertext |
| (7 bytes) | Uncompressed Public Key | (8120 bytes = 8192-65-7) +
| | (65 bytes) +-----------------------------+------------+
| | | Padded BHTTP Request | AEAD Tag |
| | | (8104 bytes = 8192-65-16-7) | (16 bytes) |
+--------------+-------------------------+------------------------------------------+
```
Response encryption uses the Export functionality of the request HPKE context to
establish a shared secret, and therefore consists of a 32 byte nonce followed by
the AEAD ciphertext and tag.
```
OHTTP Encapsulated Response Byte Representation (8192 bytes total)
+---------------------+------------------------------------------+
| Nonce | Ciphertext |
| (32 bytes) | (8160 bytes = 8192-32) +
| +-----------------------------+------------+
| | Padded BHTTP Response | AEAD Tag |
| | (8144 bytes = 8192-32-16) | (16 bytes) |
+---------------------+------------------------------------------+
```
GET requests on an empty mailbox should block until a message is posted
or a timeout occurs. The timeout should be 30 seconds because that will
not exceed the default timeout for most HTTP clients.
The directory may optionally accept HTTP/1.1 POST requests without OHTTP
to mailbox endpoint URLs for backwards compatibility with BIP 78 senders.
#### OHTTP Sequence Diagram
```text
.-------------------------------------------.
| Payjoin Directory |
+--------+ +-----------+ | +-------------+ +--------------+ |
| Client | | OHTTP | | | OHTTP | | HTTP | |
| | | Relay | | | Gateway | | Resource | |
+---+----+ +------+----+ | +-----+-------+ +------+-------+ |
| | `--------|-----------------------|----------'
| Relay Request | | |
| [ + Encapsulated | | |
| Request ] | | |
+------------------->| Gateway Request | |
| | [ + Encapsulated | |
| | Request ] | |
| +------------------->| Request |
| | +---------------------->|
| | | |
| | | Response |
| | Gateway |<----------------------+
| | Response | |
| | [ + Encapsulated | |
| | Response ] | |
| Relay |<-------------------+ |
| Response | | |
| [ + Encapsulated | | |
| Response ] | | |
|<-------------------+ | |
| | | |
```
### Relay/Directory interactions
RFC 9458 requires each OHTTP Relay to be configured to forward requests
to exactly one OHTTP Gateway. This requirement prevents receivers from
being able to choose any directory, and senders from choosing relays
independently. Without addressing this limitation, senders would have to
know which relays are appropriate to use for each directory, creating a
tendency for one directory and its affiliated relays to monopolize the
protocol.
In order to allow OHTTP Relays to be used with any directory, a
directory's OHTTP Gateway may advertise this allowed purpose. This
advertisement prevents OHTTP Relays from acting as open internet proxies,
which would otherwise allow anonymized access to arbitrary resources and
expose them to denial-of-service attacks, as well as other forms of abuse.
When the directory receives a GET request to the `/.well-known/ohttp-gateway`
path with an `allowed_purposes` query parameter, its response body
should contain a magic string in the same format as a TLS ALPN protocol
list (a U16BE length encoded list of U8 length encoded strings). The
magic string is `BIP77 454403bb-9f7b-4385-b31f-acd2dae20b7e`, offering
an unambiguous signal to relays that this OHTTP Gateway will accept
requests associated with this purpose from any relay.
By supporting this `allowed_purposes` parameter, the directory signals
to OHTTP Relays that it is willing to handle requests related to BIP 77,
removing the RFC 9458's requirement that relays and
Gateways be configured in a one-to-one relationship.
## Rationale
### Uppercase URL
In order to simplify parsing and allow QR encoders to use [Alphanumeric
QR
mode](https://www.rfc-editor.org/rfc/rfc9285.html#name-the-alphabet-used-in-base45),
which is more compact than Byte mode, the mailbox endpoint URL,
including the fragment parameters, is encoded in uppercase.
Unlike Bitcoin URI parameters, which require switching back to Byte
mode, the use of the URL fragment for session-specific parameters makes
it possible to stay in Alphanumeric mode.
### Parameter Ordering
The order of fragment parameters, Bitcoin URI parameters, as well as in the
sender's optional parameters have no defined meaning.
In the BIP 21 URI, the `pj` parameter mailbox endpoint URL SHOULD be the last
parameter to avoid QR mode switching.
Since variations might create a fingerprint for particular wallet software,
this document requires that fragment parameters MUST appear in reverse
lexicographical order.
### Session Expiration
The directory may hold a message for an offline Payjoin client until that
client comes online. However, the BIP 78 spec [
recommends](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receiver-does-not-need-to-be-a-full-node)
broadcasting Original PSBTs in the case of an offline counterparty.
Doing so exposes a naïve, surveillance-vulnerable transaction, which
Payjoin intends to avoid.
Because BIP 78 is a synchronous protocol without a standard expiration
mechanism, and automated receivers are vulnerable to probing attacks,
BIP 78 encourages receivers to broadcast the Original PSBT after some
undefined expiration time.
Because BIP 77 is an asynchronous protocol, it requires an explicit [
session-specific fragment
parameter](#receiver-fragment-parameters), `EX`, to
communicate this expiration time to the sender.
There is no way for a sender to prevent a receiver from broadcasting the
fallback transaction extracted from the Original PSBT before the
receiver-specified expiration time.
### 64-bit Short ID Length
64 bits are sufficient to make the probability of experiencing a random
collision negligible. As of writing, the UTXO set has ~2^28 elements.
This is a very loose upper bound for the number of concurrent (non-spam)
sessions, for which the probability of a random collision will be less
than 1%. The actual number of sessions will of course be (orders of
magnitudes) lower given that sessions are short-lived. With ~2^21
sessions (a loose bound on number of transactions that can be confirmed
in 24 hours) the probability is less than 1e-6. These figures bound the
probability of a collision existing anywhere in the entire set, whereas
the probability for an individual session to experience a collision is
\<\< 1e-10 in either case.
### Complete UTXO Data
Complete UTXO data is required because this information is required for
signing and calculating fees for some input types.
### HTTP
HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core
to consider an implementation. Unlike a WebSockets protocol, plain HTTP
can benefit from metadata protection by using Oblivious HTTP.
### Oblivious HTTP
OHTTP protects sender and receiver IP addresses both from one another
and from the directory. This makes it more difficult for a directory to
correlate many Payjoin transactions with specific IP addresses.
OHTTP relays can be run as basic HTTP proxies from wallet providers or
third parties.
### Uniform Payloads
Encapsulated OHTTP payloads seen by the relay and directory, and
encrypted messages seen by the directory, are constructed to be uniform
so that these third-party services are unable to distinguish between
them.
Encapsulated OHTTP messages are 8192 bytes long, and begin with a
cleartext OHTTP header and an uncompressed key which is distinguishable
from random bytes but uniform across different encapsulated requests.
End-to-end encrypted messages are 7168 bytes long, and should be
indistinguishable from uniformly random bytes.
[ElligatorSwift as defined in BIP 324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#elligatorswift-encoding-of-curve-x-coordinates)
is used to encode encapsulated HPKE public keys prepended to the HPKE ciphertext
so that the directory can't distinguish between key material, the
ciphertext, and randomness. This ensures the two different protocol
messages are indistinguishable from each other as well as any protocol
extensions.
These padded sizes are sufficient for most PSBTs without exceeding the [
8KB
limit](https://www.geekersdigest.com/max-http-request-header-size-server-comparison/)
of many HTTP/1.1 web servers. 8KB is also too small for image sharing,
making misuse of the directory impractical.
#### Random Padding
The typical [zero padding recommended by the BHTTP
specification](https://www.rfc-editor.org/rfc/rfc9292.html#name-padding-and-truncation)
would make future use of [multi-hop OHTTP inspired by the Sphinx mix
format](https://github.com/orgs/payjoin/discussions/582) detectable from the
point of view of the directory. Random padding is allowed so long as the BHTTP
encoded request is not truncated.
By randomly padding OHTTP messages, any future use of such techniques would be
indistinguishable from clients that only implement standardized OHTTP. Since
this would limit a malicious directory's ability to censor any such requests in
the future, and such requests significantly bolster the privacy threat model
against malicious OHTTP relays or traffic analysis by a global passive
adversary, it is desirable to do so for standard OHTTP requests as well.
### Secp256k1 Hybrid Public Key Encryption
[RFC 9180 Hybrid Public Key
Encryption](https://www.rfc-editor.org/rfc/rfc9180.html)
(HPKE) is a modern IETF standard for secure
message exchange without TLS, since TLS is not available in Bitcoin Core.
This proposal uses `DHKEM(Secp256k1, HKDF-SHA256)` and
`ChaCha20Poly1305` AEAD for both OHTTP encapsulation and for end-to-end
encryption between the sender and receiver.
The receiver transmits its receiver key in [receiver fragment
parameters](#receiver-fragment-parameters). The sender shares
its reply key along with the Original PSBT. These keys are ephemeral and
must only be used for a single Payjoin Session.
#### Secp256k1-based DHKEM
[Secp256k1-based DHKEM for
HPKE](https://www.ietf.org/archive/id/draft-wahby-cfrg-hpke-kem-secp256k1-01.html)
is most appropriate because of secp256k1's availability in bitcoin
contexts.
#### ChaCha20Poly1305 AEAD
This authenticated encryption with additional data [
algorithm](https://en.wikipedia.org/wiki/ChaCha20-Poly1305)
is standardized in [RFC
8439](https://www.rfc-editor.org/rfc/rfc8439) and has high
performance. ChaCha20Poly1305 AEAD has been implemented [in Bitcoin
Core](https://github.com/bitcoin/bitcoin/pull/15649) for [
BIP 324 Encrypted
Transport](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki)
as well. This has widespread support in browsers and common
cryptographic libraries. AES-GCM is more widespread but slower without
hardware support and not typically already a dependency in bitcoin software.
#### HKDF-SHA256
SHA-256 is necessarily available in bitcoin contexts.
## Attack vectors
In addition to the attack vectors and mitigations in
[BIP 78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#attack-vectors),
this proposal has the following attack vectors.
### Directory Denial of Service
Since each mailbox stores arbitrary encrypted payloads, directories are
vulnerable to flooding. To mitigate such denial of service attacks,
directory operators may respond with `401` unauthorized unless an
authorization token is provided. Authorization tokens must be unlinkable
to preserve client privacy. A specific unlinkable authorization token
mechanism is out of the scope of this proposal.
### Network privacy
Oblivious HTTP must be used to protect the IP addresses of both sender
and receiver from the directory. This requires an OHTTP Key
Configuration to be shared in the Payjoin URI and for the directory to
support Oblivious HTTP.
Unlike BIP 78 implementations, sender and receiver clients will only see
the IP address of the directory and not that of the client they are
interacting with.
Senders that submit requests directly to the directory, without using
an OHTTP Relay, may reveal their IP address to the receiver since that
receiver also specifies the directory.
## Backwards compatibility
Senders not supporting Payjoin will just ignore the `pj` parameter and
proceed to typical address-based transaction flows.
All Payjoin versions use [Bitcoin URIs](#payjoin-uri).
Receivers may choose to accept BIP 78 payloads at their discretion.
A BIP 78 sender posts their request to the directory, which stores
and forwards it to the BIP 77 receiver. A backwards-compatible
receiver proceeds with the BIP 78 checks if the encapsulated response
body is UTF-8 plaintext, signifying BIP 78. In order to service the
request, a BIP 78 response must be returned to the sender within 30
seconds or else the directory should respond with an `unavailable` JSON
error code as [defined in BIP
78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors).
## Reference implementation
A production reference implementation client can be found at
. Source code for the clients, the
directory, and development kit may be found here:
. Source code for an Oblivious
HTTP relay implementation may be found here:
.
## Changelog
- 0.2.0 2025-07-08
- Change fragment parameter delimiter from `+` to `-` to improve
compatibility with generic URI parsing libraries, and order them
lexicographically. `+` can cause issues due to a common convention (not
specified in RFC 3986, but in RFC 1866, in relation to HTML form
submission and query parameters) of interpreting `+` as ` ` when decoding
URIs.
- 0.1.0 2025-05-28
- First merged Draft version of BIP 77
================================================
FILE: bip-0078.mediawiki
================================================
==Introduction==
===Abstract===
This document proposes a protocol for two parties
to negotiate a coinjoin transaction during a payment between them.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
When two parties (later referred to as sender and receiver) want to transact,
most of the time, the sender creates a transaction spending their own Unspent Transaction Outputs (UTXOs), signs
it and broadcasts it on the network.
This simple model gave birth to several heuristics impacting the privacy of the parties and of the network as a whole.
* Common input ownership heuristic: In most transactions, all the inputs belong to the same party.
* Change identification from scriptPubKey type: If all inputs are spending UTXOs of a certain scriptPubKey type, then the change output is likely to have the same scriptPubKey type, too.
* Change identification from round amount: If an output in the transaction has a round amount, it is likely an output belonging to the receiver.
We will designate these three heuristics as common-input, change-scriptpubkey, change-round-amount.
The problems we aim to solve are:
* For the receiver, there is a missed opportunity to consolidate their own UTXOs or making payment in the sender's transaction.
* For the sender, there are privacy leaks regarding their wallet that happen when someone applies the heuristics detailed above to their transaction.
Our proposal gives an opportunity for the receiver to consolidate their UTXOs while also batching their own payments, without creating a new transaction. (Saving fees in the process)
For the sender, it allows them to invalidate the three heuristics above. With the receiver's involvement, the heuristics can even be poisoned. (ie, using the heuristics to intentionally mislead blockchain analysis)
Note that the existence of this proposal is also improving the privacy of parties who are not using it by making the three heuristics unreliable to the network as a whole.
=== Relation to BIP79 (Bustapay) ===
Another implementation proposal has been written: [[https://github.com/bitcoin/bips/blob/master/bip-0079.mediawiki|BIP79 Bustapay]].
We decided to deviate from it for several reasons:
* It was not using PSBT, so if the receiver wanted to bump the fee, they would need the full UTXO set.
* Inability to change the payment output to match scriptPubKey type.
* Lack of basic versioning negotiation if the protocol evolves.
* No standardization of error condition for proper feedback to the sender.
Other than that, our proposal is very similar.
==Specification==
===Protocol===
In a payjoin payment, the following steps happen:
* The receiver of the payment, presents a [[bip-0021.mediawiki|BIP 21 URI]] to the sender with a parameter pj= describing a payjoin endpoint.
* The sender creates a signed, finalized PSBT with witness UTXO or previous transactions of the inputs. We call this PSBT the original.
* The receiver replies back with a signed PSBT containing his own signed inputs/outputs and those of the sender. We call this PSBT Payjoin proposal.
* The sender verifies the proposal, re-signs his inputs and broadcasts the transaction to the Bitcoin network. We call this transaction Payjoin transaction.
The original PSBT is sent in the HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly.
The payjoin proposal PSBT is sent in the HTTP response body, base64 serialized with HTTP code 200.
To ensure compatibility with web-wallets and browser-based-tools, all responses (including errors) must contain the HTTP header Access-Control-Allow-Origin: *.
The sender must ensure that the URL refers to a scheme or protocol using authenticated encryption, for example TLS with certificate validation, or a .onion link to a hidden service whose public key identifier has already been communicated via a TLS connection. Senders SHOULD NOT accept a URL representing an unencrypted or unauthenticated connection.
The original PSBT MUST:
* Have all the witnessUTXO or nonWitnessUTXO information filled in.
* Be finalized.
* Not include fields unneeded for the receiver such as global xpubs or keypath information.
* Be broadcastable.
The original PSBT MAY:
* Have outputs unrelated to the payment for batching purpose.
The original PSBT SHOULD NOT:
* Include mixed input types until September 2024. Mixed inputs were previously completely disallowed so this gives some grace period for receivers to update.
The payjoin proposal MUST:
* Use all the inputs from the original PSBT.
* Use all the outputs which do not belong to the receiver from the original PSBT.
* Only finalize the inputs added by the receiver. (Referred later as additional inputs)
* Only fill the witnessUTXO or nonWitnessUTXO for the additional inputs.
The payjoin proposal MAY:
* Add, or replace the outputs belonging to the receiver unless output substitution is disabled.
The payjoin proposal SHOULD NOT:
* Include mixed input types until September 2024. Mixed inputs were previously completely disallowed so this gives some grace period for senders to update.
The payjoin proposal MUST NOT:
* Shuffle the order of inputs or outputs, the additional outputs or additional inputs must be inserted at a random index.
* Decrease the absolute fee of the original transaction.
===BIP21 payjoin parameters===
This proposal is defining the following new [[bip-0021.mediawiki|BIP 21 URI]] parameters:
* pj=: Represents an http(s) endpoint which the sender can POST the original PSBT.
* pjos=0: Signal to the sender that they MUST disallow [[#output-substitution|payment output substitution]]. (See [[#unsecured-payjoin|Unsecured payjoin server]])
Note: the amount parameter is *not* required.
===Optional parameters===
When the payjoin sender posts the original PSBT to the receiver, he can optionally specify the following HTTP query string parameters:
* v=, the version number of the payjoin protocol that the sender is using. The current version is 1.
This can be used in the future so the receiver can reject a payjoin if the sender is using a version which is not supported via an error HTTP 400, version-unsupported.
If not specified, the receiver will assume the sender is v=1.
If the receiver does not support the version of the sender, they should send an error with the list of supported versions:
{
"errorCode": "version-unsupported",
"supported" : [ 2, 3, 4 ],
"message": "The version is not supported anymore"
}
* additionalfeeoutputindex=, if the sender is willing to pay for increased fee, this indicate output can have its value subtracted to pay for it.
If the additionalfeeoutputindex is out of bounds or pointing to the payment output meant for the receiver, the receiver should ignore the parameter. See [[#fee-output|fee output]] for more information.
* maxadditionalfeecontribution=, if the sender is willing to pay for increased fee, an integer defining the maximum amount in satoshis that the sender is willing to contribute towards fees for the additional inputs. maxadditionalfeecontribution must be ignored if set to less than zero. See [[#fee-output|fee output]] for more information.
Note that both maxadditionalfeecontribution= and additionalfeeoutputindex= must be specified and valid for the receiver to be allowed to decrease an output belonging to the sender.
This fee contribution can't be used to pay for anything else than additional input's weight.
* minfeerate=, a decimal in satoshi per vbyte that the sender can use to constraint the receiver to not drop the minimum fee rate too much.
* disableoutputsubstitution=, a boolean indicating if the sender forbids the receiver to substitute the receiver's output, see [[#output-substitution|payment output substitution]]. (default to false)
===Receiver's well known errors===
If for some reason the receiver is unable to create a payjoin proposal, it will reply with a HTTP code different than 200.
The receiver is not constrained to specific set of errors, some are specified in this proposal.
The errors have the following format:
{
"errorCode": "leaking-data",
"message": "Key path information or GlobalXPubs should not be included in the original PSBT."
}
The well-known error codes are:
{| class="wikitable"
!Error code
!Meaning
|-
|unavailable
|The payjoin endpoint is not available for now.
|-
|not-enough-money
|The receiver added some inputs but could not bump the fee of the payjoin proposal.
|-
|version-unsupported
|This version of payjoin is not supported.
|-
|original-psbt-rejected
|The receiver rejected the original PSBT.
|}
The receiver is allowed to return implementation-specific errors which may assist the sender to diagnose any issue.
However, it is important that error codes that are not well-known and that the message do not appear on the sender's software user interface.
Such error codes or messages could be used maliciously to phish a non-technical user.
Instead those errors or messages can only appear in debug logs.
It is advised to hard code the description of the well known error codes into the sender's software.
===Fee output===
In some situation, the sender might want to pay some additional fee in the payjoin proposal.
If such is the case, the sender must use both [[#optional-params|optional parameters]] additionalfeeoutputindex= and maxadditionalfeecontribution= to indicate which output and how much the receiver can subtract fee.
There are several cases where a fee output is useful:
* The sender's original transaction's fee rate is at the minimum accepted by the network, aka minimum relay transaction fee rate, which is typically 1 satoshi per vbyte.
In such case, the receiver will need to increase the fee of the transaction after adding his own inputs to not drop below the minimum relay transaction fee rate.
* The sender's wallet software is using round fee rate.
If the sender's fee rate is always round, then a blockchain analyst can easily spot the transactions of the sender involving payjoin by checking if, when removing a single input to the suspected payjoin transaction, the resulting fee rate is round.
To prevent this, the sender can agree to pay more fee so the receiver make sure that the payjoin transaction fee is also round.
* The sender's transaction is time sensitive.
When a sender picks a specific fee rate, the sender expects the transaction to be confirmed after a specific amount of time. But if the receiver adds an input without bumping the fee of the transaction, the payjoin transaction fee rate will be lower, and thus, longer to confirm.
Our recommendation for maxadditionalfeecontribution= is originalPSBTFeeRate * 110.
===Receiver's original PSBT checklist===
The receiver needs to do some check on the original PSBT before proceeding:
* Non-interactive receivers (like a payment processor) need to check that the original PSBT is broadcastable. *
* If the sender included inputs in the original PSBT owned by the receiver, the receiver must either return error original-psbt-rejected or make sure they do not sign those inputs in the payjoin proposal.
* Make sure that the inputs included in the original transaction have never been seen before.
** This prevents [[#probing-attack|probing attacks]].
** This prevents reentrant payjoin, where a sender attempts to use payjoin transaction as a new original transaction for a new payjoin.
*: Interactive receivers are not required to validate the original PSBT because they are not exposed to [[#probing-attack|probing attacks]].
===Sender's payjoin proposal checklist===
The sender should check the payjoin proposal before signing it to prevent a malicious receiver from stealing money.
* Verify that the absolute fee of the payjoin proposal is equals or higher than the original PSBT.
* If the receiver's BIP21 signalled pjos=0, disable payment output substitution.
* Verify that the transaction version, and the nLockTime are unchanged.
* Check that the sender's inputs' sequence numbers are unchanged.
* For each input in the proposal:
** Verify that no keypaths are in the PSBT input
** Verify that no partial signature has been filled
** If it is one of the sender's inputs:
*** Verify that input's sequence is unchanged.
*** Verify the PSBT input is not finalized
** If it is one of the receiver's inputs:
*** Verify the PSBT input is finalized
*** Verify that non_witness_utxo or witness_utxo are filled in.
** Verify that the payjoin proposal inputs all specify the same sequence value.
** Verify that all of sender's inputs from the original PSBT are in the proposal.
* For each output in the proposal:
** Verify that no keypaths are in the PSBT output
** If the output is the [[#fee-output|fee output]]:
*** The amount that was subtracted from the output's value is less than or equal to maxadditionalfeecontribution. Let's call this amount actual contribution.
*** Make sure the actual contribution is only going towards fees: The actual contribution is less than or equals to the difference of absolute fee between the payjoin proposal and the original PSBT.
*** Make sure the actual contribution is only paying for fees incurred by additional inputs: actual contribution is less than or equal to originalPSBTFeeRate * vsize(sender_input_type) * (count(payjoin_proposal_inputs) - count(original_psbt_inputs)). (see [[#fee-output|Fee output]] section)
** If the output is the payment output and payment output substitution is allowed,
*** Do not make any check
** Else
*** Make sure the output's value did not decrease.
** Verify that all sender's outputs (ie, all outputs except the output actually paid to the receiver) from the original PSBT are in the proposal.
* Once the proposal is signed, if minfeerate was specified, check that the fee rate of the payjoin transaction is not less than this value.
The sender must be careful to only sign the inputs that were present in the original PSBT and nothing else.
Note:
* The sender must allow the receiver to add/remove or modify the receiver's own outputs. (if payment output substitution is disabled, the receiver's outputs must not be removed or decreased in value)
* The sender should allow the receiver to not add any inputs. This is useful for the receiver to change the payment output scriptPubKey type.
* If the receiver added no inputs, the sender's wallet implementation should accept the payjoin proposal, but not mark the transaction as an actual payjoin in the user interface.
Our method of checking the fee allows the receiver and the sender to batch payments in the payjoin transaction.
It also allows the receiver to pay the fee for batching adding his own outputs.
==Rationale==
There are several consequences of our proposal:
* The receiver can bump the fee of the original transaction.
* The receiver can modify the outputs of the original PSBT.
* The sender must provide the UTXO information (Witness or previous transaction) in the PSBT.
===Respecting the minimum relay fee policy===
To be properly relayed, a Bitcoin transaction needs to pay at least 1 satoshi per virtual byte.
When blocks are not full, the original transaction might already at the minimum relay fee rate (currently 1 satoshi per virtual byte), so if the receiver adds their own input, they need to make sure the fee is increased such that the rate does not drop below the minimum relay fee rate.
In such case, the sender must set both maxadditionalfeecontribution= and additionalfeeoutputindex=.
See the [[#fee-output|Fee output]] section for more information.
We also recommend the sender to set minfeerate=, as the sender's node policy might be different from the receiver's policy.
===Defeating heuristics based on the fee calculation===
Most wallets are creating a round fee rate (like 2 sat/b).
If the payjoin transaction's fee was not increased by the added size, then those payjoin transactions could easily be identifiable on the blockchain.
Not only would those transactions stand out by not having a round fee (like 1.87 sat/b), but any suspicion of payjoin could be confirmed by checking if removing one input would create a round fee rate.
In such case, the sender must set both maxadditionalfeecontribution= and additionalfeeoutputindex=.
The recommended value maxadditionalfeecontribution= is explained in the [[#fee-output|Fee output]] section.
We also recommend the sender to set minfeerate=, as the sender's node policy might be different from the receiver's policy.
===Receiver does not need to be a full node===
Because the receiver needs to bump the fee to keep the same fee rate as the original PSBT, it needs the input's UTXO information to know what is the original fee rate. Without PSBT, light wallets like Wasabi Wallet would not be able to receive a payjoin transaction.
The validation (policy and consensus) of the original transaction is optional: a receiver without a full node can decide to create the payjoin transaction and automatically broadcast the original transaction after a timeout of 1 minute, and only verify that it has been propagated in the network.
However, non-interactive receivers (like a payment processor) need to verify the transaction to prevent UTXO probing attacks.
This is not a concern for interactive receivers like Wasabi Wallet, because those receivers can just limit the number of original PSBT proposals of a specific address to one. With such wallets, the attacker has no way to generate new deposit addresses to probe the UTXOs.
===Spare change donation===
Small change inside wallets are detrimental to privacy. Mixers like Wasabi wallet, because of its protocol, eventually generate such [[https://docs.wasabiwallet.io/using-wasabi/ChangeCoins.html#first-round-coinjoin-change|small change]].
A common way to protect your privacy is to donate those spare changes, to deposit them in an exchange or on your favorite merchant's store account. Those kind of transactions can easily be spotted on the blockchain: There is only one output.
However, if you donate via payjoin, it will look like a normal transaction.
On top of this the receiver can poison analysis by randomly faking a round amount of satoshi for the additional output.
===Payment output substitution===
Unless disallowed by the sender explicitly via disableoutputsubstitution=true or by the BIP21 URL via the query parameter pjos=0, the receiver is free to decrease the amount or change the scriptPubKey output paying to himself.
Note that if payment output substitution is disallowed, the receiver can still increase the amount of the output. (See [[#reference-impl|the reference implementation]])
For example, if the sender's scriptPubKey type is P2WPKH while the receiver's payment output in the original PSBT is P2SH, then the receiver can substitute the payment output to be P2WPKH to match the sender's scriptPubKey type.
===Unsecured payjoin server===
A receiver might run the payment server (generating the BIP21 invoice) on a different server than the payjoin server, which could be less trusted than the payment server.
In such case, the payment server can signal to the sender, via the BIP21 parameter pjos=0, that they MUST disallow [[#output-substitution|payment output substitution]].
A compromised payjoin server could steal the hot wallet outputs of the receiver, but would not be able to re-route payment to himself.
===Impacted heuristics===
Our proposal of payjoin breaks the following blockchain heuristics:
* Common inputs heuristics.
Because payjoin is mixing the inputs of the sender and receiver, this heuristic becomes unreliable.
* Change identification from scriptPubKey type heuristics
When Alice pays Bob, if Alice is using P2SH but Bob's deposit address is P2WPKH, the heuristic would assume that the P2SH output is the change address of Alice.
This is now however a broken assumption, as the payjoin receiver has the freedom to mislead analytics by purposefully changing the invoice's address in the payjoin transaction.
See [[#output-substitution|payment output substitution]].
* Change identification from round change amount
If Alice pays Bob, she might be tempted to pay him a round amount, like 1.23000000 BTC. When this happens, blockchain analysis often identifies the output without the round amount as the change of the transaction.
For this reason, during a [[#spare-change|spare change]] case, the receiver may add an output with a rounded amount randomly.
==Attack vectors==
===On the receiver side: UTXO probing attack===
When the receiver creates a payjoin proposal, they expose one or more inputs belonging to them.
An attacker could create multiple original transactions in order to learn the UTXOs of the receiver, while not broadcasting the payjoin proposal.
While we cannot prevent this type of attack entirely, we implemented the following mitigations:
* When the receiver detects an original transaction being broadcast, or if the receiver detects that the original transaction has been double spent, then they will reuse the UTXO that was exposed for the next payjoin.
* While the exposed UTXO will be reused in priority to not leak other UTXOs, there is no strong guarantee about it. This prevents the attacker from detecting with certainty the next payjoin of the merchant to another peer.
Note that probing attacks are only a problem for automated payment systems such as BTCPay Server. End-user wallets with payjoin capabilities are not affected, as the attacker can't create multiple invoices to force the receiver to expose their UTXOs.
===On the sender side: Double payment risk for hardware wallets===
For a successful payjoin to happen, the sender needs to sign two transactions double spending each other: The original transaction and the payjoin proposal.
The sender's software wallet can verify that the payjoin proposal is legitimate by the sender's checklist.
However, a hardware wallet can't verify that this is indeed the case. This means that the security guarantee of the hardware wallet is decreased. If the sender's software is compromised, the hardware wallet would sign two valid transactions, thus sending two payments.
Without payjoin, the maximum amount of money that could be lost by a compromised software is equal to one payment (via [[#output-substitution|payment output substitution]]).
Note that the sender can disallow [[#output-substitution|payment output substitution]] by using the optional parameter disableoutputsubstitution=true.
With payjoin, the maximum amount of money that can be lost is equal to two payments.
==Reference sender's implementation==
Here is pseudo code of a sender implementation.
RequestPayjoin takes the BIP21 URI of the payment, the wallet and the signedPSBT.
The signedPSBT represents a PSBT which has been fully signed, but not yet finalized.
We then prepare originalPSBT from the signedPSBT via the CreateOriginalPSBT function and get back the proposal.
While we verify the proposal, we also import into it information about our own inputs and outputs from the signedPSBT.
At the end of this RequestPayjoin, the proposal is verified and ready to be signed.
We logged the different PSBT involved, and show the result in our [[#test-vectors|test vectors]].
public async Task RequestPayjoin(
BIP21Uri bip21,
Wallet wallet,
PSBT signedPSBT,
PayjoinClientParameters optionalParameters)
{
Log("Unfinalized signed PSBT" + signedPSBT);
// Extracting the pj link.
var endpoint = bip21.ExtractPayjointEndpoint();
if (signedPSBT.IsAllFinalized())
throw new InvalidOperationException("The original PSBT should not be finalized.");
PSBTOutput feePSBTOutput = null;
bool allowOutputSubstitution = !optionalParameters.DisableOutputSubstitution;
if (bip21.Parameters.Contains("pjos") && bip21.Parameters["pjos"] == "0")
allowOutputSubstitution = false;
if (optionalParameters.AdditionalFeeOutputIndex != null && optionalParameters.MaxAdditionalFeeContribution != null)
feePSBTOutput = signedPSBT.Outputs[optionalParameters.AdditionalFeeOutputIndex];
Script paymentScriptPubKey = bip21.Address == null ? null : bip21.Address.ScriptPubKey;
decimal originalFee = signedPSBT.GetFee();
PSBT originalPSBT = CreateOriginalPSBT(signedPSBT);
Transaction originalGlobalTx = signedPSBT.GetGlobalTransaction();
TxOut feeOutput = feePSBTOutput == null ? null : originalGlobalTx.Outputs[feePSBTOutput.Index];
var originalInputs = new Queue<(TxIn OriginalTxIn, PSBTInput SignedPSBTInput)>();
for (int i = 0; i < originalGlobalTx.Inputs.Count; i++)
{
originalInputs.Enqueue((originalGlobalTx.Inputs[i], signedPSBT.Inputs[i]));
}
var originalOutputs = new Queue<(TxOut OriginalTxOut, PSBTOutput SignedPSBTOutput)>();
for (int i = 0; i < originalGlobalTx.Outputs.Count; i++)
{
originalOutputs.Enqueue((originalGlobalTx.Outputs[i], signedPSBT.Outputs[i]));
}
// Add the client side query string parameters
endpoint = ApplyOptionalParameters(endpoint, optionalParameters);
Log("original PSBT" + originalPSBT);
PSBT proposal = await SendOriginalTransaction(endpoint, originalPSBT, cancellationToken);
Log("payjoin proposal" + proposal);
// Checking that the PSBT of the receiver is clean
if (proposal.GlobalXPubs.Any())
{
throw new PayjoinSenderException("GlobalXPubs should not be included in the receiver's PSBT");
}
////////////
if (proposal.CheckSanity() is List errors && errors.Count > 0)
throw new PayjoinSenderException($"The proposal PSBT is not sane ({errors[0]})");
var proposalGlobalTx = proposal.GetGlobalTransaction();
// Verify that the transaction version, and nLockTime are unchanged.
if (proposalGlobalTx.Version != originalGlobalTx.Version)
throw new PayjoinSenderException($"The proposal PSBT changed the transaction version");
if (proposalGlobalTx.LockTime != originalGlobalTx.LockTime)
throw new PayjoinSenderException($"The proposal PSBT changed the nLocktime");
HashSet sequences = new HashSet();
// For each inputs in the proposal:
foreach (PSBTInput proposedPSBTInput in proposal.Inputs)
{
if (proposedPSBTInput.HDKeyPaths.Count != 0)
throw new PayjoinSenderException("The receiver added keypaths to an input");
if (proposedPSBTInput.PartialSigs.Count != 0)
throw new PayjoinSenderException("The receiver added partial signatures to an input");
PSBTInput proposedTxIn = proposalGlobalTx.Inputs.FindIndexedInput(proposedPSBTInput.PrevOut).TxIn;
bool isOurInput = originalInputs.Count > 0 && originalInputs.Peek().OriginalTxIn.PrevOut == proposedPSBTInput.PrevOut;
// If it is one of our input
if (isOurInput)
{
OutPoint inputPrevout = ourPrevouts.Dequeue();
TxIn originalTxin = originalGlobalTx.Inputs.FromOutpoint(inputPrevout);
PSBTInput originalPSBTInput = originalPSBT.Inputs.FromOutpoint(inputPrevout);
// Verify that sequence is unchanged.
if (input.OriginalTxIn.Sequence != proposedTxIn.Sequence)
throw new PayjoinSenderException("The proposedTxIn modified the sequence of one of our inputs")
// Verify the PSBT input is not finalized
if (proposedPSBTInput.IsFinalized())
throw new PayjoinSenderException("The receiver finalized one of our inputs");
sequences.Add(proposedTxIn.Sequence);
// Fill up the info from the original PSBT input so we can sign and get fees.
proposedPSBTInput.NonWitnessUtxo = input.SignedPSBTInput.NonWitnessUtxo;
proposedPSBTInput.WitnessUtxo = input.SignedPSBTInput.WitnessUtxo;
// We fill up information we had on the signed PSBT, so we can sign it.
foreach (var hdKey in input.SignedPSBTInput.HDKeyPaths)
proposedPSBTInput.HDKeyPaths.Add(hdKey.Key, hdKey.Value);
proposedPSBTInput.RedeemScript = signedPSBTInput.RedeemScript;
proposedPSBTInput.RedeemScript = input.SignedPSBTInput.RedeemScript;
}
else
{
// Verify the PSBT input is finalized
if (!proposedPSBTInput.IsFinalized())
throw new PayjoinSenderException("The receiver did not finalized one of their input");
// Verify that non_witness_utxo or witness_utxo are filled in.
if (proposedPSBTInput.NonWitnessUtxo == null && proposedPSBTInput.WitnessUtxo == null)
throw new PayjoinSenderException("The receiver did not specify non_witness_utxo or witness_utxo for one of their inputs");
sequences.Add(proposedTxIn.Sequence);
}
}
// Verify that all of sender's inputs from the original PSBT are in the proposal.
if (originalInputs.Count != 0)
throw new PayjoinSenderException("Some of our inputs are not included in the proposal");
// Verify that the payjoin proposal did not introduced mixed inputs' sequence.
if (sequences.Count != 1)
throw new PayjoinSenderException("Mixed sequence detected in the proposal");
decimal newFee = proposal.GetFee();
decimal additionalFee = newFee - originalFee;
if (additionalFee < 0)
throw new PayjoinSenderException("The receiver decreased absolute fee");
// For each outputs in the proposal:
foreach (PSBTOutput proposedPSBTOutput in proposal.Outputs)
{
// Verify that no keypaths is in the PSBT output
if (proposedPSBTOutput.HDKeyPaths.Count != 0)
throw new PayjoinSenderException("The receiver added keypaths to an output");
if (originalOutputs.Count == 0)
continue;
var originalOutput = originalOutputs.Peek();
bool isOriginalOutput = originalOutput.OriginalTxOut.ScriptPubKey == proposedPSBTOutput.ScriptPubKey;
bool substitutedOutput = !isOriginalOutput &&
allowOutputSubstitution &&
originalOutput.OriginalTxOut.ScriptPubKey == paymentScriptPubKey;
if (isOriginalOutput || substitutedOutput)
{
originalOutputs.Dequeue();
if (originalOutput.OriginalTxOut == feeOutput)
{
var actualContribution = feeOutput.Value - proposedPSBTOutput.Value;
// The amount that was subtracted from the output's value is less than or equal to maxadditionalfeecontribution
if (actualContribution > optionalParameters.MaxAdditionalFeeContribution)
throw new PayjoinSenderException("The actual contribution is more than maxadditionalfeecontribution");
// Make sure the actual contribution is only paying fee
if (actualContribution > additionalFee)
throw new PayjoinSenderException("The actual contribution is not only paying fee");
// Make sure the actual contribution is only paying for fee incurred by additional inputs
// This assumes an additional input can be up to 110 bytes.
int additionalInputsCount = proposalGlobalTx.Inputs.Count - originalGlobalTx.Inputs.Count;
if (actualContribution > originalFeeRate * 110 * additionalInputsCount)
throw new PayjoinSenderException("The actual contribution is not only paying for additional inputs");
}
else if (allowOutputSubstitution && output.OriginalTxOut.ScriptPubKey == paymentScriptPubKey)
{
// That's the payment output, the receiver may have changed it.
}
else
{
if (originalOutput.OriginalTxOut.Value > proposedPSBTOutput.Value)
throw new PayjoinSenderException("The receiver decreased the value of one of the outputs");
}
// We fill up information we had on the signed PSBT, so we can sign it.
foreach (var hdKey in output.SignedPSBTOutput.HDKeyPaths)
proposedPSBTOutput.HDKeyPaths.Add(hdKey.Key, hdKey.Value);
proposedPSBTOutput.RedeemScript = output.SignedPSBTOutput.RedeemScript;
}
}
// Verify that all of sender's outputs from the original PSBT are in the proposal.
if (originalOutputs.Count != 0)
{
// The payment output may have been substituted
if (!allowOutputSubstitution ||
originalOutputs.Count != 1 ||
originalOutputs.Dequeue().OriginalTxOut.ScriptPubKey != paymentScriptPubKey)
{
throw new PayjoinSenderException("Some of our outputs are not included in the proposal");
}
}
// After signing this proposal, we should check if minfeerate is respected.
Log("payjoin proposal filled with sender's information" + proposal);
return proposal;
}
// Finalize the signedPSBT and remove confidential information
PSBT CreateOriginalPSBT(PSBT signedPSBT)
{
var original = signedPSBT.Clone();
original = original.Finalize();
foreach (var input in original.Inputs)
{
input.HDKeyPaths.Clear();
input.PartialSigs.Clear();
input.Unknown.Clear();
}
foreach (var output in original.Outputs)
{
output.Unknown.Clear();
output.HDKeyPaths.Clear();
}
original.GlobalXPubs.Clear();
return original;
}
==Implementations==
* [[https://github.com/BlueWallet/BlueWallet|BlueWallet]] is in the process of implementing the protocol.
* [[https://github.com/btcpayserver/btcpayserver|BTCPay Server]] has implemented sender and receiver side of this protocol.
* [[https://github.com/zkSNACKs/WalletWasabi/|Wasabi Wallet]] has merged sender's support.
* [[https://github.com/JoinMarket-Org/joinmarket-clientserver|Join Market]] has implemented sender and receiver side of this protocol.
* [[https://github.com/bitcoinjs/payjoin-client|JavaScript sender implementation]].
==Backward compatibility==
The receivers advertise payjoin capabilities through [[bip-0021.mediawiki|BIP21's URI Scheme]].
Senders not supporting payjoin will just ignore the pj variable and thus, will proceed to normal payment.
==Special thanks==
Special thanks to Kukks for developing the initial support to BTCPay Server, to junderw, AdamISZ, lukechilds, ncoelho, nopara73, lontivero, yahiheb, SomberNight, andrewkozlik, instagibbs, RHavar for all the feedback we received since our first implementation.
Thanks again to RHavar who wrote the [[bip-0079.mediawiki|BIP79 Bustapay]] proposal, this gave a good starting point for our proposal.
================================================
FILE: bip-0079.mediawiki
================================================
==Abstract==
The way bitcoin transactions are normally created leaks more information than desirable, and as a result has been exploited by unreasonably effective blockchain analysis techniques to jeopardize important properties that are expected of a useful currency.
Bustapay is a simple and practical protocol for the sender and receiver of a payment to collaboratively sign a bitcoin transaction in such a way that busts some analysis assumptions to the immediate benefit of the sender and receiver. Furthermore it does so in such a way that gives a significant amount of control to the receiver to help manage their utxo set size, a constant problem for bitcoin merchants.
==Copyright==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
==Motivation==
One of the most powerful blockchain analysis heuristics has been to assume all inputs of a transaction are controlled by a single party unless otherwise known (such as by the distinctive structure of a traditional coinjoin, or multisig spends that are validated onchain). Combined with other techniques (notably change-output guessing) this has lead to unexpectedly accurate tracking that has exposed bitcoin participants to unacceptable personal, business and financial risks -- undermining bitcoin's utility and fungibility -- and ultimately jeopardizing its ability to function as useful money.
We however can bust these assumptions with a sender-receiver coinjoin. To prevent costless spy/DoS attacks, we require the sending party to provide a fully-valid ready-to-propagate transaction to initiate the process, that the receiver can broadcast if the sender never completes the coinjoin thus tying the cost to that of spending a utxo. Most promisingly, bustapay transactions do not have an identifiable structure so any network analysis will be not able to tell if a given transaction is a bustapay transaction or not which erodes the confidence of their entire models, providing positive externalities for the entire bitcoin ecosystem.
Bustapay transactions also do not grow the receiver's count of unspent transaction outputs, and in fact gives the receiver an opportunity to better manage their utxo set, something normally only done when sending payments. Large utxo sets are often problematic and expensive, and frequently requiring privacy-destroying consolidation. Besides busting clustering assumptions, bustapay also provides a layer of obfuscation of send amounts.
It is worth noting that this specification has eschewed complexity and potentially useful extensions on the assumption that simplicity is of the most important to encourage adoption.
==Overview==
A bustapay payment is made from a sender to a receiver.
====Step 1. Sender creates a bitcoin transaction paying the receiver====
This transaction must use segwit for all inputs, and be fully valid and signed. The transaction must be eligible for propagation on the network (but not done so at this stage)
====Step 2. Sender gives the "template transaction" to the receiver====
This is done via an HTTP POST request, sent to a "bustapay url"
====Step 3. Receiver processes the transaction and returns a partially signed coinjoin====
The receiver validates the transaction, and pays himself. The receiver then adds one or more of his own inputs (known as the ''contributed inputs'') and (optionally) increases the output that pays himself (generally by the sum of the ''contributed inputs''). Doing so creates a ''partial transaction'', which the receiver returns to the sender. It is called such as it requires the sender to re-sign his own inputs.
====Step 4. Sender validates, re-signs, and propagates on the bitcoin network====
The sender MUST validate the ''partial transaction'' was changed correctly and non-maliciously (to allow using potentially untrusted communication channels), re-sign its original inputs and propagate the final transaction over the bitcoin network.
====Step 5. Receiver observes the finalized transaction on the bitcoin network====
Once the receiver has seen the finalized transactions on the network (and has enough confirmations) it can process it like a normal payment for the sent amount (as opposed to the amount that it looks like on the network). If the receiver does not see the finalized transaction after a timeout, they will propagate the original "template transaction", which ensures the payment happens and functions a strong anti-DoS mechanism.
== Specification ==
The standard way of letting a sender know where to send a bustapay transaction is done via a bip21 encoded address. The key value "bpu" (short for "BustaPayUrl") should be used. An example of such address would be bitcoin:2NABbUr9yeRCp1oUCtVmgJF8HGRCo3ifpTT?bpu=https://bp.bustabit.com/submit It is highly encouraged that urls are kept short.
When the sender is creating a "template transaction" it is done almost identically to creating a normal send, with the exception that *only* segwit inputs may be used. The sender is also encouraged to use a slightly more aggressive feerate than usual as well as BIP125 (Opt-in Full Replace-by-Fee Signaling), but neither is strictly required.
The template transaction should be sent to the receiver via an HTTP POST to the bustapay url, with a binary encoded body.
The receiver is then responsible for validating the template transaction. If there is a problem with the transaction, or the receiver is generally unhappy with the transaction (e.g. fees are too small) the HTTP response code of 422 should be used and a human-readable string containing information on why which can be directly given to the user.
Should the receiver reject a transaction, it should not attempt to propagate it on the network. However it is important for the sender to be aware that the receiver *could* at any time (regardless of which error was given) send this transaction. The client should therefore assume the receiver will, and act accordingly (either retry with adjustments or just propagate the transaction). It is imperative that the sender never finds themselves in a situation where two payments to the sender could be valid.
=== Contributed Input Choice ===
The receiver must add at least one input to the transaction (the "contributed inputs"). If the receiver has no inputs, it should use a 500 internal server error, so the client can send the transaction as per normal (or try again later). Its generally advised to only add a single contributed input, however they are circumstances where adding more than a single input can be useful.
To prevent an attack where a receiver is continually sent variations of the same transaction to enumerate the receiver's utxo set, it is essential that the receiver always returns the same contributed inputs when it's seen the same inputs.
It is strongly preferable that the receiver makes an effort to pick a contributed input of the same type as the other transaction inputs if possible.
=== Output Adjustment ===
After adding inputs to the transaction, the receiver generally will want to adjust the output that pays himself by increasing it by the sum of the contributed input amounts (minus any fees he wants to contribute). However the only strict requirement is that the receiver *must never* remove inputs, and *must not* ever decrease any output amount.
=== Returning the partial transaction ===
The receiver must sign all contributed inputs in the partial transaction. The partial transaction should also remove all witnesses from the original template transaction as they are no longer valid, and need to be recalculated by the sender. The receiver returns the partial transaction as a binary-encoded HTTP response with a status code of 200. To ensure compatibility with web-wallets and browser-based-tools, all responses (including errors) must contain the HTTP header "Access-Control-Allow-Origin: *"
=== Sender Validation ===
The sender *must* do important validation on the partial transaction. They *must* verify:
* All template transaction inputs are in the partial transaction (but perhaps different order) and have the same sequence numbers.
* The partial transaction contains at least one new (and signed) segwit input (owned by the receiver)
* All outputs from the template transaction exist in the partial transaction, except they are allowed to be reordered and have their amounts increased (but *never* decreased)
=== Creating Final Transaction ===
After validating the partial transaction, the sender signs all its inputs to create what is now the final transaction. It is important that the sender is careful to not be tricked by the receiver into signing other inputs it owns. The sender must only sign inputs that existed in the template transaction. If the sender is not careful the receiver may "contribute" inputs that are actually owned by the sender, with the hope the sender blindly signs everything.
=== Transaction Publishing ===
Once the final transaction is created, the sender should publish it directly onto the bitcoin network. If the sender does not do this after a reasonable time (e.g. 1 minute), the receiver should publish the template transaction as an important anti-spy/anti-DoS tactic . The sender may also choose to publish the template transaction instead of the final transaction if they believe the receiver to have unreasonably lowered the feerate of the transaction (i.e. increased the size of the transaction, but not the feerate enough). And both parties can consider publishing the template transaction even after the finalized transaction is on the network (taking advantage of replace-by-fee) if the final transaction is not confirming and the template transaction has more fees.
=== Implementation Notes ===
For anyone wanting to implement bustapay payments, here are some notes for receivers:
* A transaction can easily be checked if it's suitable for the mempool with testmempoolaccept in bitcoin core 0.17+
* Tracking transactions by txid is precarious. To keep your sanity make sure all inputs are segwit. But remember segwit does not prevent txid malleability unless you validate the transaction. So really make sure you're using testmempoolaccept at the very least
* Bustapay could be abused by a malicious party to query if you own a deposit address or not. So never accept a bustapay transaction that pays an already used deposit address
* You will need to keep a mapping of which utxos people have showed you and which you revealed. So if you see them again, you can reveal the same one of your own
* Check if the transaction was already sorted according to BIP69, if so ensure the result stays that way. Otherwise probably just shuffle the inputs/outputs
* A reference implementation is maintained at https://github.com/rhavar/bustapay which functions as a wrapper around some RPC calls to bitcoin core's wallet.
* The sender must be careful of an attack where the receiver tries to add additional inputs that are controlled by the sender, with the hope that the sender blindly signs it.
== Backwards Compatibility ==
Bustapay is an optional payment protocol and therefore has no backwards compatibility concerns. It in fact can only be supported in addition to normal transaction processing, as falling back to a normal bitcoin transaction is a required behavior.
== Credits ==
The idea is obviously based upon Dr. Maxwell's seminal CoinJoin proposal, and reduced scope inspired by a simplification of the "pay 2 endpoint" blog post by blockstream.
================================================
FILE: bip-0080.mediawiki
================================================
BIP: 80
Title: Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets
Authors: Justus Ranvier
Jimmy Song
Status: Closed
Type: Informational
Assigned: 2014-08-11
License: PD
==Abstract==
This BIP defines a logical hierarchy for non-colored voting pool deterministic multisig wallets based on an algorithm described in BIP-0032 (BIP32 from now on) and purpose scheme described in BIP-0043 (BIP43 from now on).
This BIP is a particular application of BIP43 and is based on BIP44.
==Motivation==
The hierarchy proposed in this paper allows the handling of multiple coins and multiple series from a single seed.
==Path levels==
We define the following 4 levels in BIP32 path:
m / purpose' / coin_type' / series' / address_index
Apostrophe in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
===Purpose===
Purpose is a constant set following the BIP43 recommendation to: the ASCII value of "80" with the most significant bit set to indicate hardened derivation (0x80000050). It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
===Coin type===
One master node (seed) can be used for unlimited number of independent cryptocoins such as Bitcoin, Litecoin or Namecoin. However, sharing the same space for various cryptocoins has some disadvantages.
This level creates a separate subtree for every cryptocoin, avoiding reusing addresses across cryptocoins and improving privacy issues.
Coin type is a constant, set for each cryptocoin. The list of registered coin type constants should be obtained from BIP44.
Hardened derivation is used at this level.
===Series===
Series are used by voting pools in order to implement FIFO cold storage. By directing deposits into multiple series, the private keys for most of the deposits can be kept offline, and a limited portion can be brought online to process withdrawals.
Hardened derivation is used at this level.
===Index===
Public/private keypairs are numbered from index 0 in sequentially increasing manner. This number is used as child index in BIP32 derivation.
Public keys obtained at this level of the hierarchy are used to construct multisig deposit scripts, using a schema that is shared between the members as an out-of-band contract.
Public derivation is used at this level.
==Compatible wallets==
* [[https://github.com/btcsuite/btcwallet|btcwallet]] is the reference Bitcoin wallet for voting pools.
==Copyright==
This document is placed in the public domain.
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
================================================
FILE: bip-0081.mediawiki
================================================
BIP: 81
Title: Hierarchy for Colored Voting Pool Deterministic Multisig Wallets
Authors: Justus Ranvier
Jimmy Song
Status: Closed
Type: Informational
Assigned: 2014-08-11
License: PD
==Abstract==
This BIP defines a logical hierarchy for colored coin voting pool deterministic multisig wallets based on an algorithm described in BIP-0032 (BIP32 from now on) and purpose scheme described in BIP-0043 (BIP43 from now on).
This BIP is a particular application of BIP43 and is based on BIP44.
==Motivation==
The hierarchy proposed in this paper allows the handling of multiple color definitions from a single seed.
==Path levels==
We define the following 8 levels in BIP32 path:
m / purpose' / series' / (5 color definition levels) / address_index
Apostrophe in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
===Purpose===
Purpose is a constant set following the BIP43 recommendation to: the ASCII value of "81" with the most significant bit set to indicate hardened derivation (0x80000051). It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
===Color Definition===
Index values which can be applied to a BIP32 node are limited to 4 bytes (32 bits).
Since this is not sufficient to identify color definitions without a risk of collision, multiple levels are used.
Color definitions are first shortened to 20 bytes using the Bitcoin hash160 function.
The resulting 20 bytes are split into five groups in little endian format, and where each group is used as the seed for the five levels of color definition levels
Public derivation is used at these levels, even when the index exceeds 2^31.
===Index===
Public/private keypairs are numbered from index 0 in sequentially increasing manner. This number is used as child index in BIP32 derivation.
Public keys obtained at this level of the hierarchy are used to construct multisig deposit scripts, using a schema that is shared between the members as an out-of-band contract.
Public derivation is used at this level.
==Compatible wallets==
* [[https://github.com/btcsuite/btcwallet|btcwallet]] is the reference Bitcoin wallet for voting pools.
==Copyright==
This document is placed in the public domain.
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
* [[bip-0080.mediawiki|BIP80 - Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets]]
================================================
FILE: bip-0083.mediawiki
================================================
==Abstract==
This BIP defines a scheme for key derivation that allows for dynamic creation of key hierarchies based on the algorithm described in BIP32.
==Motivation==
Several proposals have been made to try to standardize a structure for hierarchical deterministic wallets for the sake of interoperability (reference BIP32, BIP44, BIP45). However, all proposals to date have tried to impose a specific structure upfront without providing any flexibility for dynamic creation of new hierarchical levels with different semantics or mapping between different applications that use distinct structures.
Instead of attempting to impose a specific structure upfront, this BIP proposes that we design the derivation in such a way that we can continue extending hierarchies arbitrarily and indefinitely.
==Specification==
BIP32 provides a hierarchical derivation scheme where every node in the tree can be either used to derive child nodes or used as a signing key for ECDSA. This means that as soon as we choose to use a node as a signing key, we can no longer derive children from that node. To draw an analogy to file systems, each node is either a file or a directory but never both. However, given the need to predictably know the location of new children, it is generally not a good idea to mix both signing keys and parent nodes at the same level in the hierarchy. This means that as soon as we've decided that a particular level in the hierarchy is to be used for signing keys, we've lost the ability to nest deeper levels into the tree.
At every level of the hierarchy, we reserve the child with index 0 to allow further nesting, and for signing key parent nodes use child indices 1 to MAX_INDEX (231 - 1) for signing keys. We can use either hardened or nonhardened derivation.
Let p denote a specific signing key parent node and k be an index greater than 0. The children signing keys are then:
p / k
with k > 0.
To create sublevels, we derive the nested nodes:
p / 0 / n
with n ≥ 0.
Each of these nodes can now contain signing key children of their own, and again we reserve index 0 to allow deeper nesting.
==Notation==
We propose the following shorthand for writing nested node derivations:
p // n instead of p / 0 / n
p //' n instead of p / 0' / n
==Mappings==
Rather than specifying upfront which path is to be used for a specific purpose (i.e. external invoicing vs. internal change), different applications can specify arbitrary parent nodes and derivation paths. This allows for nesting of sublevels to arbitrary depth with application-specified semantics. Rather than trying to specify use cases upfront, we leave the design completely open-ended. Different applications can exchange these mappings for interoperability. Eventually, if certain mappings become popular, application user interfaces can provide convenient shortcuts or use them as defaults.
Note that BIP32 suggests reserving child 0 for the derivation of signing keys rather than sublevels. It is not really necessary to reserve signing key parents, however, as each key's parent's path can be explicitly stated. But unless we reserve a child for sublevel derivation, we lose the ability to nest deeper levels into the hierarchy. While we could reserve any arbitrary index for nesting sublevels, reserving child 0 seems simplest to implement, leaving all indices > 0 for contiguously indexed signing keys. We could also use MAX_INDEX (231 - 1) for this purpose. However, we believe doing so introduces more idiosyncrasies into the semantics and will present a problem if we ever decide to extend the scheme to use indices larger than 31 bits.
==Use Cases==
===Account Hierarchies===
For all that follows, we assume that key indices k > 0 and parent node indices n ≥ 0.
From a master seed m, we can construct a default account using the following derivations for nonhardened signing keys:
m / 1 / k (for change/internal outputs)
m / 2 / k (for invoice/external outputs)
To create subaccount an, we use:
an = m // n
To generate keys for subaccount an, we use:
an / 1 / k (for change/internal outputs)
an / 2 / k (for invoice/external outputs)
We can continue creating subaccounts indefinitely using this scheme.
===Bidirectional Payment Channels===
In order to create a bidirectional payment channel, it is necessary that previous commitments be revokable. In order to revoke previous commitments, each party reveals a secret to the other that would allow them to steal the funds in the channel if a transaction for a previous commitment is inserted into the blockchain.
By allowing for arbitrary nesting of sublevels, we can construct decision trees of arbitrary depth and revoke an entire branch by revealing a parent node used to derive all the children.
==References==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[https://lightning.network/lightning-network-paper.pdf|Lightning Network Whitepaper]]
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0084.mediawiki
================================================
BIP: 84
Layer: Applications
Title: Derivation scheme for P2WPKH based accounts
Authors: Pavol Rusnak
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0084
Status: Deployed
Type: Specification
Assigned: 2017-12-28
License: CC0-1.0
==Abstract==
This BIP defines the derivation scheme for HD wallets using the P2WPKH ([[bip-0173.mediawiki|BIP 173]]) serialization format for segregated witness transactions.
==Motivation==
With the usage of P2WPKH transactions it is necessary to have a common derivation scheme.
It allows the user to use different HD wallets with the same masterseed and/or a single account seamlessly.
Thus the user needs to create dedicated segregated witness accounts, which ensures that only wallets compatible with this BIP will detect the accounts and handle them appropriately.
===Considerations===
We use the same rationale as described in Considerations section of [[bip-0049.mediawiki|BIP 49]].
==Specifications==
This BIP defines the two needed steps to derive multiple deterministic addresses based on a [[bip-0032.mediawiki|BIP 32]] root account.
===Public key derivation===
To derive a public key from the root account, this BIP uses the same account-structure as defined in [[bip-0044.mediawiki|BIP 44]] and [[bip-0049.mediawiki|BIP 49]], but only uses a different purpose value to indicate the different transaction serialization method.
For the purpose-path level it uses 84'. The rest of the levels are used as defined in BIP44 or BIP49.
===Address derivation===
To derive the P2WPKH address from the above calculated public key, we use the encapsulation defined in [[bip-0141.mediawiki#p2wpkh|BIP 141]]:
witness:
scriptSig: (empty)
scriptPubKey: 0 <20-byte-key-hash>
(0x0014{20-byte-key-hash})
===Extended Key Version===
When serializing extended keys, this scheme uses alternate version bytes. Extended public keys use 0x04b24746 to produce a "zpub" prefix, and private keys use 0x04b2430c to produce a "zprv" prefix. Testnet uses 0x045f1cf6 "vpub" and 0x045f18bc "vprv."
Additional registered version bytes are listed in [[https://github.com/satoshilabs/slips/blob/master/slip-0132.md|SLIP-0132]].
==Backwards Compatibility==
This BIP is not backwards compatible by design as described under [[#considerations|considerations]]. An incompatible wallet will not discover accounts at all and the user will notice that something is wrong.
==Test vectors==
==Abstract==
''"One Seed to rule them all,''
''One Key to find them,''
''One Path to bring them all,''
''And in cryptography bind them."''
It is not possible to maintain one single (mnemonic) seed backup for all keychains used across various wallets because there are a variety of incompatible standards. Sharing of seeds across multiple wallets is not desirable for security reasons. Physical storage of multiple seeds is difficult depending on the security and redundancy required.
As HD keychains are essentially derived from initial entropy, this proposal provides a way to derive entropy from the keychain which can be fed into whatever method a wallet uses to derive the initial mnemonic seed or root key.
==Copyright==
This BIP is dual-licensed under the Open Publication License and BSD 2-clause license.
==Definitions==
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
The terminology related to keychains used in the wild varies widely, for example `seed` has various different meanings. In this document we define the terms
# '''BIP32 root key''' is the root extended private key that is represented as the top root of the keychain in BIP32.
# '''BIP39 mnemonic''' is the mnemonic phrase that is calculated from the entropy used before hashing of the mnemonic in BIP39.
# '''BIP39 seed''' is the result of hashing the BIP39 mnemonic seed.
When in doubt, assume big endian byte serialization, such that the leftmost
byte is the most significant.
==Motivation==
Most wallets implement BIP32 which defines how a BIP32 root key can be used to derive keychains. As a consequence, a backup of just the BIP32 root key is sufficient to include all keys derived from it. BIP32 does not have a human-friendly serialization of the BIP32 root key (or BIP32 extended keys in general), which makes paper backups or manually restoring the key more error-prone. BIP39 was designed to solve this problem, but rather than serialize the BIP32 root key, it takes some entropy, encoded to a "seed mnemonic", which is then hashed to derive the BIP39 seed, which can be turned into the BIP32 root key. Saving the BIP39 mnemonic is enough to reconstruct the entire BIP32 keychain, but a BIP32 root key cannot be reversed back to the BIP39 mnemonic.
Most wallets implement BIP39, so on initialization or restoration, the user must interact with a BIP39 mnemonic. Most wallets do not support BIP32 extended private keys, so each wallet must either share the same BIP39 mnemonic, or have a separate BIP39 mnemonic entirely. Neither scenario is particularly satisfactory for security reasons. For example, some wallets may be inherently less secure, like hot wallets on smartphones, JoinMarket servers, or Lightning Network nodes. Having multiple seeds is far from desirable, especially for those who rely on split key or redundancy backups in different geological locations. Adding keys is necessarily difficult and may result in users being more lazy with subsequent keys, resulting in compromised security or loss of keys.
There is an added complication with wallets that implement other standards, or no standards at all. The Bitcoin Core wallet uses a WIF as the ''hdseed'', and yet other wallets, like Electrum, use different mnemonic schemes to derive the BIP32 root key. Other cryptocurrencies, like Monero, use an entirely different mnemonic scheme.
Ultimately, all of the mnemonic/seed schemes start with some "initial entropy" to derive a mnemonic/seed, and then process the mnemonic into a BIP32 key, or private key. We can use BIP32 itself to derive the "initial entropy" to then recreate the same mnemonic or seed according to the specific application standard of the target wallet. We can use a BIP44-like categorization to ensure uniform derivation according to the target application type.
==Specification==
We assume a single BIP32 master root key. This specification is not concerned with how this was derived (e.g. directly or via a mnemonic scheme such as BIP39).
For each application that requires its own wallet, a unique private key is derived from the BIP32 master root key using a fully hardened derivation path. The resulting private key (k) is then processed with HMAC-SHA512, where the key is "bip-entropy-from-k", and the message payload is the private key k: HMAC-SHA512(key="bip-entropy-from-k", msg=k)
The reason for running the derived key through HMAC-SHA512 and truncating the result as necessary is to prevent leakage of the parent tree should the derived key (''k'') be compromised. While the specification requires the use of hardened key derivation which would prevent this, we cannot enforce hardened derivation, so this method ensures the derived entropy is hardened. Also, from a semantic point of view, since the purpose is to derive entropy and not a private key, we are required to transform the child key. This is done out of an abundance of caution, in order to ward off unwanted side effects should ''k'' be used for a dual purpose, including as a nonce ''hash(k)'', where undesirable and unforeseen interactions could occur.
.
The result produces 512 bits of entropy. Each application SHOULD use up to the required number of bits necessary for their operation, and truncate the rest.
The HMAC-SHA512 function is specified in [https://tools.ietf.org/html/rfc4231 RFC 4231].
===Test vectors===
====Test case 1====
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/0'/0'
OUTPUT:
* DERIVED KEY=cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0
* DERIVED ENTROPY=efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7
====Test case 2====
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
*PATH: m/83696968'/0'/1'
OUTPUT
* DERIVED KEY=503776919131758bb7de7beb6c0ae24894f4ec042c26032890c29359216e21ba
* DERIVED ENTROPY=70c6e3e8ebee8dc4c0dbba66076819bb8c09672527c4277ca8729532ad711872218f826919f6b67218adde99018a6df9095ab2b58d803b5b93ec9802085a690e
==BIP85-DRNG==
BIP85-DRNG-SHAKE256 is a deterministic random number generator for cryptographic functions that require deterministic outputs, but where the input to that function requires more than the 64 bytes provided by BIP85's HMAC output. BIP85-DRNG-SHAKE256 uses BIP85 to seed a SHAKE256 stream (from the SHA-3 standard). The input must be exactly 64 bytes long (from the BIP85 HMAC output).
RSA key generation is an example of a function that requires orders of magnitude more than 64 bytes of random input. Further, it is not possible to precalculate the amount of random input required until the function has completed.
drng_reader = BIP85DRNG.new(bip85_entropy)
rsa_key = RSA.generate_key(4096, drng_reader.read)
===Test Vectors===
INPUT:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* MASTER BIP32 ROOT KEY: m/83696968'/0'/0'
OUTPUT
* DERIVED KEY=cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0
* DERIVED ENTROPY=efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7
* DRNG(80 bytes)=b78b1ee6b345eae6836c2d53d33c64cdaf9a696487be81b03e822dc84b3f1cd883d7559e53d175f243e4c349e822a957bbff9224bc5dde9492ef54e8a439f6bc8c7355b87a925a37ee405a7502991111
==Applications==
The Application number defines how entropy will be used post processing. Some basic examples follow:
Derivation paths follow the format m/83696968'/{app_no}'/{index}', where ''{app_no}'' is the path for the application, and ''{index}'' is the index.
Application numbers should be semantic in some way, such as a BIP number or ASCII character code sequence.
===BIP39===
Application number: 39'
Truncate trailing (least significant) bytes of the entropy to the number of bits required to map to the relevant word length: 128 bits for 12 words, 256 bits for 24 words.
The derivation path format is: m/83696968'/39'/{language}'/{words}'/{index}'
Example: a BIP39 mnemonic with 12 English words (first index) would have the path m/83696968'/39'/0'/12'/0', the next key would be m/83696968'/39'/0'/12'/1' etc.
Language Table
{|
!Wordlist
!Code
|-
| English
| 0'
|-
| Japanese
| 1'
|-
| Korean
| 2'
|-
| Spanish
| 3'
|-
| Chinese (Simplified)
| 4'
|-
| Chinese (Traditional)
| 5'
|-
| French
| 6'
|-
| Italian
| 7'
|-
| Czech
| 8'
|-
| Portuguese
| 9'
|-
|}
Words Table
{|
!Words
!Entropy
!Code
|-
| 12 words
| 128 bits
| 12'
|-
| 15 words
| 160 bits
| 15'
|-
| 18 words
| 192 bits
| 18'
|-
| 21 words
| 224 bits
| 21'
|-
| 24 words
| 256 bits
| 24'
|}
====12 English words====
BIP39 English 12 word mnemonic seed
128 bits of entropy as input to BIP39 to derive 12 word mnemonic
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/39'/0'/12'/0'
OUTPUT:
* DERIVED ENTROPY=6250b68daf746d12a24d58b4787a714b
* DERIVED BIP39 MNEMONIC=girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose
====18 English words====
BIP39 English 18 word mnemonic seed
192 bits of entropy as input to BIP39 to derive 18 word mnemonic
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/39'/0'/18'/0'
OUTPUT:
* DERIVED ENTROPY=938033ed8b12698449d4bbca3c853c66b293ea1b1ce9d9dc
* DERIVED BIP39 MNEMONIC=near account window bike charge season chef number sketch tomorrow excuse sniff circle vital hockey outdoor supply token
====24 English words====
Derives 24 word BIP39 mnemonic seed
256 bits of entropy as input to BIP39 to derive 24 word mnemonic
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/39'/0'/24'/0'
OUTPUT:
* DERIVED ENTROPY=ae131e2312cdc61331542efe0d1077bac5ea803adf24b313a4f0e48e9c51f37f
* DERIVED BIP39 MNEMONIC=puppy ocean match cereal symbol another shed magic wrap hammer bulb intact gadget divorce twin tonight reason outdoor destroy simple truth cigar social volcano
===HD-Seed WIF===
Application number: 2'
Uses the most significant 256 bits
There is a very small chance that you'll make an invalid
key that is zero or larger than the order of the curve. If this occurs, software
should hard fail (forcing users to iterate to the next index). From BIP32:
In case parse256(IL) ≥ n or ki = 0, the resulting key is invalid, and one should proceed with the next value for i. (Note: this has probability lower than 1 in 2127.)
of entropy as the secret exponent to derive a private key and encode as a compressed
WIF that will be used as the hdseed for Bitcoin Core wallets.
Path format is m/83696968'/2'/{index}'
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/2'/0'
OUTPUT
* DERIVED ENTROPY=7040bb53104f27367f317558e78a994ada7296c6fde36a364e5baf206e502bb1
* DERIVED WIF=Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp
===XPRV===
Application number: 32'
Taking 64 bytes of the HMAC digest, the first 32 bytes are the chain code, and the second 32 bytes are the private key for the BIP32 XPRV value. Child number, depth, and parent fingerprint are forced to zero.
''Warning'': The above order reverses the order of BIP32, which takes the first 32 bytes as the private key, and the second 32 bytes as the chain code.
Applications may support Testnet by emitting TPRV keys if and only if the input root key is a Testnet key.
Path format is m/83696968'/32'/{index}'
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/32'/0'
OUTPUT
* DERIVED ENTROPY=ead0b33988a616cf6a497f1c169d9e92562604e38305ccd3fc96f2252c177682
* DERIVED XPRV=xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX
===HEX===
Application number: 128169'
The derivation path format is: m/83696968'/128169'/{num_bytes}'/{index}'
`16 <= num_bytes <= 64`
Truncate trailing (least significant) bytes of the entropy after `num_bytes`.
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/128169'/64'/0'
OUTPUT
* DERIVED ENTROPY=492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c
===PWD BASE64===
Application number: 707764'
The derivation path format is: m/83696968'/707764'/{pwd_len}'/{index}'
`20 <= pwd_len <= 86`
[https://datatracker.ietf.org/doc/html/rfc4648 Base64] encode all 64 bytes of entropy.
Remove any spaces or new lines inserted by Base64 encoding process. Slice Base64 result string
on index 0 to `pwd_len`. This slice is the password. As `pwd_len` is limited to 86, passwords will not contain padding.
Entropy calculation:
R = 64 (Base64 - do not count padding)
L = pwd_len
Entropy = log2(R ** L)
{| class="wikitable" style="margin:auto"
! pwd_length !! (cca) entropy
|-
| 20 || 120.0
|-
| 24 || 144.0
|-
| 32 || 192.0
|-
| 64 || 384.0
|-
| 86 || 516.0
|}
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/707764'/21'/0'
OUTPUT
* DERIVED ENTROPY=74a2e87a9ba0cdd549bdd2f9ea880d554c6c355b08ed25088cfa88f3f1c4f74632b652fd4a8f5fda43074c6f6964a3753b08bb5210c8f5e75c07a4c2a20bf6e9
* DERIVED PWD=dKLoepugzdVJvdL56ogNV
===PWD BASE85===
Application number: 707785'
The derivation path format is: m/83696968'/707785'/{pwd_len}'/{index}'
`10 <= pwd_len <= 80`
Base85 encode all 64 bytes of entropy.
Remove any spaces or new lines inserted by Base85 encoding process. Slice Base85 result string
on index 0 to `pwd_len`. This slice is the password. `pwd_len` is limited to 80 characters.
Entropy calculation:
R = 85
L = pwd_len
Entropy = log2(R ** L)
{| class="wikitable" style="margin:auto"
! pwd_length !! (cca) entropy
|-
| 10 || 64.0
|-
| 15 || 96.0
|-
| 20 || 128.0
|-
| 30 || 192.0
|-
| 80 || 512.0
|}
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/707785'/12'/0'
OUTPUT
* DERIVED ENTROPY=f7cfe56f63dca2490f65fcbf9ee63dcd85d18f751b6b5e1c1b8733af6459c904a75e82b4a22efff9b9e69de2144b293aa8714319a054b6cb55826a8e51425209
* DERIVED PWD=_s`{TW89)i4`
===RSA===
Application number: 828365'
The derivation path format is: m/83696968'/828365'/{key_bits}'/{key_index}'
The RSA key generator should use BIP85-DRNG as the input RNG function.
===RSA GPG===
Keys allocated for RSA-GPG purposes use the following scheme:
- Main key m/83696968'/828365'/{key_bits}'/{key_index}'
- Sub keys: m/83696968'/828365'/{key_bits}'/{key_index}'/{sub_key}'
- key_index is the parent key for CERTIFY capability
- sub_key 0' is used as the ENCRYPTION key
- sub_key 1' is used as the AUTHENTICATION key
- sub_key 2' is usually used as SIGNATURE key
Note on timestamps:
The resulting RSA key can be used to create a GPG key where the creation date MUST be fixed to UNIX Epoch timestamp 1231006505 (the Bitcoin genesis block time '2009-01-03 18:15:05' UTC)The human-readable datetime string was incorrectly noted as '2009-01-03 18:05:05' prior to v2.0.0 of this BIP, so implementations that relied on it rather than UNIX Epoch timestamp 1231006505 will produce different key fingerprints. because the key fingerprint is affected by the creation date (Epoch timestamp 0 was not chosen because of legacy behavior in GNUPG implementations for older keys). Additionally, when importing sub-keys under a key in GNUPG, the system time must be frozen to the same timestamp before importing (e.g. by use of faketime).
Note on GPG key capabilities on smartcard/hardware devices:
GPG capable smart-cards SHOULD be loaded as follows: The encryption slot SHOULD be loaded with the ENCRYPTION capable key; the authentication slot SHOULD be loaded with the AUTHENTICATION capable key. The signature capable slot SHOULD be loaded with the SIGNATURE capable key.
However, depending on available slots on the smart-card, and preferred policy, the CERTIFY capable key MAY be flagged with CERTIFY and SIGNATURE capabilities and loaded into the SIGNATURE capable slot (for example where the smart-card has only three slots and the CERTIFY capability is required on the same card). In this case, the SIGNATURE capable sub-key would be disregarded because the CERTIFY capable key serves a dual purpose.
===DICE===
Application number: 89101'
The derivation path format is: m/83696968'/89101'/{sides}'/{rolls}'/{index}'
2 <= sides <= 2^32 - 1
1 <= rolls <= 2^32 - 1
Use this application to generate PIN numbers, numeric secrets, and secrets over custom alphabets.
For example, applications could generate alphanumeric passwords from a 62-sided die (26 + 26 + 10).
Roll values are zero-indexed, such that an N-sided die produces values in the range
[0, N-1], inclusive. Applications should separate printed rolls by a comma or similar.
Create a BIP85 DRNG whose seed is the derived entropy.
Calculate the following integers:
bits_per_roll = ceil(log_2(sides))
bytes_per_roll = ceil(bits_per_roll / 8)
Read bytes_per_roll bytes from the DRNG.
Trim any bits in excess of bits_per_roll (retain the most
significant bits). The resulting integer represents a single roll or trial.
If the trial is greater than or equal to the number of sides, skip it and
move on to the next one. Repeat as needed until all rolls are complete.
INPUT:
* MASTER BIP32 ROOT KEY: xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
* PATH: m/83696968'/89101'/6'/10'/0'
OUTPUT
* DERIVED ENTROPY=5e41f8f5d5d9ac09a20b8a5797a3172b28c806aead00d27e36609e2dd116a59176a738804236586f668da8a51b90c708a4226d7f92259c69f64c51124b6f6cd2
* DERIVED ROLLS=1,0,0,2,0,1,5,5,2,4
==Backwards Compatibility==
This specification is not backwards compatible with any other existing specification.
This specification relies on BIP32 but is agnostic to how the BIP32 root key is derived. As such, this standard is able to derive wallets with initialization schemes like BIP39 or Electrum wallet style mnemonics.
==References==
BIP32, BIP39
==Reference Implementations==
* 1.3.0 Python 3.x library implementation: [https://github.com/akarve/bipsea]
* 1.1.0 Python 2.x library implementation: [https://github.com/ethankosakovsky/bip85]
* 1.0.0 JavaScript library implementation: [https://github.com/hoganri/bip85-js]
==Changelog==
===2.0.0 (2025-09-19)===
====Fixed====
* Fixed the human-readable datetime string for BIP85 GPG Keys that was incorrectly stated as '2009-01-03 18:05:05' rather than '2009-01-03 18:15:05'. Implementations that relied on the previously incorrect datetime string instead of UNIX Epoch timestamp 1231006505 will produce different key fingerprints.
===1.3.0 (2024-10-22)===
====Added====
* Dice application 89101'
* Czech language code to application 39'
* TPRV guidance for application 32'
* Warning on application 32' key and chain code ordering
===1.2.0 (2022-12-04)===
====Added====
* Base64 application 707764'
* Base85 application 707785'
===1.1.0 (2020-11-19)===
====Added====
* BIP85-DRNG-SHAKE256
* RSA application 828365'
===1.0.0 (2020-06-11)===
* Initial version
==Footnotes==
==Acknowledgements==
Many thanks to Peter Gray and Christopher Allen for their input, and to Peter for suggesting extra application use cases.
================================================
FILE: bip-0086.mediawiki
================================================
BIP: 86
Layer: Applications
Title: Key Derivation for Single Key P2TR Outputs
Authors: Ava Chow
Status: Deployed
Type: Specification
Assigned: 2021-06-22
License: BSD-2-Clause
==Abstract==
This document suggests a derivation scheme for HD wallets whose keys are involved in single key
P2TR ([[bip-0341.mediawiki|BIP 341]]) outputs as the Taproot internal key.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
==Motivation==
With the usage of single key P2TR transactions, it is useful to have a common derivation scheme so
that HD wallets that only have a backup of the HD seed can be likely to recover single key Taproot
outputs. Although there are now solutions which obviate the need for fixed derivation paths for
specific script types, many software wallets and hardware signers still use seed backups which
lack derivation path and script information. Thus we largely use the same approach used in BIPs
[[bip-0049.mediawiki|49]] and [[bip-0084.mediawiki|84]] for ease of implementation.
==Specifications==
This BIP defines the two needed steps to derive multiple deterministic addresses based on a
[[bip-0032.mediawiki|BIP 32]] master private key.
===Public key derivation===
To derive a public key from the root account, this BIP uses the same account-structure as
defined in BIPs [[bip-0044.mediawiki|44]], [[bip-0049.mediawiki|49]], and [[bip-0084.mediawiki|84]],
but with a different purpose value for the script type.
For the purpose-path level it uses 86'.
The rest of the levels are used as defined in BIPs 44, 49, and 84.
A key derived with this derivation path pattern will be referred to as derived_key further
in this document.
===Address derivation===
[[bip-0341.mediawiki#cite_ref-22-0|BIP 341]] states: "If the spending conditions do not require a
script path, the output key should commit to an unspendable script path instead of having no
script path. This can be achieved by computing the output key point as
''Q = P + int(hashTapTweak(bytes(P)))G''." Thus:
==Backwards Compatibility==
This BIP is not backwards compatible by design.
An incompatible wallet will not discover these accounts at all and the user will notice that
something is wrong.
However this BIP uses the same method used in BIPs 44, 49, and 84, so it should not be difficult
to implement.
==Test vectors==
==Abstract==
This BIP defines a sane hierarchy for deterministic multisig wallets based on an algorithm described in BIP-0032 (BIP32 from now on), purpose scheme described in BIP-0043 (BIP43 from now on), and multi-account hierarchy described in BIP-0044 (BIP44 from now on).
This BIP is a particular application of BIP43.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
With the increase of more user friendly (offline) multisignature wallets, and adoption of new technologies such as [https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md the descriptor language] and [https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki BIP-0174 (Partially Signed Bitcoin Transactions)], it is necessary to create a common derivation scheme that makes use of all new technologies.
As background, BIP 44/49/84 specifies:
where the BIP43 purpose' path is separate for each script (P2PKH, P2WPKH-in-P2SH, and P2WPKH respectively). Having a script-per-derivation for single sig wallets allows for easy backup and restore, with just the private key information.
Multisignature wallets need more information to backup and restore (such as all cosigner public keys), and these per-script derivations are made redundant with descriptors, which provide that information (while also specifying a collection of output scripts).
A modern standardization is needed for multisig derivation paths. There are some in existence, but all have issues. For example, BIP45 specifies:
m / purpose' / cosigner_index / change / address_index
BIP45 unnecessarily demands a single script type (here, P2SH). In addition, BIP45 sets cosigner_index in order to sort the purpose' public keys of each cosigner. This too is redundant, as descriptors can set the order of the public keys with multi or have them sorted lexicographically (as described in [https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki BIP67]) with sortedmulti. Sorting public keys between cosigners in order to create the full derivation path, prior to sending the key record to the coordinator to create the descriptor, merely adds additional unnecessary communication rounds.
The second multisignature "standard" in use is m/48', which specifies:
Rather than following in BIP 44/49/84's path and having a separate BIP per script after P2SH (BIP45), vendors decided to insert script_type' into the derivation path (where P2SH-P2WSH=1, P2WSH=2, Future_Script=3, etc). As described previously, this is unnecessary, as the descriptor sets the script. While it attempts to reduce maintenance work by getting rid of new BIPs-per-script, it still requires maintaining an updated, redundant, script_type list.
The structure proposed later in this paper solves these issues and is quite comprehensive. It allows for the handling of multiple accounts, external and internal chains per account, and millions of addresses per chain, in a multi-party, multisignature, hierarchical deterministic wallet regardless of the script type '''Why propose this structure only for multisignature wallets?''' Currently, single-sig wallets are able to restore funds using just the master private key data (in the format of BIP39 usually). Even if the user doesn't recall the derivation used, the wallet implementation can iterate through common schemes (BIP44/49/84). With this proposed hierarchy, the user would either have to now backup additional data (the descriptor), or the wallet would have to attempt all script types for every account level when restoring. Because of this, even though the descriptor language handles the signature type just like it does the script type, it is best to restrict this script-agnostic hierarchy to multisignature wallets only..
This paper was inspired from BIP44.
==Specification==
===Key sorting===
Any wallet that supports descriptors inherently supports deterministic key sorting as per BIP67 (through the sortedmulti function) so that all possible multisignature addresses/scripts are derived from deterministically sorted public keys.
===Path levels===
We should not be mixing keys and scripts in the same layer. The wallet should create extended private/public keys independent of the script type, whereas the descriptor language tells wallets to watch the multisig outputs with the specified public keys.
We define the following 5 levels in the BIP32 path:
h or ' in the path indicates that BIP32 hardened derivation is used.
Each level has a special meaning, described in the chapters below.
===Purpose===
Purpose is a constant set to 87' following the BIP43 recommendation.
It indicates that the subtree of this node is used according to this specification.
Hardened derivation is used at this level.
===Coin type===
One master node (seed) can be used for multiple Bitcoin networks.
Sharing the same space for various networks has some disadvantages.
This level creates a separate subtree for every network, avoiding reusing addresses across networks and improving privacy issues.
Coin type 0 for mainnet and 1 for testnets (testnet, regtest, and signet).
Hardened derivation is used at this level.
===Account===
This level splits the key space into independent user identities, following the BIP44 pattern, so the wallet never mixes the coins across different accounts.
Users can use these accounts to organize the funds in the same fashion as bank accounts; for donation purposes (where all addresses are considered public), for saving purposes, for common expenses, etc.
Accounts are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Hardened derivation is used at this level.
It is crucial that this level is increased for each new wallet joined or private/public keys created; for both privacy and cryptographic purposes.
For example, before sending a new key record to a coordinator, the wallet must increment the account' level.
This prevents key reuse - across ECDSA and Schnorr signatures, across different script types, and in between the same wallet types.
===Change===
Constant 0 is used for external chain and constant 1 for internal chain (also known as change addresses). External chain is used for addresses that are meant to be visible outside of the wallet (e.g. for receiving payments). Internal chain is used for addresses which are not meant to be visible outside of the wallet and is used for return transaction change.
Public derivation is used at this level.
===Index===
Addresses are numbered from index 0 in sequentially increasing manner.
This number is used as child index in BIP32 derivation.
Public derivation is used at this level.
==Address Discovery==
The multisig descriptors or descriptor template that is generated from the cosigners' combined key records should be used to generate and discover addresses.
Please see [https://github.com/bitcoin/bips/blob/master/bip-0129.mediawiki BIP-0129 (Bitcoin Secure Multisig Setup)] for an introduction on descriptor templates.
The descriptor or descriptor template should contain the key origin information for maximum compatibility with BIP-0174.
For example:
The following descriptor template and derivation path restrictions:
wsh(sortedmulti(2,[xfpForA/87'/0'/0']XpubA/**,[xfpForB/87'/0'/0']XpubB/**))/0/*,/1/*
Expands to the two concrete descriptors:
wsh(sortedmulti(2,[xfpForA/87'/0'/0']XpubA/0/*,[xfpForB/87'/0'/0']XpubB/0/*))wsh(sortedmulti(2,[xfpForA/87'/0'/0']XpubA/1/*,[xfpForB/87'/0'/0']XpubB/1/*))
To discover addresses, import both the receiving and change descriptors; respect the gap limit described below.
===Address Gap Limit===
Address gap limit is currently set to 20. If the software hits 20 unused addresses in a row, it expects there are no used addresses beyond this point and stops searching the address chain.
Wallet software should warn when the user is trying to exceed the gap limit on an external descriptor by generating multiple unused addresses.
==Backwards Compatibility==
Any script that is supported by descriptors (and the specific wallet implementation) is compatible with this BIP.
As wallets complying with this BIP are descriptor wallets, this therefore necessitates that the cosigners backup their private key information and the descriptor, in order to properly restore at a later time. This shouldn't be a user burden, since (to much user surprise), all cosigner public keys need to be supplied in addition to M seeds in any M of N multisig restore operation. The descriptor provides this information in a standardized format, with key origin information and error detection.
==Rationale==
==Examples==
{|
|network
|account
|chain
|address
|path
|-
|mainnet
|first
|external
|first
|m / 87' / 0' / 0' / 0 / 0
|-
|mainnet
|first
|external
|second
|m / 87' / 0' / 0' / 0 / 1
|-
|mainnet
|first
|change
|first
|m / 87' / 0' / 0' / 1 / 0
|-
|mainnet
|first
|change
|second
|m / 87' / 0' / 0' / 1 / 1
|-
|mainnet
|second
|external
|first
|m / 87' / 0' / 1' / 0 / 0
|-
|mainnet
|second
|external
|second
|m / 87' / 0' / 1' / 0 / 1
|-
|testnet
|first
|external
|first
|m / 87' / 1' / 0' / 0 / 0
|-
|testnet
|first
|external
|second
|m / 87' / 1' / 0' / 0 / 1
|-
|testnet
|first
|change
|first
|m / 87' / 1' / 0' / 1 / 0
|-
|testnet
|first
|change
|second
|m / 87' / 1' / 0' / 1 / 1
|-
|testnet
|second
|external
|first
|m / 87' / 1' / 1' / 0 / 0
|-
|testnet
|second
|external
|second
|m / 87' / 1' / 1' / 0 / 1
|-
|testnet
|second
|change
|first
|m / 87' / 1' / 1' / 1 / 0
|-
|testnet
|second
|change
|second
|m / 87' / 1' / 1' / 1 / 1
|}
==Reference Implementation==
None at the moment.
==Acknowledgement==
Special thanks to SomberNight, Craig Raw, David Harding, Jochen Hoenicke, Sjors Provoost, and others for their feedback on the specification.
==References==
Original mailing list thread: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-March/018630.html
* [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-0032 (Hierarchical Deterministic Wallets)]
* [https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki BIP-0043 (Purpose Field for Deterministic Wallets)]
* [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP-0044 (Multi-Account Hierarchy for Deterministic Wallets)]
* [https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md Output Descriptors]
* [https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki BIP-0174 (Partially Signed Bitcoin Transaction Format)]
* [https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki BIP-0067 (Deterministic Pay-to-script-hash multi-signature addresses through public key sorting)]
* [https://github.com/bitcoin/bips/blob/master/bip-0129.mediawiki BIP-0129 (Bitcoin Secure Multisig Setup)]
================================================
FILE: bip-0088.mediawiki
================================================
==Abstract==
This document describes a format for the representation of the templates that specify
the constraints that can be imposed on BIP32 derivation paths.
The constraints specified by the templates allow to easily discern 'valid' paths,
that match the constraints, and 'invalid' paths, that exceed the constraints.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
BIP32 derivation path format is universal, and a number of schemes for derivation were proposed
in BIP43 and other documents, such as BIPs 44,45,49,84. The flexibility of the format also allowed
industry participants to implement custom derivation schemes that fit particular purposes,
but not necessarily useful in general.
Even when existing BIPs for derivation schemes are used, their usage is not uniform across
the different wallets, in part because software vendors might have different considerations
and priorities when making decisions about derivation paths. This creates friction for users,
which might face problems when they try to access their coins using the wallet that derives
addresses differently than the one they used before.
===Known solutions===
The problem is common enough to warrant the creation of a dedicated website
([https://walletsrecovery.org/ walletsrecovery.org]) that tracks paths used by different wallets.
At the time of writing, this website has used their own format to succinctly describe multiple
derivation paths. As far as author knows, it was the only publicly used format to describe
path templates before introduction of this BIP. The format was not specified anywhere beside
the main page of the website. It used | to denote alternative derivation indexes
(example: m/|44'|49'|84'/0'/0') or whole alternative paths (m/44'/0'/0'|m/44'/1'/0').
It was not declared as a template format to use for processing by software, and seems to be
an ad-hoc format only intended for illustration. In contrast to this ad-hoc format, the format
described in this BIP is intended for unambiguous parsing by software, and to be easily read by humans
at the same time. Humans can visually detect the 'templated' parts of the path more easily than the use
of | in the template could allow. Wider range of paths can be defined in a single template more
succinctly and unambiguously.
===Intended use and advantages===
Wallet software authors can use the proposed format to describe the derivation paths that
their software uses. This can improve user experience when switching to different wallet
software, restoring access to old wallets, etc.
Unrestricted derivation path usage might be unsafe in certain contexts. In particular, when "change"
outputs of a transaction are sent to the addresses derived via paths unknown to the sender, the sender
might lose access to the whole change amount.
A simplistic approach of hard-coding the checks for well-known paths into software and firmware leads
to reduced interoperability. Vendors cannot choose custom paths that are appropriate for
their particular, non-general-purpose applications, and are forced to shoehorn their solutions
into using well-known paths, or convince other vendors to support their custom paths. This approach
scales poorly.
A flexible approach proposed in this document is to define a standard notation for "BIP32 path templates"
that succinctly describes the constraints to impose on the derivation path.
Wide support for these path templates will increase interoperability and flexibility of solutions,
and will allow vendors and individual developers to easily define their own custom restrictions.
This way, they will be able to deal with the risks of accidental or malicious use of unrestricted
derivation paths in a more flexible and precise manner.
Well-known path templates can be pre-configured by default on devices and applications,
but users can have an option to turn off the templates that are not relevant to their uses.
Having a standardized format for custom path templates will enable a common approach to be developed
in the enforcement of application-specific path restrictions in devices and applications.
One example of such an approach might be for devices to allow application-specific profiles
with path templates and possibly other custom parameters. Care must be taken to prevent the accidental
installation of malicious or incorrect profiles, though.
==Specification==
The format for the template was chosen to make it easy to read, convenient and visually unambiguous.
Template starts with optional prefix m/, and then one or more sections delimited by the slash character (/).
Implementations MAY limit the maximum number of sections.
Each section consists of ''index template'', optionally followed by the hardened marker: either an apostrophe (') or letter h.
Index template can be:
* An integer value from 0 to 2147483647 ("Unit index template")
* A single * character, which denotes any value from 0 to 2147483647 ("Wildcard index template")
* The { character, followed by a number of ''index ranges'' delimited by commas (,), followed by } character ("Ranged index template")
Implementations MAY limit the maximum number of index ranges within the Ranged index template.
If an index template is immediately followed by hardened marker, this means that all values specified in this index template is to be increased by 2147483648 for the purposes of matching.
Index range can be:
* An integer value from 0 to 2147483647 ("Unit range")
* An integer value from 0 to 2147483647, followed by the - character, followed by another integer value from 0 to 2147483647 ("Non-unit range")
For Non-unit range, value on the left side of the - character is the range_start, and the value on the right side of the - character is the range_end.
For Unit range, we say that range_start is equal to range_end, even though there is no start/end in the Unit range.
Unit index template contains a single index range, which is the Unit range
Wildcard index template contains a single index range, and we say that its range_start is set to 0 and its range_end is set to 2147483647
Constraints:
# To avoid ambiguity, whitespace MUST NOT appear within the path template.
# Commas within the Ranged index template MUST only appear in between index ranges.
# To avoid ambiguity, an index range that matches a single value MUST be specified as Unit range.
# To avoid ambiguity, an index range 0-2147483647 is not allowed, and MUST be specified as Wildcard index template instead
# For Non-unit range, range_end MUST be larger than range_start.
# If there is more than one index range within the Ranged index template, range_start of the second and any subsequent range MUST be larger than the range_end of the preceding range.
# To avoid ambiguity, all representations of integer values larger than 0 MUST NOT start with character 0 (no leading zeroes allowed).
# If hardened marker appears within any section in the path template, all preceding sections MUST also specify hardened matching.
# To avoid ambiguity, if a hardened marker appears within any section in the path template, all preceding sections MUST also use the same hardened marker (either h or ').
# To avoid ambiguity, trailing slashes (for example, 1/2/) and duplicate slashes (for example, 0//1) MUST NOT appear in the template.
It may be desirable to have fully unambiguous encoding, where for each valid path template string, there is no other valid template string that matches the exact same set of paths. This would enable someone to compare templates for equality through a simple string equality check, without any parsing.
To achieve this, two extra rules are needed:
* Within Ranged index template, subsequent range MUST NOT start with the value that is equal to the end of the previous range plus one. Thus, {1,2,3-5} is not allowed, and should be specified as {1-5} instead. This rule might make templates less convenient for frequent edits, though.
* Only one type of hardened marker should be allowed (either h or ').
Instead of requiring the second extra rule, implementations can simply replace one type of marker with another in the template strings before comparing them.
==Full and partial templates==
If the template starts with m/, that means that this is the "full" template, that matches the whole path.
If the template does not start with m/, that means that this is a "partial" template, and it can be used to match a part of the path, in the contexts where this might be appropriate (for example, when constraints for the suffix of the path might be dynamic, while constraints for the prefix of the path are fixed).
Full template can be combined with partial template, where partial template extends full template,
resulting in new, longer full template.
Partial template can be combined with another partial template, resulting in new, longer partial template.
Full template can not be combined with another full template.
Implementations MUST support parsing full templates and matching paths against full templates.
Implementations MAY support parsing partial templates and matching portions of the paths against partial templates, as well as combining the templates.
==Parsing result==
The result of successful parsing of a valid path template can be represented by a list of sections, where each section is a list of index ranges, where index range is a tuple of (range_start, range_end). The length of the list of sections is also referred to as the "length of the template".
==Matching==
The matching is to be performed against a list of integer values that represent a BIP32 path (or a portion of BIP32 path, for partial templates). The length of this list is referred to as the "length of the path".
Non-hardened indexes in this list should be represented by values from 0 to 2147483647.
Hardened indexes in this list should be represented by values from 2147483648 to 4294967295.
The matching algorithm:
1. If the length of the path differs from the length of the template, fail
2. For each value V at position N in the path:
If for all index ranges within the section at position N in the template,
value V is either less than range_start, or greater than range_end, fail
3. Otherwise, succeed
==Formal specification==
The finite state machine (FSM) for the parser of the described template format,
and the matching formula are specified in TLA+ specification language at https://github.com/dgpv/bip32_template_parse_tplaplus_spec
The specification can be used with TLC checker and accompanying script to generate test data for the implementations.
==Implementations==
While the formal specification specifies an FSM, which would be convenient for implementation without access to rich string handling facilities, when such facilities are available, the implementation might use the whole-string deconstruction approach where the templates are first split into sections, then sections are split into index templates, and then each index template are parsed individually.
A FSM-based approach can be made close to the formal specification, though, and the test data generated with TLC checker would give much better coverage for a FSM based implementation. If the template string contains several errors, an implementation that uses deconstruction approach might detect some of these errors earlier than FSM-based implementation, and vise versa.
At the moment, three implementations exist:
* FSM implementation in C: https://github.com/dgpv/bip32_template_c_implementation
* FSM implementation in Python (micropython compatible): https://github.com/dgpv/bip32_template_python_implementation
* non-FSM implementation in python: BIP32PathTemplate class in bitcointx.core.key module of python-bitcointx library (https://github.com/Simplexum/python-bitcointx)
==Compatibility==
The full path template that only contains Unit index templates represents a fully valid BIP32 path.
There's no other path template standards that is known to the author currently.
There is a discussion on path templating for bitcoin script descriptors at https://github.com/bitcoin/bitcoin/issues/17190, which proposes the format xpub...{0,1}/*, of which the {0,1}/* part would correspond to the partial path template in the format of this BIP.
==Examples==
m/{44,49,84}'/0'/0'/{0-1}/{0-50000} specifies a full template that matches both external and internal chains of BIP44, BIP49 and BIP84 paths, with a constraint that the address index cannot be larger than 50000
Its representation after parsing can be (using Python syntax, ignoring full/partial distinction):
[[(2147483692, 2147483692), (2147483697, 2147483697), (2147483732, 2147483732)],
[(2147483648, 2147483648)],
[(2147483648, 2147483648)],
[(0, 1)],
[(0, 50000)]]
{0-2,33,123}/* specifies a partial template that matches non-hardened values 0, 1, 2, 33, 123 as first index, and any non-hardened value at second index
Its representation after parsing can be:
[[(0, 2), (33, 33), (123, 123)], [(0, 2147483647)]]
*h/0 specifies a partial template that matches any hardened index followed by non-hardened index 0
Its representation after parsing can be:
[[(2147483648, 4294967295)], [(0, 0)]]
==Acknowledgements==
Special thanks to Peter D. Gray, Dr. Maxim Orlovsky, Robert Spigler and others for their feedback on the specification, and to Janine (github:@Enegnei) for the help in preparing the draft.
================================================
FILE: bip-0089/bip32.py
================================================
"""BIP32 helpers for the CCD reference implementation."""
from __future__ import annotations
from dataclasses import dataclass
import hmac
from hashlib import new as hashlib_new, sha256, sha512
from typing import List, Tuple, Mapping, Sequence
from secp256k1lab.secp256k1 import G, GE, Scalar
CURVE_N = Scalar.SIZE
def int_to_bytes(value: int, length: int) -> bytes:
return value.to_bytes(length, "big")
def bytes_to_int(data: bytes) -> int:
return int.from_bytes(data, "big")
def compress_point(point: GE) -> bytes:
if point.infinity:
raise ValueError("Cannot compress point at infinity")
return point.to_bytes_compressed()
def decompress_point(data: bytes) -> GE:
return GE.from_bytes_compressed(data)
def apply_tweak_to_public(base_public: bytes, tweak: int) -> bytes:
base_point = GE.from_bytes_compressed(base_public)
tweaked_point = base_point + (tweak % CURVE_N) * G
if tweaked_point.infinity:
raise ValueError("Tweaked key is at infinity")
return tweaked_point.to_bytes_compressed()
def apply_tweak_to_secret(base_secret: int, tweak: int) -> int:
if not (0 < base_secret < CURVE_N):
raise ValueError("Invalid base secret scalar")
return (base_secret + tweak) % CURVE_N
def decode_path(path_elements: Sequence[object]) -> List[int]:
result: List[int] = []
for element in path_elements:
if isinstance(element, int):
index = element
else:
element_str = str(element)
hardened = element_str.endswith("'") or element_str.endswith("h")
suffix = element_str[:-1] if hardened else element_str
if not suffix:
raise AssertionError("invalid derivation index")
index = int(suffix)
if hardened:
index |= HARDENED_INDEX
result.append(index)
return result
HARDENED_INDEX = 0x80000000
def _hash160(data: bytes) -> bytes:
return hashlib_new("ripemd160", sha256(data).digest()).digest()
@dataclass
class ExtendedPublicKey:
point: GE
chain_code: bytes
depth: int = 0
parent_fingerprint: bytes = b"\x00\x00\x00\x00"
child_number: int = 0
def fingerprint(self) -> bytes:
return _hash160(compress_point(self.point))[:4]
def derive_child(self, index: int) -> Tuple[int, "ExtendedPublicKey"]:
tweak, child_point, child_chain = derive_public_child(self.point, self.chain_code, index)
child = ExtendedPublicKey(
point=child_point,
chain_code=child_chain,
depth=self.depth + 1,
parent_fingerprint=self.fingerprint(),
child_number=index,
)
return tweak, child
def derive_public_child(parent_point: GE, chain_code: bytes, index: int) -> Tuple[int, GE, bytes]:
if index >= HARDENED_INDEX:
raise ValueError("Hardened derivations are not supported for delegates")
data = compress_point(parent_point) + int_to_bytes(index, 4)
il_ir = hmac.new(chain_code, data, sha512).digest()
il, ir = il_ir[:32], il_ir[32:]
tweak = bytes_to_int(il)
if tweak >= CURVE_N:
raise ValueError("Invalid tweak derived (>= curve order)")
child_point_bytes = apply_tweak_to_public(compress_point(parent_point), tweak)
child_point = decompress_point(child_point_bytes)
return tweak, child_point, ir
def parse_path(path: str) -> List[int]:
if not path or path in {"m", "M"}:
return []
if path.startswith(("m/", "M/")):
path = path[2:]
components: List[int] = []
for element in path.split("/"):
if element.endswith("'") or element.endswith("h"):
raise ValueError("Hardened steps are not allowed in CCD derivations")
index = int(element)
if index < 0 or index >= HARDENED_INDEX:
raise ValueError("Derivation index out of range")
components.append(index)
return components
def parse_extended_public_key(data: Mapping[str, object]) -> ExtendedPublicKey:
compressed_hex = data.get("compressed")
if not isinstance(compressed_hex, str):
raise ValueError("Compressed must be a string")
chain_code_hex = data.get("chain_code")
if not isinstance(chain_code_hex, str):
raise ValueError("Chain code must be a string")
depth = data.get("depth")
if not isinstance(depth, int):
raise ValueError("Depth must be an integer")
child_number = data.get("child_number", 0)
if not isinstance(child_number, int):
raise ValueError("Child number must be an integer")
parent_fp_hex = data.get("parent_fingerprint", "00000000")
compressed = bytes.fromhex(compressed_hex)
chain_code = bytes.fromhex(chain_code_hex)
parent_fp = bytes.fromhex(str(parent_fp_hex))
return build_extended_public_key(
compressed,
chain_code,
depth=depth,
parent_fingerprint=parent_fp,
child_number=child_number,
)
def build_extended_public_key(
compressed: bytes,
chain_code: bytes,
*,
depth: int = 0,
parent_fingerprint: bytes = b"\x00\x00\x00\x00",
child_number: int = 0,
) -> ExtendedPublicKey:
if len(chain_code) != 32:
raise ValueError("Chain code must be 32 bytes")
point = decompress_point(compressed)
return ExtendedPublicKey(
point=point,
chain_code=chain_code,
depth=depth,
parent_fingerprint=parent_fingerprint,
child_number=child_number,
)
================================================
FILE: bip-0089/descriptor.py
================================================
"""Helpers for working with minimal SortedMulti descriptor templates."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Sequence
@dataclass(frozen=True)
class SortedMultiDescriptorTemplate:
"""Minimal representation of a ``wsh(sortedmulti(m, ...))`` descriptor."""
threshold: int
def witness_script(self, tweaked_keys: Sequence[bytes]) -> bytes:
"""Return the witness script for ``wsh(sortedmulti(threshold, tweaked_keys))``."""
if not tweaked_keys:
raise ValueError("sortedmulti requires at least one key")
if not 1 <= self.threshold <= len(tweaked_keys):
raise ValueError("threshold must satisfy 1 <= m <= n")
for key in tweaked_keys:
if len(key) != 33:
raise ValueError("sortedmulti keys must be 33-byte compressed pubkeys")
sorted_keys = sorted(tweaked_keys)
script = bytearray()
script.append(_op_n(self.threshold))
for key in sorted_keys:
script.append(len(key))
script.extend(key)
script.append(_op_n(len(sorted_keys)))
script.append(0xAE) # OP_CHECKMULTISIG
return bytes(script)
def _op_n(value: int) -> int:
if not 0 <= value <= 16:
raise ValueError("OP_N value out of range")
if value == 0:
return 0x00
return 0x50 + value
================================================
FILE: bip-0089/reference.py
================================================
# BIPXXX reference implementation
#
# WARNING: This implementation is for demonstration purposes only and _not_ to
# be used in production environments. The code is vulnerable to timing attacks,
# for example.
from typing import Dict, Mapping, Optional, Sequence, Tuple, NewType, NamedTuple, List, Callable, Any, cast
import hashlib
import json
import os
import secrets
import sys
from bip32 import (
CURVE_N,
ExtendedPublicKey,
apply_tweak_to_public,
apply_tweak_to_secret,
int_to_bytes,
parse_extended_public_key,
compress_point,
decode_path,
)
from descriptor import SortedMultiDescriptorTemplate
from secp256k1lab.bip340 import schnorr_sign, schnorr_verify
from secp256k1lab.keys import pubkey_gen_plain
from secp256k1lab.secp256k1 import G, GE, Scalar
HashFunc = Callable[[bytes], Any]
PlainPk = NewType('PlainPk', bytes)
XonlyPk = NewType('XonlyPk', bytes)
def xbytes(P: GE) -> bytes:
return P.to_bytes_xonly()
def cbytes(P: GE) -> bytes:
return P.to_bytes_compressed()
def cpoint(x: bytes) -> GE:
return GE.from_bytes_compressed(x)
TweakContext = NamedTuple('TweakContext', [('Q', GE),
('gacc', Scalar),
('tacc', Scalar)])
def tweak_ctx_init(pk: PlainPk) -> TweakContext:
Q = cpoint(pk)
if Q.infinity:
raise ValueError('The public key cannot be infinity.')
gacc = Scalar(1)
tacc = Scalar(0)
return TweakContext(Q, gacc, tacc)
def apply_tweak(tweak_ctx: TweakContext, tweak: bytes, is_xonly: bool) -> TweakContext:
if len(tweak) != 32:
raise ValueError('The tweak must be a 32-byte array.')
Q, gacc, tacc = tweak_ctx
if is_xonly and not Q.has_even_y():
g = Scalar(-1)
else:
g = Scalar(1)
try:
t = Scalar.from_bytes_checked(tweak)
except ValueError:
raise ValueError('The tweak must be less than n.')
Q_ = g * Q + t * G
if Q_.infinity:
raise ValueError('The result of tweaking cannot be infinity.')
gacc_ = g * gacc
tacc_ = t + g * tacc
return TweakContext(Q_, gacc_, tacc_)
# Return the plain public key corresponding to a given secret key
def individual_pk(seckey: bytes) -> PlainPk:
return PlainPk(pubkey_gen_plain(seckey))
def bytes_xor(a: bytes, b: bytes) -> bytes:
return bytes(x ^ y for x, y in zip(a, b))
# This implementation can be sped up by storing the midstate after hashing
# tag_hash instead of rehashing it all the time.
def tagged_hash(tag: str, msg: bytes, hash_func: HashFunc = hashlib.sha256) -> bytes:
tag_hash = hash_func(tag.encode()).digest()
return hash_func(tag_hash + tag_hash + msg).digest()
def nonce_hash(rand: bytes, pk: PlainPk, extra_in: bytes) -> bytes:
buf = b''
buf += rand
buf += len(pk).to_bytes(1, 'big')
buf += pk
buf += len(extra_in).to_bytes(4, 'big')
buf += extra_in
return tagged_hash('CCD/blindnonce', buf)
def blind_nonce_gen_internal(rand_: bytes, sk: Optional[bytes], pk: Optional[PlainPk], extra_in: Optional[bytes]) -> Tuple[bytearray, bytes]:
if sk is not None:
rand = bytes_xor(sk, tagged_hash('CCD/aux', rand_))
else:
rand = rand_
if pk is None:
pk = PlainPk(b'')
if extra_in is None:
extra_in = b''
k = Scalar.from_bytes_wrapping(nonce_hash(rand, pk, extra_in))
# k == 0 cannot occur except with negligible probability.
assert k != 0
R = k * G
assert R is not None
blindpubnonce = cbytes(R)
blindsecnonce = bytearray(k.to_bytes() + pk)
return blindsecnonce, blindpubnonce
def blind_nonce_gen(sk: Optional[bytes], pk: Optional[PlainPk], extra_in: Optional[bytes]) -> Tuple[bytearray, bytes]:
if sk is not None and len(sk) != 32:
raise ValueError('The optional byte array sk must have length 32.')
rand_ = secrets.token_bytes(32)
return blind_nonce_gen_internal(rand_, sk, pk, extra_in)
SessionContext = NamedTuple('SessionContext', [('pk', PlainPk),
('blindfactor', bytes),
('challenge', bytes),
('pubnonce', bytes),
('tweaks', List[bytes]),
('is_xonly', List[bool])])
def blind_factor_hash(rand: bytes, cpk: PlainPk, blindpubnonce: bytes, msg: bytes, extra_in: bytes) -> bytes:
buf = b''
buf += rand
buf += len(cpk).to_bytes(1, 'big')
buf += cpk
buf += len(blindpubnonce).to_bytes(1, 'big')
buf += blindpubnonce
buf += len(msg).to_bytes(8, 'big')
buf += msg
buf += len(extra_in).to_bytes(4, 'big')
buf += extra_in
return tagged_hash('CCD/blindfactor', buf, hashlib.sha512)
def blind_challenge_gen_internal(rand: bytes, msg: bytes, blindpubnonce: bytes, pk: PlainPk, tweaks: List[bytes], is_xonly: List[bool], extra_in: Optional[bytes]) -> Tuple[SessionContext, bytes, bool, bool]:
if extra_in is None:
extra_in = b''
Q, gacc, tacc = pubkey_and_tweak(pk, tweaks, is_xonly)
cpk = PlainPk(cbytes(Q))
k = blind_factor_hash(rand, cpk, blindpubnonce, msg, extra_in)
a_ = Scalar.from_bytes_wrapping(k[0:32])
assert a_ != 0
b_ = Scalar.from_bytes_wrapping(k[32:64])
assert b_ != 0
g = Scalar(1) if Q.has_even_y() else Scalar(-1)
pk_parity = g * gacc == 1
X_ = cpoint(pk)
X = X_ if pk_parity else -X_
R_ = cpoint(blindpubnonce)
R = R_ + (a_ * G) + (b_ * X)
if R is None:
raise ValueError('The result of nonce blinding cannot be infinity.')
nonce_parity = R.has_even_y()
if not nonce_parity:
a = -a_
b = -b_
else:
a = a_
b = b_
e = Scalar.from_bytes_wrapping(tagged_hash("BIP0340/challenge", xbytes(R) + xbytes(Q) + msg))
e_ = e + b
session_ctx = SessionContext(pk, a.to_bytes(), e.to_bytes(), cbytes(R), tweaks, is_xonly)
return session_ctx, e_.to_bytes(), pk_parity, nonce_parity
def blind_challenge_gen(msg: bytes, blindpubnonce: bytes, pk: PlainPk, tweaks: List[bytes], is_xonly: List[bool], extra_in: Optional[bytes]) -> Tuple[SessionContext, bytes, bool, bool]:
rand = secrets.token_bytes(32)
return blind_challenge_gen_internal(rand, msg, blindpubnonce, pk, tweaks, is_xonly, extra_in)
def blind_sign(sk: bytes, blindchallenge: bytes, blindsecnonce: bytearray, pk_parity: bool, nonce_parity: bool) -> bytes:
try:
d_ = Scalar.from_bytes_checked(sk)
if d_ == 0:
raise ValueError('The secret key cannot be zero.')
except ValueError:
raise ValueError('The secret key is out of range.')
P = d_ * G
if P.infinity:
raise ValueError('The public key cannot be infinity.')
d = d_ if pk_parity else -d_
e_ = Scalar.from_bytes_checked(blindchallenge)
k_ = Scalar.from_bytes_checked(bytes(blindsecnonce[0:32]))
k = k_ if nonce_parity else -k_
# Overwrite the secnonce argument with zeros such that subsequent calls of
# sign with the same secnonce raise a ValueError.
blindsecnonce[:64] = bytearray(b'\x00'*64)
R_ = k_ * G
if R_.infinity:
raise ValueError('The blindpubnonce cannot be infinity.')
s_ = k + (e_ * d)
pk = PlainPk(cbytes(P))
blindsignature = s_.to_bytes()
assert verify_blind_signature(pk, cbytes(R_), blindchallenge, blindsignature, pk_parity, nonce_parity)
return blindsignature
def verify_blind_signature(pk: PlainPk, blindpubnonce: bytes, blindchallenge: bytes, blindsignature: bytes, pk_parity: bool, nonce_parity: bool) -> bool:
P_ = cpoint(pk)
P = P_ if pk_parity else -P_
if P.infinity:
raise ValueError('The public key cannot be infinity.')
R_ = cpoint(blindpubnonce)
R = R_ if nonce_parity else -R_
e_ = Scalar.from_bytes_checked(blindchallenge)
s_ = Scalar.from_bytes_checked(blindsignature)
R_calc = (s_ * G) + (-e_ * P)
if R_calc.infinity:
return False
return R == R_calc
def pubkey_and_tweak(pk: PlainPk, tweaks: List[bytes], is_xonly: List[bool]) -> TweakContext:
if len(tweaks) != len(is_xonly):
raise ValueError('The tweaks and is_xonly arrays must have the same length.')
tweak_ctx = tweak_ctx_init(pk)
v = len(tweaks)
for i in range(v):
tweak_ctx = apply_tweak(tweak_ctx, tweaks[i], is_xonly[i])
return tweak_ctx
def get_session_values(session_ctx: SessionContext) -> Tuple[GE, Scalar, Scalar, GE, Scalar, Scalar]:
(pk, blindfactor, challenge, pubnonce, tweaks, is_xonly) = session_ctx
Q, gacc, tacc = pubkey_and_tweak(pk, tweaks, is_xonly)
a = Scalar.from_bytes_checked(blindfactor)
e = Scalar.from_bytes_checked(challenge)
R = cpoint(pubnonce)
return Q, a, e, R, gacc, tacc
def unblind_signature(session_ctx: SessionContext, blindsignature: bytes) -> bytes:
Q, a, e, R, gacc, tacc = get_session_values(session_ctx)
s_ = Scalar.from_bytes_checked(blindsignature)
g = Scalar(1) if Q.has_even_y() else Scalar(-1)
s = s_ + a + (e * g * tacc)
return xbytes(R) + s.to_bytes()
#
# The following code is only used for testing.
#
def hx(s: str) -> bytes:
return bytes.fromhex(s)
def fromhex_all(l): # noqa: E741
return [hx(l_i) for l_i in l]
def get_error_details(tc):
et = tc["error"]["type"]
# Resolve to real class from name
exc_cls = getattr(__builtins__, et, None) or getattr(__import__("builtins"), et)
# Optional message predicate
msg = tc["error"].get("message")
if msg is None:
return exc_cls, (lambda e: True)
return exc_cls, (lambda e: msg in str(e))
def assert_raises(exc_cls, fn, pred):
try:
fn()
except Exception as e:
assert isinstance(e, exc_cls), f"Raised {type(e).__name__}, expected {exc_cls.__name__}"
assert pred(e), f"Exception message predicate failed: {e}"
return
assert False, f"Expected {exc_cls.__name__} but no exception was raised"
def build_session_ctx(obj):
pk = PlainPk(bytes.fromhex(obj["pk"]))
a = bytes.fromhex(obj["blindfactor"])
e = bytes.fromhex(obj["challenge"])
R = bytes.fromhex(obj["pubnonce"])
tweaks = fromhex_all(obj["tweaks"])
is_xonly = obj["is_xonly"]
return (pk, a, e, R, tweaks, is_xonly)
def test_blind_nonce_gen_vectors():
with open(os.path.join(sys.path[0], 'vectors', 'blind_nonce_gen_vectors.json')) as f:
tv = json.load(f)
for tc in tv["test_cases"]:
def get_bytes(key) -> bytes:
return bytes.fromhex(tc[key])
def get_bytes_maybe(key) -> Optional[bytes]:
v = tc.get(key)
return None if v is None else bytes.fromhex(v)
rand_ = get_bytes("rand_")
sk = get_bytes_maybe("sk")
pk = get_bytes_maybe("pk")
if pk is not None:
pk = PlainPk(pk)
extra_in = get_bytes_maybe("extra_in")
expected_blindsecnonce = get_bytes("expected_blindsecnonce")
expected_blindpubnonce = get_bytes("expected_blindpubnonce")
blindsecnonce, blindpubnonce = blind_nonce_gen_internal(rand_, sk, pk, extra_in)
assert bytes(blindsecnonce) == expected_blindsecnonce
assert blindpubnonce == expected_blindpubnonce
pk_len = 0 if tc["pk"] is None else 33
assert len(expected_blindsecnonce) == 32 + pk_len
assert len(expected_blindpubnonce) == 33
def test_blind_challenge_gen_vectors():
with open(os.path.join(sys.path[0], 'vectors', 'blind_challenge_gen_vectors.json')) as f:
tv = json.load(f)
# ---------- Valid cases ----------
for tc in tv["test_cases"]:
rand = bytes.fromhex(tc["rand"])
msg = bytes.fromhex(tc["msg"]) if tc["msg"] != "" else b""
blindpubnonce = bytes.fromhex(tc["blindpubnonce"])
pk = PlainPk(bytes.fromhex(tc["pk"]))
tweaks = fromhex_all(tc["tweaks"])
is_xonly = tc["is_xonly"]
extra_in = None if tc["extra_in"] is None else bytes.fromhex(tc["extra_in"])
expected_a = bytes.fromhex(tc["expected_blindfactor"])
expected_e = bytes.fromhex(tc["expected_challenge"])
expected_R = bytes.fromhex(tc["expected_pubnonce"])
expected_e_prime = bytes.fromhex(tc["expected_blindchallenge"])
expected_pk_parity = bool(tc["expected_pk_parity"])
expected_nonce_parity = bool(tc["expected_nonce_parity"])
session_ctx, blindchallenge, pk_parity, nonce_parity = blind_challenge_gen_internal(
rand, msg, blindpubnonce, pk, tweaks, is_xonly, extra_in
)
# Check tuple outputs
assert blindchallenge == expected_e_prime
assert pk_parity == expected_pk_parity
assert nonce_parity == expected_nonce_parity
# Check session_ctx fields
pk_sc, blindfactor_sc, challenge_sc, pubnonce_sc, tweaks_sc, is_xonly_sc = session_ctx
assert pk_sc == pk
assert blindfactor_sc == expected_a
assert challenge_sc == expected_e
assert pubnonce_sc == expected_R
assert tweaks_sc == tweaks
assert is_xonly_sc == is_xonly
# Extra sanity: recompute Q and e and compare
Q, gacc, tacc = pubkey_and_tweak(pk, tweaks, is_xonly)
R = cpoint(expected_R)
e_check = tagged_hash("BIP0340/challenge", xbytes(R) + xbytes(Q) + msg)
assert e_check == expected_e
# Length sanity
assert len(expected_a) == 32
assert len(expected_e) == 32
assert len(expected_R) == 33
assert len(expected_e_prime) == 32
# ---------- Error cases ----------
for tc in tv.get("error_test_cases", []):
rand = bytes.fromhex(tc["rand"])
msg = bytes.fromhex(tc["msg"]) if tc["msg"] != "" else b""
blindpubnonce = bytes.fromhex(tc["blindpubnonce"])
pk = PlainPk(bytes.fromhex(tc["pk"]))
tweaks = fromhex_all(tc["tweaks"])
is_xonly = tc["is_xonly"]
extra_in = None if tc["extra_in"] is None else bytes.fromhex(tc["extra_in"])
err = tc["error"]
err_type = err["type"]
err_message = err.get("message")
raised = False
try:
_ = blind_challenge_gen_internal(rand, msg, blindpubnonce, pk, tweaks, is_xonly, extra_in)
except Exception as e:
raised = True
# Type check
assert e.__class__.__name__ == err_type
# Optional substring match on message, if provided
if err_message is not None:
assert err_message in str(e)
assert raised, "Expected an exception but none was raised"
def test_blind_sign_and_verify_vectors():
with open(os.path.join(sys.path[0], 'vectors', 'blind_sign_and_verify_vectors.json')) as f:
tv = json.load(f)
# ------------------ Valid ------------------
for test_case in tv["valid_test_cases"]:
sk = hx(test_case["sk"])
pk = PlainPk(hx(test_case["pk"]))
blindsecnonce_all = hx(test_case["blindsecnonce"])
blindpubnonce = hx(test_case["blindpubnonce"])
blindchallenge = hx(test_case["blindchallenge"])
pk_parity = bool(test_case["pk_parity"])
nonce_parity = bool(test_case["nonce_parity"])
# R' consistency check: cbytes(k'*G) == blindpubnonce
k_ = Scalar.from_bytes_checked(blindsecnonce_all[0:32])
R_prime = k_ * G
assert cbytes(R_prime) == blindpubnonce
expected_sprime = hx(test_case["expected"]["blindsignature"])
# Copy because blind_sign zeroizes the first 64 bytes of the buffer
secnonce_buf = bytearray(blindsecnonce_all)
s_prime = blind_sign(sk, blindchallenge, secnonce_buf, pk_parity, nonce_parity)
assert s_prime == expected_sprime
checks = test_case.get("checks", {})
if checks.get("secnonce_prefix_zeroed_after_sign", False):
assert all(b == 0 for b in secnonce_buf[:64])
if checks.get("verify_returns_true", True):
ok = verify_blind_signature(pk, blindpubnonce, blindchallenge, s_prime, pk_parity, nonce_parity)
assert ok is True
if checks.get("second_call_raises_valueerror", False):
# Reuse the same (now zeroized) buffer; must raise
def try_again():
blind_sign(sk, blindchallenge, secnonce_buf, pk_parity, nonce_parity)
raised = False
try:
try_again()
except ValueError:
raised = True
assert raised, "Expected ValueError on nonce reuse"
# ------------------ Sign errors (exceptions) ------------------
for test_case in tv.get("sign_error_test_cases", []):
exception, except_fn = get_error_details(test_case)
sk = hx(test_case["sk"])
blindsecnonce_all = hx(test_case["blindsecnonce"])
blindchallenge = hx(test_case["blindchallenge"])
pk_parity = bool(test_case["pk_parity"])
nonce_parity = bool(test_case["nonce_parity"])
repeat = int(test_case.get("repeat", 1))
if repeat == 1:
# Single-call error (e.g., out-of-range e')
assert_raises(exception, lambda: blind_sign(sk, blindchallenge, bytearray(blindsecnonce_all), pk_parity, nonce_parity), except_fn)
else:
# Two-call error (nonce reuse)
buf = bytearray(blindsecnonce_all)
# First call should succeed
_ = blind_sign(sk, blindchallenge, buf, pk_parity, nonce_parity)
# Second call must raise
assert_raises(exception, lambda: blind_sign(sk, blindchallenge, buf, pk_parity, nonce_parity), except_fn)
# ------------------ Verify returns False (no exception) ------------------
for test_case in tv.get("verify_fail_test_cases", []):
pk = PlainPk(hx(test_case["pk"]))
blindpubnonce = hx(test_case["blindpubnonce"])
blindchallenge = hx(test_case["blindchallenge"])
blindsignature = hx(test_case["blindsignature"])
pk_parity = bool(test_case["pk_parity"])
nonce_parity = bool(test_case["nonce_parity"])
assert verify_blind_signature(pk, blindpubnonce, blindchallenge, blindsignature, pk_parity, nonce_parity) is False
# ------------------ Verify errors (exceptions) ------------------
for test_case in tv.get("verify_error_test_cases", []):
exception, except_fn = get_error_details(test_case)
pk = PlainPk(hx(test_case["pk"]))
blindpubnonce = hx(test_case["blindpubnonce"])
blindchallenge = hx(test_case["blindchallenge"])
blindsignature = hx(test_case["blindsignature"])
pk_parity = bool(test_case["pk_parity"])
nonce_parity = bool(test_case["nonce_parity"])
assert_raises(exception, lambda: verify_blind_signature(pk, blindpubnonce, blindchallenge, blindsignature, pk_parity, nonce_parity), except_fn)
def test_unblind_signature_vectors():
with open(os.path.join(sys.path[0], 'vectors', 'unblind_signature_vectors.json')) as f:
tv = json.load(f)
# ---------- Valid ----------
for tc in tv["valid_test_cases"]:
session_ctx = build_session_ctx(tc["session_ctx"])
msg = bytes.fromhex(tc["msg"]) if tc["msg"] != "" else b""
blindsignature = bytes.fromhex(tc["blindsignature"])
expected_sig = bytes.fromhex(tc["expected_bip340_sig"])
sig = unblind_signature(session_ctx, blindsignature)
assert sig == expected_sig
# Verify BIP340 with tweaked Q
pk, _, _, _, tweaks, is_xonly = session_ctx
Q, _, _ = pubkey_and_tweak(pk, tweaks, is_xonly)
assert schnorr_verify(msg, xbytes(Q), sig)
# ---------- Errors ----------
for tc in tv.get("error_test_cases", []):
session_ctx = build_session_ctx(tc["session_ctx"])
msg = bytes.fromhex(tc["msg"]) if tc["msg"] != "" else b""
blindsignature = bytes.fromhex(tc["blindsignature"])
err = tc["error"]
err_type = err["type"]
err_msg = err.get("message")
raised = False
try:
_ = unblind_signature(session_ctx, blindsignature)
except Exception as e:
raised = True
assert e.__class__.__name__ == err_type
if err_msg is not None:
assert err_msg in str(e)
assert raised, "Expected an exception but none was raised"
def test_sign_and_verify_random(iters: int) -> None:
for _ in range(iters):
sk = Scalar.from_bytes_wrapping(secrets.token_bytes(32))
pk = individual_pk(sk.to_bytes())
msg = Scalar.from_bytes_wrapping(secrets.token_bytes(32))
v = secrets.randbelow(4)
tweaks = [secrets.token_bytes(32) for _ in range(v)]
tweak_modes = [secrets.choice([False, True]) for _ in range(v)]
Q, _, _ = pubkey_and_tweak(pk, tweaks, tweak_modes)
assert not Q.infinity
# Round 1
# Signer
extra_in_1 = secrets.token_bytes(32)
blindsecnonce, blindpubnonce = blind_nonce_gen(sk.to_bytes(), pk, extra_in_1)
# User
extra_in_2 = secrets.token_bytes(32)
session_ctx, blindchallenge, pk_parity, nonce_parity = blind_challenge_gen(msg.to_bytes(), blindpubnonce, pk, tweaks, tweak_modes, extra_in_2)
# Round 2
# Signer
blindsignature = blind_sign(sk.to_bytes(), blindchallenge, blindsecnonce, pk_parity, nonce_parity)
# User
sig = unblind_signature(session_ctx, blindsignature)
assert schnorr_verify(msg.to_bytes(), xbytes(Q), sig)
def compute_bip32_tweak(xpub: ExtendedPublicKey, path: Sequence[int]) -> Tuple[int, ExtendedPublicKey]:
"""Compute the CCD tweak scalar for a non-hardened derivation path."""
aggregate = 0
current = xpub
for index in path:
tweak, child = current.derive_child(index)
aggregate = (aggregate + tweak) % CURVE_N
current = child
return aggregate, current
def input_verification(
descriptor_template: SortedMultiDescriptorTemplate,
witness_script: Optional[bytes],
tweaks: Mapping[bytes, int],
) -> bool:
"""Check that an input script matches the tweaked policy from CCD data."""
return _verify_tweaked_descriptor(
descriptor_template,
witness_script,
tweaks,
)
def change_output_verification(
descriptor_template: SortedMultiDescriptorTemplate,
witness_script: Optional[bytes],
tweaks: Mapping[bytes, int],
) -> bool:
"""Validate a change output script using delegated CCD tweak data."""
return _verify_tweaked_descriptor(
descriptor_template,
witness_script,
tweaks,
)
def _verify_tweaked_descriptor(
descriptor_template: SortedMultiDescriptorTemplate,
witness_script: Optional[bytes],
tweaks: Mapping[bytes, int],
) -> bool:
if witness_script is None or not tweaks:
return False
if descriptor_template.threshold > len(tweaks):
return False
tweaked_keys: List[bytes] = []
for base_key, tweak in sorted(tweaks.items(), key=lambda item: item[0]):
if len(base_key) != 33:
return False
tweaked_key = apply_tweak_to_public(base_key, tweak % CURVE_N)
tweaked_keys.append(tweaked_key)
try:
expected_witness_script = descriptor_template.witness_script(tweaked_keys)
except ValueError:
return False
return witness_script == expected_witness_script
def delegator_sign(
tweak: int,
base_secret: int,
message: bytes,
) -> bytes:
"""Derive the delegated key, sign ``message``, and return signature."""
child_secret = int_to_bytes(apply_tweak_to_secret(base_secret, tweak), 32)
message_digest = hashlib.sha256(message).digest()
signature = schnorr_sign(message_digest, child_secret, bytes(32))
return signature
def test_compute_tweak_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'compute_bip32_tweak_vectors.json')) as f:
data = json.load(f)
default_xpub_data = data.get("xpub")
if default_xpub_data is None:
raise AssertionError("compute_bip32_tweak_vectors.json missing top-level 'xpub'")
for case in data.get("valid_test_cases", []):
xpub_data = case.get("xpub", default_xpub_data)
xpub = parse_extended_public_key(xpub_data)
path = decode_path(case.get("path", []))
expected = case.get("expected")
if not isinstance(expected, Mapping):
raise AssertionError("valid compute_tweak case missing 'expected'")
tweak_hex = expected.get("tweak")
if not isinstance(tweak_hex, str):
raise AssertionError("expected 'tweak' must be a string")
derived = expected.get("derived_xpub", {})
derived_compressed = derived.get("compressed")
if not isinstance(derived_compressed, str):
raise AssertionError("expected 'derived_xpub.compressed' must be a string")
derived_chain_code = derived.get("chain_code")
if not isinstance(derived_chain_code, str):
raise AssertionError("expected 'derived_xpub.chain_code' must be a string")
tweak, child = compute_bip32_tweak(xpub, path)
actual_tweak_hex = f"{tweak:064x}"
if actual_tweak_hex != tweak_hex.lower():
raise AssertionError(f"tweak mismatch: expected {tweak_hex}, got {actual_tweak_hex}")
actual_compressed = compress_point(child.point).hex()
actual_chain_code = child.chain_code.hex()
if actual_compressed != derived_compressed.lower():
raise AssertionError("derived public key mismatch")
if actual_chain_code != derived_chain_code.lower():
raise AssertionError("derived chain code mismatch")
for case in data.get("error_test_cases", []):
xpub_data = case.get("xpub", default_xpub_data)
xpub = parse_extended_public_key(xpub_data)
path = decode_path(case.get("path", []))
error_spec = case.get("error", {})
exc_type, message = resolve_error_spec(error_spec)
try:
compute_bip32_tweak(xpub, path)
except exc_type as exc:
if message and message.lower() not in str(exc).lower():
raise AssertionError(f"expected error containing '{message}' but got '{exc}'")
else:
raise AssertionError("expected failure but case succeeded")
def test_delegator_sign_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'delegator_sign_vectors.json')) as f:
data = json.load(f)
for case in data.get("test_cases", []):
base_secret_hex = case.get("base_secret")
tweak_hex = case.get("tweak")
message_hex = case.get("message")
base_secret = int(base_secret_hex, 16)
tweak = int(tweak_hex, 16)
message = message_hex.encode('utf-8')
expected = case.get("expected")
if not isinstance(expected, Mapping):
raise AssertionError("delegator_sign case missing 'expected'")
expected_signature_hex = expected.get("signature")
if not isinstance(expected_signature_hex, str):
raise AssertionError("expected 'signature' must be a string")
expected_signature = bytes.fromhex(expected_signature_hex)
signature = delegator_sign(
tweak,
base_secret,
message,
)
if signature != expected_signature:
raise AssertionError("signature mismatch")
def test_input_verification_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'input_verification_vectors.json')) as f:
data = json.load(f)
for case in data.get("test_cases", []):
descriptor = SortedMultiDescriptorTemplate(threshold=2)
witness_hex = case.get("witness_script")
# Get the tweak map of the bare public keys to the BIP 32 tweak
tweaks_raw = case.get("tweak_map", {})
tweaks = parse_tweak_map(tweaks_raw)
expected_bool = bool(case.get("expected", False))
result = input_verification(
descriptor,
bytes.fromhex(witness_hex),
tweaks,
)
if result != expected_bool:
raise AssertionError(
f"input_verification result {result} did not match expected {expected_bool}"
)
def test_change_output_verification_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'change_output_verification_vectors.json')) as f:
data = json.load(f)
for case in data.get("test_cases", []):
descriptor = SortedMultiDescriptorTemplate(threshold=2)
witness_hex = case.get("witness_script")
# Get the tweak map of the bare public keys to the BIP 32 tweak
tweaks_raw = case.get("tweak_map", {})
tweaks = parse_tweak_map(tweaks_raw)
expected_bool = bool(case.get("expected", False))
result = change_output_verification(
descriptor,
bytes.fromhex(witness_hex),
tweaks,
)
if result != expected_bool:
raise AssertionError(
f"change_output_verification result {result} did not match expected {expected_bool}"
)
def parse_tweak_map(raw: Mapping[str, object]) -> Dict[bytes, int]:
tweaks: Dict[bytes, int] = {}
for key_hex, tweak_hex in raw.items():
base_key = bytes.fromhex(key_hex)
if not isinstance(tweak_hex, str):
raise ValueError(f"tweak value for key {key_hex} must be a string")
tweak_value = int(tweak_hex, 16)
tweaks[base_key] = tweak_value % CURVE_N
return tweaks
def resolve_error_spec(raw: object) -> Tuple[type[Exception], Optional[str]]:
mapping: Dict[str, type[Exception]] = {"value": ValueError, "assertion": AssertionError, "runtime": RuntimeError}
if not isinstance(raw, dict):
return ValueError, None
raw_dict = cast(Dict[str, Any], raw)
name = str(raw_dict.get("type", "value")).lower()
message = raw_dict.get("message")
exc_type = mapping.get(name, ValueError)
return exc_type, None if message is None else str(message)
if __name__ == '__main__':
test_blind_nonce_gen_vectors()
test_blind_challenge_gen_vectors()
test_blind_sign_and_verify_vectors()
test_unblind_signature_vectors()
test_sign_and_verify_random(6)
test_compute_tweak_vectors()
test_delegator_sign_vectors()
test_input_verification_vectors()
test_change_output_verification_vectors()
print("All tests passed")
================================================
FILE: bip-0089/secp256k1lab/COPYING
================================================
The MIT License (MIT)
Copyright (c) 2009-2024 The Bitcoin Core developers
Copyright (c) 2009-2024 Bitcoin Developers
Copyright (c) 2025- The secp256k1lab Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: bip-0089/secp256k1lab/__init__.py
================================================
================================================
FILE: bip-0089/secp256k1lab/bip340.py
================================================
# The following functions are based on the BIP 340 reference implementation:
# https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py
from .secp256k1 import FE, GE, G
from .util import int_from_bytes, bytes_from_int, xor_bytes, tagged_hash
def pubkey_gen(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
P = d0 * G
assert not P.infinity
return P.to_bytes_xonly()
def schnorr_sign(
msg: bytes, seckey: bytes, aux_rand: bytes, tag_prefix: str = "BIP0340"
) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
if len(aux_rand) != 32:
raise ValueError("aux_rand must be 32 bytes instead of %i." % len(aux_rand))
P = d0 * G
assert not P.infinity
d = d0 if P.has_even_y() else GE.ORDER - d0
t = xor_bytes(bytes_from_int(d), tagged_hash(tag_prefix + "/aux", aux_rand))
k0 = (
int_from_bytes(tagged_hash(tag_prefix + "/nonce", t + P.to_bytes_xonly() + msg))
% GE.ORDER
)
if k0 == 0:
raise RuntimeError("Failure. This happens only with negligible probability.")
R = k0 * G
assert not R.infinity
k = k0 if R.has_even_y() else GE.ORDER - k0
e = (
int_from_bytes(
tagged_hash(
tag_prefix + "/challenge", R.to_bytes_xonly() + P.to_bytes_xonly() + msg
)
)
% GE.ORDER
)
sig = R.to_bytes_xonly() + bytes_from_int((k + e * d) % GE.ORDER)
assert schnorr_verify(msg, P.to_bytes_xonly(), sig, tag_prefix=tag_prefix)
return sig
def schnorr_verify(
msg: bytes, pubkey: bytes, sig: bytes, tag_prefix: str = "BIP0340"
) -> bool:
if len(pubkey) != 32:
raise ValueError("The public key must be a 32-byte array.")
if len(sig) != 64:
raise ValueError("The signature must be a 64-byte array.")
try:
P = GE.from_bytes_xonly(pubkey)
except ValueError:
return False
r = int_from_bytes(sig[0:32])
s = int_from_bytes(sig[32:64])
if (r >= FE.SIZE) or (s >= GE.ORDER):
return False
e = (
int_from_bytes(tagged_hash(tag_prefix + "/challenge", sig[0:32] + pubkey + msg))
% GE.ORDER
)
R = s * G - e * P
if R.infinity or (not R.has_even_y()) or (R.x != r):
return False
return True
================================================
FILE: bip-0089/secp256k1lab/ecdh.py
================================================
import hashlib
from .secp256k1 import GE, Scalar
def ecdh_compressed_in_raw_out(seckey: bytes, pubkey: bytes) -> GE:
"""TODO"""
shared_secret = Scalar.from_bytes_checked(seckey) * GE.from_bytes_compressed(pubkey)
assert not shared_secret.infinity # prime-order group
return shared_secret
def ecdh_libsecp256k1(seckey: bytes, pubkey: bytes) -> bytes:
"""TODO"""
shared_secret = ecdh_compressed_in_raw_out(seckey, pubkey)
return hashlib.sha256(shared_secret.to_bytes_compressed()).digest()
================================================
FILE: bip-0089/secp256k1lab/keys.py
================================================
from .secp256k1 import GE, G
from .util import int_from_bytes
# The following function is based on the BIP 327 reference implementation
# https://github.com/bitcoin/bips/blob/master/bip-0327/reference.py
# Return the plain public key corresponding to a given secret key
def pubkey_gen_plain(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
P = d0 * G
assert not P.infinity
return P.to_bytes_compressed()
================================================
FILE: bip-0089/secp256k1lab/py.typed
================================================
================================================
FILE: bip-0089/secp256k1lab/secp256k1.py
================================================
# Copyright (c) 2022-2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test-only implementation of low-level secp256k1 field and group arithmetic
It is designed for ease of understanding, not performance.
WARNING: This code is slow and trivially vulnerable to side channel attacks. Do not use for
anything but tests.
Exports:
* FE: class for secp256k1 field elements
* GE: class for secp256k1 group elements
* G: the secp256k1 generator point
"""
from __future__ import annotations
from typing import Self
# TODO Docstrings of methods still say "field element"
class APrimeFE:
"""Objects of this class represent elements of a prime field.
They are represented internally in numerator / denominator form, in order to delay inversions.
"""
# The size of the field (also its modulus and characteristic).
SIZE: int
def __init__(self, a: int | Self = 0, b: int | Self = 1) -> None:
"""Initialize a field element a/b; both a and b can be ints or field elements."""
if isinstance(a, type(self)):
num = a._num
den = a._den
else:
assert isinstance(a, int)
num = a % self.SIZE
den = 1
if isinstance(b, type(self)):
den = (den * b._num) % self.SIZE
num = (num * b._den) % self.SIZE
else:
assert isinstance(b, int)
den = (den * b) % self.SIZE
assert den != 0
if num == 0:
den = 1
self._num: int = num
self._den: int = den
def __add__(self, a: int | Self) -> Self:
"""Compute the sum of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._den + self._den * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num + self._den * a, self._den)
return NotImplemented
def __radd__(self, a: int) -> Self:
"""Compute the sum of an integer and a field element."""
return type(self)(a) + self
@classmethod
def sum(cls, *es: Self) -> Self:
"""Compute the sum of field elements.
sum(a, b, c, ...) is identical to (0 + a + b + c + ...)."""
return sum(es, start=cls(0))
def __sub__(self, a: int | Self) -> Self:
"""Compute the difference of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._den - self._den * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num - self._den * a, self._den)
return NotImplemented
def __rsub__(self, a: int) -> Self:
"""Compute the difference of an integer and a field element."""
return type(self)(a) - self
def __mul__(self, a: int | Self) -> Self:
"""Compute the product of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num * a, self._den)
return NotImplemented
def __rmul__(self, a: int) -> Self:
"""Compute the product of an integer with a field element."""
return type(self)(a) * self
def __truediv__(self, a: int | Self) -> Self:
"""Compute the ratio of two field elements (second may be int)."""
if isinstance(a, type(self)) or isinstance(a, int):
return type(self)(self, a)
return NotImplemented
def __pow__(self, a: int) -> Self:
"""Raise a field element to an integer power."""
return type(self)(pow(self._num, a, self.SIZE), pow(self._den, a, self.SIZE))
def __neg__(self) -> Self:
"""Negate a field element."""
return type(self)(-self._num, self._den)
def __int__(self) -> int:
"""Convert a field element to an integer in range 0..SIZE-1. The result is cached."""
if self._den != 1:
self._num = (self._num * pow(self._den, -1, self.SIZE)) % self.SIZE
self._den = 1
return self._num
def sqrt(self) -> Self | None:
"""Compute the square root of a field element if it exists (None otherwise)."""
raise NotImplementedError
def is_square(self) -> bool:
"""Determine if this field element has a square root."""
# A more efficient algorithm is possible here (Jacobi symbol).
return self.sqrt() is not None
def is_even(self) -> bool:
"""Determine whether this field element, represented as integer in 0..SIZE-1, is even."""
return int(self) & 1 == 0
def __eq__(self, a: object) -> bool:
"""Check whether two field elements are equal (second may be an int)."""
if isinstance(a, type(self)):
return (self._num * a._den - self._den * a._num) % self.SIZE == 0
elif isinstance(a, int):
return (self._num - self._den * a) % self.SIZE == 0
return False # for other types
def to_bytes(self) -> bytes:
"""Convert a field element to a 32-byte array (BE byte order)."""
return int(self).to_bytes(32, 'big')
@classmethod
def from_int_checked(cls, v: int) -> Self:
"""Convert an integer to a field element (no overflow allowed)."""
if v >= cls.SIZE:
raise ValueError
return cls(v)
@classmethod
def from_int_wrapping(cls, v: int) -> Self:
"""Convert an integer to a field element (reduced modulo SIZE)."""
return cls(v % cls.SIZE)
@classmethod
def from_bytes_checked(cls, b: bytes) -> Self:
"""Convert a 32-byte array to a field element (BE byte order, no overflow allowed)."""
v = int.from_bytes(b, 'big')
return cls.from_int_checked(v)
@classmethod
def from_bytes_wrapping(cls, b: bytes) -> Self:
"""Convert a 32-byte array to a field element (BE byte order, reduced modulo SIZE)."""
v = int.from_bytes(b, 'big')
return cls.from_int_wrapping(v)
def __str__(self) -> str:
"""Convert this field element to a 64 character hex string."""
return f"{int(self):064x}"
def __repr__(self) -> str:
"""Get a string representation of this field element."""
return f"{type(self).__qualname__}(0x{int(self):x})"
class FE(APrimeFE):
SIZE = 2**256 - 2**32 - 977
def sqrt(self) -> Self | None:
# Due to the fact that our modulus p is of the form (p % 4) == 3, the Tonelli-Shanks
# algorithm (https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm) is simply
# raising the argument to the power (p + 1) / 4.
# To see why: (p-1) % 2 = 0, so 2 divides the order of the multiplicative group,
# and thus only half of the non-zero field elements are squares. An element a is
# a (nonzero) square when Euler's criterion, a^((p-1)/2) = 1 (mod p), holds. We're
# looking for x such that x^2 = a (mod p). Given a^((p-1)/2) = 1, that is equivalent
# to x^2 = a^(1 + (p-1)/2) mod p. As (1 + (p-1)/2) is even, this is equivalent to
# x = a^((1 + (p-1)/2)/2) mod p, or x = a^((p+1)/4) mod p.
v = int(self)
s = pow(v, (self.SIZE + 1) // 4, self.SIZE)
if s**2 % self.SIZE == v:
return type(self)(s)
return None
class Scalar(APrimeFE):
"""TODO Docstring"""
SIZE = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
@classmethod
def from_int_nonzero_checked(cls, v: int) -> Self:
"""Convert an integer to a scalar (no zero or overflow allowed)."""
if not (0 < v < cls.SIZE):
raise ValueError
return cls(v)
@classmethod
def from_bytes_nonzero_checked(cls, b: bytes) -> Self:
"""Convert a 32-byte array to a scalar (BE byte order, no zero or overflow allowed)."""
v = int.from_bytes(b, 'big')
return cls.from_int_nonzero_checked(v)
class GE:
"""Objects of this class represent secp256k1 group elements (curve points or infinity)
GE objects are immutable.
Normal points on the curve have fields:
* x: the x coordinate (a field element)
* y: the y coordinate (a field element, satisfying y^2 = x^3 + 7)
* infinity: False
The point at infinity has field:
* infinity: True
"""
# TODO The following two class attributes should probably be just getters as
# classmethods to enforce immutability. Unfortunately Python makes it hard
# to create "classproperties". `G` could then also be just a classmethod.
# Order of the group (number of points on the curve, plus 1 for infinity)
ORDER = Scalar.SIZE
# Number of valid distinct x coordinates on the curve.
ORDER_HALF = ORDER // 2
@property
def infinity(self) -> bool:
"""Whether the group element is the point at infinity."""
return self._infinity
@property
def x(self) -> FE:
"""The x coordinate (a field element) of a non-infinite group element."""
assert not self.infinity
return self._x
@property
def y(self) -> FE:
"""The y coordinate (a field element) of a non-infinite group element."""
assert not self.infinity
return self._y
def __init__(self, x: int | FE | None = None, y: int | FE | None = None) -> None:
"""Initialize a group element with specified x and y coordinates, or infinity."""
if x is None:
# Initialize as infinity.
assert y is None
self._infinity = True
else:
# Initialize as point on the curve (and check that it is).
assert x is not None
assert y is not None
fx = FE(x)
fy = FE(y)
assert fy**2 == fx**3 + 7
self._infinity = False
self._x = fx
self._y = fy
def __add__(self, a: GE) -> GE:
"""Add two group elements together."""
# Deal with infinity: a + infinity == infinity + a == a.
if self.infinity:
return a
if a.infinity:
return self
if self.x == a.x:
if self.y != a.y:
# A point added to its own negation is infinity.
assert self.y + a.y == 0
return GE()
else:
# For identical inputs, use the tangent (doubling formula).
lam = (3 * self.x**2) / (2 * self.y)
else:
# For distinct inputs, use the line through both points (adding formula).
lam = (self.y - a.y) / (self.x - a.x)
# Determine point opposite to the intersection of that line with the curve.
x = lam**2 - (self.x + a.x)
y = lam * (self.x - x) - self.y
return GE(x, y)
@staticmethod
def sum(*ps: GE) -> GE:
"""Compute the sum of group elements.
GE.sum(a, b, c, ...) is identical to (GE() + a + b + c + ...)."""
return sum(ps, start=GE())
@staticmethod
def batch_mul(*aps: tuple[Scalar, GE]) -> GE:
"""Compute a (batch) scalar group element multiplication.
GE.batch_mul((a1, p1), (a2, p2), (a3, p3)) is identical to a1*p1 + a2*p2 + a3*p3,
but more efficient."""
# Reduce all the scalars modulo order first (so we can deal with negatives etc).
naps = [(int(a), p) for a, p in aps]
# Start with point at infinity.
r = GE()
# Iterate over all bit positions, from high to low.
for i in range(255, -1, -1):
# Double what we have so far.
r = r + r
# Add then add the points for which the corresponding scalar bit is set.
for (a, p) in naps:
if (a >> i) & 1:
r += p
return r
def __rmul__(self, a: int | Scalar) -> GE:
"""Multiply an integer or scalar with a group element."""
if self == G:
return FAST_G.mul(Scalar(a))
return GE.batch_mul((Scalar(a), self))
def __neg__(self) -> GE:
"""Compute the negation of a group element."""
if self.infinity:
return self
return GE(self.x, -self.y)
def __sub__(self, a: GE) -> GE:
"""Subtract a group element from another."""
return self + (-a)
def __eq__(self, a: object) -> bool:
"""Check if two group elements are equal."""
if not isinstance(a, type(self)):
return False
return (self - a).infinity
def has_even_y(self) -> bool:
"""Determine whether a non-infinity group element has an even y coordinate."""
assert not self.infinity
return self.y.is_even()
def to_bytes_compressed(self) -> bytes:
"""Convert a non-infinite group element to 33-byte compressed encoding."""
assert not self.infinity
return bytes([3 - self.y.is_even()]) + self.x.to_bytes()
def to_bytes_compressed_with_infinity(self) -> bytes:
"""Convert a group element to 33-byte compressed encoding, mapping infinity to zeros."""
if self.infinity:
return 33 * b"\x00"
return self.to_bytes_compressed()
def to_bytes_uncompressed(self) -> bytes:
"""Convert a non-infinite group element to 65-byte uncompressed encoding."""
assert not self.infinity
return b'\x04' + self.x.to_bytes() + self.y.to_bytes()
def to_bytes_xonly(self) -> bytes:
"""Convert (the x coordinate of) a non-infinite group element to 32-byte xonly encoding."""
assert not self.infinity
return self.x.to_bytes()
@staticmethod
def lift_x(x: int | FE) -> GE:
"""Return group element with specified field element as x coordinate (and even y)."""
y = (FE(x)**3 + 7).sqrt()
if y is None:
raise ValueError
if not y.is_even():
y = -y
return GE(x, y)
@staticmethod
def from_bytes_compressed(b: bytes) -> GE:
"""Convert a compressed to a group element."""
assert len(b) == 33
if b[0] != 2 and b[0] != 3:
raise ValueError
x = FE.from_bytes_checked(b[1:])
r = GE.lift_x(x)
if b[0] == 3:
r = -r
return r
@staticmethod
def from_bytes_compressed_with_infinity(b: bytes) -> GE:
"""Convert a compressed to a group element, mapping zeros to infinity."""
if b == 33 * b"\x00":
return GE()
else:
return GE.from_bytes_compressed(b)
@staticmethod
def from_bytes_uncompressed(b: bytes) -> GE:
"""Convert an uncompressed to a group element."""
assert len(b) == 65
if b[0] != 4:
raise ValueError
x = FE.from_bytes_checked(b[1:33])
y = FE.from_bytes_checked(b[33:])
if y**2 != x**3 + 7:
raise ValueError
return GE(x, y)
@staticmethod
def from_bytes(b: bytes) -> GE:
"""Convert a compressed or uncompressed encoding to a group element."""
assert len(b) in (33, 65)
if len(b) == 33:
return GE.from_bytes_compressed(b)
else:
return GE.from_bytes_uncompressed(b)
@staticmethod
def from_bytes_xonly(b: bytes) -> GE:
"""Convert a point given in xonly encoding to a group element."""
assert len(b) == 32
x = FE.from_bytes_checked(b)
r = GE.lift_x(x)
return r
@staticmethod
def is_valid_x(x: int | FE) -> bool:
"""Determine whether the provided field element is a valid X coordinate."""
return (FE(x)**3 + 7).is_square()
def __str__(self) -> str:
"""Convert this group element to a string."""
if self.infinity:
return "(inf)"
return f"({self.x},{self.y})"
def __repr__(self) -> str:
"""Get a string representation for this group element."""
if self.infinity:
return "GE()"
return f"GE(0x{int(self.x):x},0x{int(self.y):x})"
def __hash__(self) -> int:
"""Compute a non-cryptographic hash of the group element."""
if self.infinity:
return 0 # 0 is not a valid x coordinate
return int(self.x)
# The secp256k1 generator point
G = GE.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
class FastGEMul:
"""Table for fast multiplication with a constant group element.
Speed up scalar multiplication with a fixed point P by using a precomputed lookup table with
its powers of 2:
table = [P, 2*P, 4*P, (2^3)*P, (2^4)*P, ..., (2^255)*P]
During multiplication, the points corresponding to each bit set in the scalar are added up,
i.e. on average ~128 point additions take place.
"""
def __init__(self, p: GE) -> None:
self.table: list[GE] = [p] # table[i] = (2^i) * p
for _ in range(255):
p = p + p
self.table.append(p)
def mul(self, a: Scalar | int) -> GE:
result = GE()
a_ = int(a)
for bit in range(a_.bit_length()):
if a_ & (1 << bit):
result += self.table[bit]
return result
# Precomputed table with multiples of G for fast multiplication
FAST_G = FastGEMul(G)
================================================
FILE: bip-0089/secp256k1lab/util.py
================================================
import hashlib
# This implementation can be sped up by storing the midstate after hashing
# tag_hash instead of rehashing it all the time.
def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
def bytes_from_int(x: int) -> bytes:
return x.to_bytes(32, byteorder="big")
def xor_bytes(b0: bytes, b1: bytes) -> bytes:
return bytes(x ^ y for (x, y) in zip(b0, b1))
def int_from_bytes(b: bytes) -> int:
return int.from_bytes(b, byteorder="big")
def hash_sha256(b: bytes) -> bytes:
return hashlib.sha256(b).digest()
================================================
FILE: bip-0089/vectors/blind_challenge_gen_vectors.json
================================================
{
"test_cases": [
{
"rand": "92950940B9C21B956D2950EA4C2CBD966D5DCF32517D2419636C3B434E7E7243",
"msg": "33DF4B220B36836C25198D4AFCFD25D1EE2E7B237C3021D7A0EDBA137E70958C",
"blindpubnonce": "02866A953BB982D4755FC9DCF0E09CC8EA56E2F75040DCAFE0C17A2A6FB5D4AC6E",
"pk": "0232D9E2657C0AA02A6E5AFF67175757832D1B3260A915970EA1CD95E2C9838B52",
"tweaks": ["7F91E8EA5D4FD39AAEB0FCDE90ABAAA8681D2610AF0FDDF132DEFBD5E1183580", "8F4ECAB71A22CDB15945BD2898DF005A8623B8DC50013F12700E678E92837406", "FD890EE6226ECA9EFB889DC1EC77B5D59FE0AF1D876C35F2CBE9F25F6B8FB760"],
"is_xonly": [true, true, false],
"extra_in": "FD8AA0C64B66C38EA627FABB0CFCCE5BB905D130470101ED88771E0A62331AC9",
"expected_blindfactor": "545AB2AAB17406BE3270D0DFB7B13568F9ED5FAD5ABC5E9ACBAFC8D17131CC37",
"expected_challenge": "AC03DF1F1DA05BFD6E01E11BD7B95E3A6A0752BBB0E31EA26251675CECCE3A15",
"expected_pubnonce": "0367E34DAB4F1377CD8F3E7C5CD3E1E4A4D3B27BEAB9C0C0DC6717C9C52275D03B",
"expected_blindchallenge": "B5B3A3D63771818E930E55D3F91EBF11ED16BCDB11E0F1B5DF06F636F870DFB5",
"expected_pk_parity": true,
"expected_nonce_parity": false
}
],
"error_test_cases": [
{
"rand": "2B01EE16681AE0C2D8845C5F1D3F05F92453E95E7AC053DD5CABC736322B6CA3",
"msg": "6C22FC98FEEB69347A04BDE44B99FA50428689608E63B307D9F5904F86FE0B28",
"blindpubnonce": "02D9F53C5816BD205B8208A11491530CD6BD1EC35FFA31F026AD3444EFEA329440",
"pk": "03E9EBFEEAF165FBA6CD394EB1DBD514AE45CE8EA0AE56D54C8B5D7931D79FFBAF",
"tweaks": ["E3DD85653AAFDF2D94312FB8133D6B7E12DFC94B1B82A4E98D85E69D6F2F179A"],
"is_xonly": [true, false],
"extra_in": "C8BB4B046334864F71173C39BDE2A305289AA1AB5C0E0C624EC2D30A0A182310",
"error": {
"type": "ValueError",
"message": "The tweaks and is_xonly arrays must have the same length."
},
"comment": "mismatched arrays"
},
{
"rand": "A8F932BD0BAC6F31824002482A42493B7AA1CAC2814D80D470A716D47ADCDF86",
"msg": "1776037E19AA1A2BF2C9DB770CA12A5AB683E2D7B436090BAC8CE48CB22582E0",
"blindpubnonce": "04411898DF38979F1DA000CEFF9166EE258AB6B0F696B8537F90E551751AA3C6F2",
"pk": "0333438C1C269BD73BADE95C62EDA258F74B093DA359DEDBF990E923CEC95BD6A4",
"tweaks": [],
"is_xonly": [],
"extra_in": null,
"error": {
"type": "ValueError"
},
"comment": "invalid blindpubnonce encoding"
}
]
}
================================================
FILE: bip-0089/vectors/blind_nonce_gen_vectors.json
================================================
{
"test_cases": [
{
"rand_": "0F6166D1645791EAD551572348A43CA9293E02CF0ED32B17EA5E1AEC6BC41931",
"sk": "F22F1B584D8B5CE15ED8F561DAD077B3FB743E6AABB97DBA758AFD88852DB490",
"pk": "0204B445C4EF4E822DA5842965BC03CBDC865EF846774FD27ACDE063F40CD7812C",
"extra_in": "887BEFE686260D09F471715719B7CB2D48E4116BD346319D9C002A4FC9D82857",
"expected_blindsecnonce": "A4B954BBCB05059CF0ACE8BC2C82BEA5ABD0D2C39B03D7A7205DB41E9BE9CA610204B445C4EF4E822DA5842965BC03CBDC865EF846774FD27ACDE063F40CD7812C",
"expected_blindpubnonce": "0355A32C1B472EE1874924CD9A1BF2536D6A2B214413684FBDFC5B84870EFDCEF8",
"comment": "All params present"
},
{
"rand_": "D4B20323E12CEC7E21B41A4FD2395844F93D4B3E9F3FED13CF3234C32702A242",
"sk": null,
"pk": null,
"extra_in": null,
"expected_blindsecnonce": "78ACDD864846BB5C18017A421E792CC771D63EDA6B63A6CDC3825F298CAC7788",
"expected_blindpubnonce": "025CA329F7676AECEAC10C29566D9C7883A661DB2574454AE491476EADEE3CD430",
"comment": "Every optional parameter is absent"
}
]
}
================================================
FILE: bip-0089/vectors/blind_sign_and_verify_vectors.json
================================================
{
"valid_test_cases": [
{
"sk": "E4E64DB308215A81F1F41969624B9A6265D50F479BA6789E40190027AC6C72A8",
"pk": "03E812BE6ED9A2B180FA21B682D5FB35158A9542399D389B736AEDC930CAED04AA",
"blindsecnonce": "D05EC853CBCFC49EAEB5DF5AED030C880C1FB59414AD4ECC3D0E5C50CD7B906803E812BE6ED9A2B180FA21B682D5FB35158A9542399D389B736AEDC930CAED04AA",
"blindpubnonce": "03E97BD8C531CB0B40AC13857BCDCA6E9FF33889148BA5C9C02E0BE93D79560186",
"blindchallenge": "64FD1082FA5E7C5BF1267A5AB5BC3F4BD41167427E4D4A4166876709857E92EB",
"pk_parity": true,
"nonce_parity": false,
"expected": {
"blindsignature": "8632B771A6A923FF1561B3513C4841F2D88795B05D99BC581ABCA201EED86EC5"
},
"checks": {
"verify_returns_true": true,
"secnonce_prefix_zeroed_after_sign": true,
"second_call_raises_valueerror": true
}
}
],
"sign_error_test_cases": [
{
"sk": "5D2E5F8FD68D31B28F14334CA3E2DF8B85C2F31DBBD5C3E583DBFF90E2024286",
"blindsecnonce": "EDBA15E0F013E5323F22998F324B5ABF75D8FEB5EF4FD4BBD7B706B057BF1F08036E3F9DB8CD5E6461E8C23F80F4A67F7006011A1AE3DBDD863213E73D1534D5DC",
"blindchallenge": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
"pk_parity": false,
"nonce_parity": true,
"error": { "type": "ValueError" },
"repeat": 1,
"comment": "e' out of range"
},
{
"sk": "8C3975176DD4A9A2CFDFBBF50243C29E6C889D3867BE5D3C3BEBCD00B1BC6469",
"blindsecnonce": "E1B7C8E2750577A638D26BCABE96F66C7AE5DCCC6BF429E167686CC1BCDC07AF037C1AAEF6EEDEA6DBB123DC76D8C4AF9210E33EB26D7BBA95123680E0632F7F65",
"blindchallenge": "93EF4DEE1C3EC61665D94448715FC756363FC775A10B6CBB158B089404E3CB1E",
"pk_parity": true,
"nonce_parity": false,
"error": { "type": "ValueError" },
"repeat": 2,
"comment": "nonce reuse: second call must raise"
}
],
"verify_fail_test_cases": [
{
"pk": "03E812BE6ED9A2B180FA21B682D5FB35158A9542399D389B736AEDC930CAED04AA",
"blindpubnonce": "03E97BD8C531CB0B40AC13857BCDCA6E9FF33889148BA5C9C02E0BE93D79560186",
"blindchallenge": "64FD1082FA5E7C5BF1267A5AB5BC3F4BD41167427E4D4A4166876709857E92EB",
"blindsignature": "9632B771A6A923FF1561B3513C4841F2D88795B05D99BC581ABCA201EED86EC5",
"pk_parity": true,
"nonce_parity": false,
"expected_valid": false,
"comment": "Verify should return False (no exception)"
}
],
"verify_error_test_cases": [
{
"pk": "03E812BE6ED9A2B180FA21B682D5FB35158A9542399D389B736AEDC930CAED04AA",
"blindpubnonce": "04E97BD8C531CB0B40AC13857BCDCA6E9FF33889148BA5C9C02E0BE93D79560186",
"blindchallenge": "64FD1082FA5E7C5BF1267A5AB5BC3F4BD41167427E4D4A4166876709857E92EB",
"blindsignature": "8632B771A6A923FF1561B3513C4841F2D88795B05D99BC581ABCA201EED86EC5",
"pk_parity": true,
"nonce_parity": false,
"error": { "type": "ValueError" },
"comment": "Bad blindpubnonce encoding"
}
]
}
================================================
FILE: bip-0089/vectors/change_output_verification_vectors.json
================================================
{
"test_cases": [
{
"comment": "Change output verification 2-of-3 (path [1,5])",
"expected": true,
"tweak_map": {
"02a047233eec59cf06b9a5ee62d9088eeb8127201423f88637443ff7ee591923c9": "ee665bd369e95c42180fc3e4a504ce4f19173deb6ee7ed1b2c05df7d37d8ed1e",
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "2102aa7f5b2acf81e86d9fa841acdfe8e08d1faa800a318679ad7423dc615a2b",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "96c3196aaa0af9b79148d58ff2f58dc7291d4007202722602ddbd29e6cd6c018"
},
"witness_script": "52210202573f6f0cd23e1d68894ddf5a50f65970833b75d7c1d5b862cbe17166d48850210206df37b85a2393162f1efd561297c37165dc7d8958ab4c5553ddf2e08108784d21037579ad42e47027db0734e66894863f31287b663695f643eb655873baf761a20453ae"
},
{
"comment": "Witness script mismatch",
"expected": false,
"tweaks": {
"02a047233eec59cf06b9a5ee62d9088eeb8127201423f88637443ff7ee591923c9": "ee665bd369e95c42180fc3e4a504ce4f19173deb6ee7ed1b2c05df7d37d8ed1e",
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "2102aa7f5b2acf81e86d9fa841acdfe8e08d1faa800a318679ad7423dc615a2b",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "96c3196aaa0af9b79148d58ff2f58dc7291d4007202722602ddbd29e6cd6c018"
},
"witness_script": "52210202573f6f0cd23e1d68894ddf5a50f65970833b75d7c1d5b862cbe17166d48850210206df37b85a2393162f1efd561297c37165dc7d8958ab4c5553ddf2e08108784d21037579ad42e47027db0734e66894863f31287b663695f643eb655873baf761a20453af"
},
{
"comment": "Missing participant tweak",
"expected": false,
"tweaks": {
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "2102aa7f5b2acf81e86d9fa841acdfe8e08d1faa800a318679ad7423dc615a2b",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "96c3196aaa0af9b79148d58ff2f58dc7291d4007202722602ddbd29e6cd6c018"
},
"witness_script": "52210202573f6f0cd23e1d68894ddf5a50f65970833b75d7c1d5b862cbe17166d48850210206df37b85a2393162f1efd561297c37165dc7d8958ab4c5553ddf2e08108784d21037579ad42e47027db0734e66894863f31287b663695f643eb655873baf761a20453ae"
},
{
"comment": "Invalid base key length in tweak map",
"expected": false,
"tweaks": {
"02a047233eec59cf06b9a5ee62d9088eeb8127201423f88637443ff7ee591923": "ee665bd369e95c42180fc3e4a504ce4f19173deb6ee7ed1b2c05df7d37d8ed1e",
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "2102aa7f5b2acf81e86d9fa841acdfe8e08d1faa800a318679ad7423dc615a2b",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "96c3196aaa0af9b79148d58ff2f58dc7291d4007202722602ddbd29e6cd6c018"
},
"witness_script": "52210202573f6f0cd23e1d68894ddf5a50f65970833b75d7c1d5b862cbe17166d48850210206df37b85a2393162f1efd561297c37165dc7d8958ab4c5553ddf2e08108784d21037579ad42e47027db0734e66894863f31287b663695f643eb655873baf761a20453ae"
}
]
}
================================================
FILE: bip-0089/vectors/compute_bip32_tweak_vectors.json
================================================
{
"xpub": {
"compressed": "0296928602758150d2b4a8a253451b887625b94ab0a91f801f1408cb33b9cf0f83",
"chain_code": "433cf1154e61c4eb9793488880f8a795a3a72052ad14a7367852542425609640",
"depth": 0,
"parent_fingerprint": "71348c8a",
"child_number": 0
},
"valid_test_cases": [
{
"comment": "Delegatee tweak aggregation for a two-step path",
"path": ["0", "1"],
"expected": {
"tweak": "d81d8e239630639ac24f3976257d9e4d905272b3da3a6507841c1ec80b04b91b",
"derived_xpub": {
"compressed": "03636eb334a6ffdfc4b975a61dae12f49e7f94461690fa4688632db8eed5601b03",
"chain_code": "299bc0ad44ab883a5be9601918badd2720c86c48a6d8b9d17e1ae1c3b0ad975d"
}
}
}
],
"error_test_cases": [
{
"comment": "Hardened path should raise an error",
"path": ["0", "2147483648"],
"error": {
"type": "value",
"message": "Hardened derivations are not supported for delegates"
}
}
]
}
================================================
FILE: bip-0089/vectors/delegator_sign_vectors.json
================================================
{
"test_cases": [
{
"comment": "Delegator signing with provided CCD tweak over arbitrary message",
"base_secret": "9303c68c414a6208dbc0329181dd640b135e669647ad7dcb2f09870c54b26ed9",
"tweak": "d81d8e239630639ac24f3976257d9e4d905272b3da3a6507841c1ec80b04b91b",
"message": "Chain Code Delegation",
"expected": {
"signature": "2f558d1519106f6cffdcfce09954c6ae328b98308718a0903e3efed103b457cd563c315fe6c6b5ffe6f71f413ce68ba22ee793238ab73fd2cef9d5881ae80017"
}
}
]
}
================================================
FILE: bip-0089/vectors/input_verification_vectors.json
================================================
{
"test_cases": [
{
"comment": "Input verification for wsh(sortedmulti) 2-of-3 (path [0,5])",
"expected": true,
"tweak_map": {
"02a047233eec59cf06b9a5ee62d9088eeb8127201423f88637443ff7ee591923c9": "6e4dd29833f7b88751dad6ea6ff536959122f2d07074006657d0e2ef26af3ef6",
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "b30d8530e3464dc71ed6e20897ef5c3c9d1149ecc11f332336520addab1454f3",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "c1efff9fb89227d09e54b403ae269f1991003e964f66f412e8302f8bb1c71644"
},
"witness_script": "5221034ebf1d6b674fbf3d7ff09e4bc44b23e17745188b4aac3e2e101bd210cd8f3ed42103a0d8aed25b77d286d7bf7a668b452f18def89f2e2285acd315fc00668fe0a70b2103bd4632ebd0de4573710722bf73b4bbb76713734c4756b830302b8492f29a6aae53ae"
},
{
"comment": "Witness script mismatch",
"expected": false,
"tweak_map": {
"02a047233eec59cf06b9a5ee62d9088eeb8127201423f88637443ff7ee591923c9": "6e4dd29833f7b88751dad6ea6ff536959122f2d07074006657d0e2ef26af3ef6",
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "b30d8530e3464dc71ed6e20897ef5c3c9d1149ecc11f332336520addab1454f3",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "c1efff9fb89227d09e54b403ae269f1991003e964f66f412e8302f8bb1c71644"
},
"witness_script": "5221034ebf1d6b674fbf3d7ff09e4bc44b23e17745188b4aac3e2e101bd210cd8f3ed42103a0d8aed25b77d286d7bf7a668b452f18def89f2e2285acd315fc00668fe0a70b2103bd4632ebd0de4573710722bf73b4bbb76713734c4756b830302b8492f29a6aae53af"
},
{
"comment": "Missing participant tweak",
"expected": false,
"tweak_map": {
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "b30d8530e3464dc71ed6e20897ef5c3c9d1149ecc11f332336520addab1454f3",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "c1efff9fb89227d09e54b403ae269f1991003e964f66f412e8302f8bb1c71644"
},
"witness_script": "5221034ebf1d6b674fbf3d7ff09e4bc44b23e17745188b4aac3e2e101bd210cd8f3ed42103a0d8aed25b77d286d7bf7a668b452f18def89f2e2285acd315fc00668fe0a70b2103bd4632ebd0de4573710722bf73b4bbb76713734c4756b830302b8492f29a6aae53ae"
},
{
"comment": "Invalid base key length in tweak map",
"expected": false,
"tweak_map": {
"02a047233eec59cf06b9a5ee62d9088eeb8127201423f88637443ff7ee591923": "6e4dd29833f7b88751dad6ea6ff536959122f2d07074006657d0e2ef26af3ef6",
"0386623c88ed79ef5d9aacd24f227a0cd845f5840b861a25118c1200cccd046e0f": "b30d8530e3464dc71ed6e20897ef5c3c9d1149ecc11f332336520addab1454f3",
"03c3c01af1d84ec032f7f8d6decd48d74cbbd62253e12691debd064e8b41cb0945": "c1efff9fb89227d09e54b403ae269f1991003e964f66f412e8302f8bb1c71644"
},
"witness_script": "5221034ebf1d6b674fbf3d7ff09e4bc44b23e17745188b4aac3e2e101bd210cd8f3ed42103a0d8aed25b77d286d7bf7a668b452f18def89f2e2285acd315fc00668fe0a70b2103bd4632ebd0de4573710722bf73b4bbb76713734c4756b830302b8492f29a6aae53ae"
}
]
}
================================================
FILE: bip-0089/vectors/unblind_signature_vectors.json
================================================
{
"valid_test_cases": [
{
"session_ctx": {
"pk": "03A1B69A6C047657AA6A0DF9ED43E5B0CA75097260F065048606D0946B2B89A6AD",
"blindfactor": "D08134A1CA8F716EE99EE69179BD939CF2DCD29D3EB1827124BAEB1364088AA9",
"challenge": "0AB1D307369FB4D994A8DEDE3D503FDC7B8AF459AECE3C69B5C22F5BFA293618",
"pubnonce": "02ED7E7EB4E886F9A9DF4E375F5F9321DCF5AA909B85A028B7EBB14F2ED80AE3BD",
"tweaks": ["1956DF466B657FFA287B6BFC63219BB6BF3D5A72ECE44E43E14091CBF15100BB", "2CB93A737A3B9A86D678DD8060ECA5443978B87BA54CFC21AE1341B47C2640B9"],
"is_xonly": [false, true]
},
"msg": "28431125D79E16223AAF5401267447B8729324613B74A3A1DFD4EE8E277B5C40",
"blindsignature": "6180428458B0EDA605A2D897A45784C399D310060FD0BE701DA4AE5B2EEB7A40",
"expected_bip340_sig": "ED7E7EB4E886F9A9DF4E375F5F9321DCF5AA909B85A028B7EBB14F2ED80AE3BD1A606D2DE092BD1A05B82532BDEA7F11493D00EB1109CF1EF30A8D8E2FF2721C"
}
],
"error_test_cases": [
{
"session_ctx": {
"pk": "03A1B69A6C047657AA6A0DF9ED43E5B0CA75097260F065048606D0946B2B89A6AD",
"blindfactor": "D08134A1CA8F716EE99EE69179BD939CF2DCD29D3EB1827124BAEB1364088AA9",
"challenge": "0AB1D307369FB4D994A8DEDE3D503FDC7B8AF459AECE3C69B5C22F5BFA293618",
"pubnonce": "04ED7E7EB4E886F9A9DF4E375F5F9321DCF5AA909B85A028B7EBB14F2ED80AE3BD",
"tweaks": ["1956DF466B657FFA287B6BFC63219BB6BF3D5A72ECE44E43E14091CBF15100BB", "2CB93A737A3B9A86D678DD8060ECA5443978B87BA54CFC21AE1341B47C2640B9"],
"is_xonly": [false, true]
},
"msg": "28431125D79E16223AAF5401267447B8729324613B74A3A1DFD4EE8E277B5C40",
"blindsignature": "6180428458B0EDA605A2D897A45784C399D310060FD0BE701DA4AE5B2EEB7A40",
"error": { "type": "ValueError" },
"comment": "Bad pubnonce encoding"
},
{
"session_ctx": {
"pk": "03A1B69A6C047657AA6A0DF9ED43E5B0CA75097260F065048606D0946B2B89A6AD",
"blindfactor": "D08134A1CA8F716EE99EE69179BD939CF2DCD29D3EB1827124BAEB1364088AA9",
"challenge": "0AB1D307369FB4D994A8DEDE3D503FDC7B8AF459AECE3C69B5C22F5BFA293618",
"pubnonce": "04ED7E7EB4E886F9A9DF4E375F5F9321DCF5AA909B85A028B7EBB14F2ED80AE3BD",
"tweaks": ["1956DF466B657FFA287B6BFC63219BB6BF3D5A72ECE44E43E14091CBF15100BB", "2CB93A737A3B9A86D678DD8060ECA5443978B87BA54CFC21AE1341B47C2640B9"],
"is_xonly": [true]
},
"msg": "28431125D79E16223AAF5401267447B8729324613B74A3A1DFD4EE8E277B5C40",
"blindsignature": "6180428458B0EDA605A2D897A45784C399D310060FD0BE701DA4AE5B2EEB7A40",
"error": { "type": "ValueError", "message": "must have the same length" },
"comment": "tweaks/is_xonly length mismatch"
},
{
"session_ctx": {
"pk": "03A1B69A6C047657AA6A0DF9ED43E5B0CA75097260F065048606D0946B2B89A6AD",
"blindfactor": "D08134A1CA8F716EE99EE69179BD939CF2DCD29D3EB1827124BAEB1364088AA9",
"challenge": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
"pubnonce": "04ED7E7EB4E886F9A9DF4E375F5F9321DCF5AA909B85A028B7EBB14F2ED80AE3BD",
"tweaks": ["1956DF466B657FFA287B6BFC63219BB6BF3D5A72ECE44E43E14091CBF15100BB", "2CB93A737A3B9A86D678DD8060ECA5443978B87BA54CFC21AE1341B47C2640B9"],
"is_xonly": [true]
},
"msg": "28431125D79E16223AAF5401267447B8729324613B74A3A1DFD4EE8E277B5C40",
"blindsignature": "6180428458B0EDA605A2D897A45784C399D310060FD0BE701DA4AE5B2EEB7A40",
"error": { "type": "ValueError" },
"comment": "challenge out of range"
}
]
}
================================================
FILE: bip-0089.mediawiki
================================================
== Abstract ==
Chain Code Delegation (CCD) is a method for multi-signature wallets in which a privileged participant withholds BIP32 chain codes from one or more non-privileged participants, and supplies per-input scalar tweaks at signing time. This allows non-privileged participants to co-sign transactions without learning wallet-wide derivations, balances, or signing activity from other spending combinations. CCD defines the tweak exchange needed for verification and signing behavior when the signer does not possess a chain code.
== Motivation ==
In multisig deployments, sharing extended public keys (xpubs) or descriptors enables all participants to scan the chain and infer counterparties' activity. CCD limits that visibility by ensuring non-privileged participants only ever hold a non-extended keypair and only receive the minimum per-spend data needed to sign. The procedure keeps policy enforcement feasible for the non-privileged signer while preserving balance privacy, which is particularly useful in collaborative custody arrangements where the wallet owner wants balance privacy from their custodian.
== Terminology ==
In CCD, the chain code is the object of delegation—not signing authority. A participant who gives up their chain code delegates it to another.
* A "Delegator" is a participant who delegates their chain code to another party. They hold only a non-extended keypair and receive scalar tweaks from the delegatee when asked to sign.
* A "Delegatee" is a participant who receives and retains a delegated chain code for another participant's public key, and computes derivation tweaks for that participant.
* A "Participant" is any key holder that can co-sign for UTXOs in the wallet (including delegators and delegatees).
* A "Non-hardened derivation" is a BIP32 child derivation where index < 2^31.
== Overview ==
CCD operates by having Delegatees deprive Delegators of BIP32 chain codes during setup and later conveying the aggregated scalar tweak computed as the sum of non-hardened derivation tweaks along the remaining path to the child key used by a given input or change output. A Delegator uses the tweak to compute the child keys for verification and signing without being able to derive or recognize keys for other paths.
== Specification ==
=== Key material and setup ===
* '''Delegator key:''' Each delegator generates a standard (non-extended) secp256k1 keypair and provides the public key to the counterparties. A delegator MUST NOT retain or be provided a chain code for this key.
* '''Delegated chain code:''' A designated delegatee computes and retains a BIP32 chain code bound to the delegator's public key, forming an xpub that MUST NOT be disclosed to the delegator. The delegatee MAY share this xpub with other delegatees.
* '''Other participants:''' Non-delegator participants use conventional extended keys and share the public half as appropriate for the wallet descriptor.
* '''Derivation constraints:''' The delegatee holds an extended public key for the delegator. All derivation from this extended key MUST be non-hardened, as hardened derivation requires the private key, which the delegatee does not possess.
=== Notation ===
The following conventions are used, with constants as defined for [https://www.secg.org/sec2-v2.pdf secp256k1]. We note that adapting this proposal to other elliptic curves is not straightforward and can result in an insecure scheme.
* Lowercase variables represent integers or byte arrays.
** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''.
** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''.
* Uppercase variables refer to points on the curve with equation ''y2 = x3 + 7'' over the integers modulo ''p''.
** ''is_infinite(P)'' returns whether ''P'' is the point at infinity.
** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity).
** The constant ''G'' refers to the base point, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''.
** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation].
** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication (⋅) of an integer and a point] refers to the repeated application of the group operation.
* Functions and operations:
** ''||'' refers to byte array concatenation.
** The function ''x[i:j]'', where ''x'' is a byte array and ''i, j ≥ 0'', returns a ''(j - i)''-byte array with a copy of the ''i''-th byte (inclusive) to the ''j''-th byte (exclusive) of ''x''.
** The function ''bytes(n, x)'', where ''x'' is an integer, returns the n-byte encoding of ''x'', most significant byte first.
** The constant ''empty_bytestring'' refers to the empty byte array. It holds that ''len(empty_bytestring) = 0''.
** The function ''xbytes(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''bytes(32, x(P))''.
** The function ''len(x)'' where ''x'' is a byte array returns the length of the array.
** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 == 0''.
** The function ''with_even_y(P)'', where ''P'' is a point, returns ''P'' if ''is_infinite(P)'' or ''has_even_y(P)''. Otherwise, ''with_even_y(P)'' returns ''-P''.
** The function ''cbytes(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''a || xbytes(P)'' where ''a'' is a byte that is ''2'' if ''has_even_y(P)'' and ''3'' otherwise.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..2256-1'', returns the point ''P'' for which ''x(P) = x''
Given a candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''. and ''has_even_y(P)'', or fails if ''x'' is greater than ''p-1'' or no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Fail if ''x > p-1''.
*** Let ''c = x3 + 7 mod p''.
*** Let ''y' = c(p+1)/4 mod p''.
*** Fail if ''c ≠ y'2 mod p''.
*** Let ''y = y' '' if ''y' mod 2 = 0'', otherwise let ''y = p - y' ''.
*** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y''.
** The function ''cpoint(x)'', where ''x'' is a 33-byte array (compressed serialization), sets ''P = lift_x(int(x[1:33]))'' and fails if that fails. If ''x[0] = 2'' it returns ''P'' and if ''x[0] = 3'' it returns ''-P''. Otherwise, it fails.
** The function ''hash256tag(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)''.
** The function ''hash512tag(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 64-byte hash ''SHA512(SHA512(tag) || SHA512(tag) || x)''.
* Other:
** Tuples are written by listing the elements within parentheses and separated by commas. For example, ''(2, 3, 1)'' is a tuple.
=== Tweak Calculation ===
To produce CCD tweak data, a delegatee computes a per-participant scalar that aggregates the non-hardened derivation tweaks along the remaining path. Let the extended key retained by the delegatee be P at depth d, and let the target index vector be I = (id+1, …, in) with each ik < 231.
Algorithm ''ComputeBIP32Tweak(P, I)'':
* Inputs:
** ''P'': base public key at depth ''d''
** ''I = (id+1, …, in)'': ordered sequence of non-hardened child indices
* Let ''t = 0'' and ''E = P''.
* For each index ''i'' in ''I'' (from left to right):
** Run the BIP32 non-hardened derivation ''CKDpub'' on ''E'' with child index ''i'', yielding the child extended key ''Pchild'' and its scalar tweak ''δ'' (the parse256(''IL'') term from BIP32).
** Let ''t = (t + δ) mod n''.
** Let ''E = Pchild''.
* If ''I'' is empty, let ''P′ = P''; otherwise let ''P′ = Pchild'' from the final iteration.
* Return ''(t, P′)''.
Any attempt to apply a hardened derivation (index ≥ 231) MUST fail. Delegatees MAY discard P′ after extracting t if it is not otherwise required.
=== Delegation Bundle ===
CCD requires the delegatee to provide per-participant tweaks for inputs and (optionally) change outputs. Tweaks for change outputs are only required if a delegator wants to be able to compute the amount of bitcoin they are spending.
A delegatee MUST provide each delegator with, for every signing context, a collection of tuples (Pi, ti) where Pi is the participant's base public key disclosed to the delegator and ti is the aggregated tweak returned by ''ComputeBIP32Tweak''. The scalar ti MUST be encoded as a 32-byte big-endian integer.
The transport that carries this bundle is out of scope for this proposal; implementers MAY use PSBT proprietary keys, RPC payloads, or bespoke messages as long as the delegator can authenticate the origin of the data. Delegatees SHOULD attach the witness script (or sufficient script template information) built with the tweaked keys when the delegator is expected to verify the input or enforce spending policy on change outputs.
Delegators use the supplied CCD tweak bundle during verification (see ''Delegator input and change verification'') and signature generation (see ''DelegatorSign''). The message to be signed is provided separately as part of the standard signing protocol and is not part of the CCD-specific bundle.
=== Signing Modes ===
This BIP supports two modes:
* '''Non‑blinded.''' The delegator receives the tweak for the child public key and the message. The delegator learns only about the specific child keys and transactions it signs for; it does not learn the wider address space.
* '''Blinded.''' The delegator receives only a blinded challenge and parity bits. The delegator learns nothing about the message or child key for which it produces a signature.
Both modes produce valid BIP340 signatures.
====Non-Blinded Signing====
For non-blinded signing, the delegator can produce signatures as usual using the tweaked key.
=====Delegator input and change verification (Optional)=====
A delegator MAY validate the data it receives before producing signatures.
For example, input verification reassures the delegator that every tweaked key they are asked to sign for corresponds to a wallet input they recognise. Change verification lets them establish the net outflow and enforce spending policy.
Both checks rely on the same delegated tweak bundle described above.
=====Input verification=====
For each input, the delegatee SHOULD disclose the descriptor template, the untweaked participant keys, the input witness script, and the per-participant tweaks. The delegator then applies the following procedure.
Algorithm ''InputVerification(D, W, T)'':
* Inputs:
** ''D'': wallet policy or descriptor template expressed in terms of the untweaked participant keys ''Pi''
** ''W'': witness script disclosed for the input under review
** ''T'': mapping from each ''Pi'' to a 32-byte big-endian tweak scalar ''ti''
* For each participant key ''Pi'' referenced in ''D'':
** Retrieve ''ti'' from ''T''; fail if the entry is missing or malformed.
** If the verifier controls the corresponding private key ''di'', let ''d′i = (di + ti) mod n'' and ''P′i = d′i · G''; otherwise let ''P′i = Pi + ti · G''.
* Let ''D′'' be the descriptor formed by substituting every occurrence of ''Pi'' in ''D'' with ''P′i''.
* Derive the witness script ''W′'' from ''D′''.
* Return true if ''W′ = W'', otherwise false.
Successful verification of an input confirms that the delegator is signing for a script that belongs to the wallet and that the aggregate tweak values align with the expected policy.
=====Change-output verification=====
When change outputs are disclosed, the delegator can perform an analogous check to ensure the destination script matches their policy template and to calculate outflows. Let D be the descriptor expressed in untweaked keys, W the provided witness script, and T the tweak mapping:
Algorithm ''ChangeOutputVerification(D, W, T)'':
* Inputs:
** ''D'': wallet policy or descriptor template expressed in terms of the untweaked participant keys ''Pi''
** ''W'': witness script disclosed for the change output
** ''T'': mapping from each ''Pi'' to a 32-byte big-endian tweak scalar ''ti''
* For each participant key ''Pi'' referenced in ''T'':
** Retrieve ''ti'' from ''T''; fail if the entry is missing or malformed.
** If the verifier controls the corresponding private key ''di'', let ''d′i = (di + ti) mod n'' and ''P′i = d′i · G''; otherwise let ''P′i = Pi + ti · G''.
* Let ''D′'' be the descriptor formed by substituting every occurrence of ''Pi'' in ''D'' with ''P′i''.
* Derive the witness script ''W′'' from ''D′''.
* Return true if ''W′ = W'', otherwise false.
Successful verification ensures the change output commits to the tweaked participant keys implied by the CCD tweaks, preserving the intended policy.
The delegator may perform additional application-specific verification on the transaction (e.g., recipient addresses, amounts, compliance checks) using the message ''m''. In the concurrently secure blinded mode, such policies can be enforced via zero-knowledge proofs that encode predicates about ''m''. Specification of such policies is outside the scope of this BIP.
=====Delegator Signing=====
A delegator that holds only its base secret key x and public key P uses the delegated tweak bundle to derive per-input signing keys. The delegator MAY first call ''InputVerification'' and ''ChangeOutputVerification'' on any input and change output that provides a tweak in order to confirm outflow or policy requirements before signing.
Algorithm ''DelegatorSign(t, x, m)'':
* Inputs:
** ''t'': aggregated tweak for the signing context (scalar mod ''n'')
** ''x'': delegator base secret key
** ''m'': message to be signed (for example, a transaction digest under the desired SIGHASH policy)
* Let ''x′ = (x + t) mod n''.
* Use secret key ''x′'' to produce the required signature ''σ'' under the indicated policy.
* Return ''σ''.
The delegatee is responsible for inserting ''σ'' into the surrounding protocol (e.g., a PSBT, transaction witness, or adaptor signature exchange).
====Blinded Signing====
The delegator learns neither the message, the challenge, or the public key used in the BIP340 signature, only a blinded challenge e'.
This blind‑signing protocol specifies how a delegator can produce a blind partial Schnorr signature that a delegatee can unblind into a standard [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] signature under a possibly tweaked X‑only public key. The notation, algorithmic patterns, and test‑vector style are adapted from [BIP‑327 (MuSig2)] and from the [https://github.com/siv2r/bip-frost-signing FROST Signing BIP]. The design follows the “plain” blind Schnorr flow described in Concurrently Secure Blind Schnorr Signatures ([https://eprint.iacr.org/2022/1676 ePrint 2022/1676]), but without the concurrency hardening from that work.
The output signature is a BIP340 Schnorr signature valid under an X‑only key obtained by applying a sequence of plain (e.g. BIP32) and X‑only (e.g. Tapscript) tweaks to the signer’s plain public key. Consequently the protocol is compatible with [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341]. The delegator learns neither the message, the challenge, or the public key used in the BIP340 signature, only a blinded challenge e'.
The plain protocol here is '''not''' concurrently secure. A signer '''MUST NOT''' run multiple blind signing sessions in parallel or interleave state across sessions. A signer '''MUST''' refuse any new blind‑nonce requests while a previous blind‑signature request is outstanding, or '''MUST''' irrevocably discard (and never reuse) any in‑flight blind nonce commitments that have not resulted in a signature, before accepting new ones.
To obtain concurrency security as in ([https://eprint.iacr.org/2022/1676 ePrint 2022/1676]), the delegatee first sends an encryption of (m, a, b) before the signer commits to the blind nonce; later, the delegatee includes a zero‑knowledge proof binding the produced challenge to that encrypted tuple. That proof can additionally encode policy predicates about m (spend limits, velocity controls, etc.). A complete specification of this variant is outside the scope of this BIP.
The following sections fully specify the non-concurrent blind signing protocol.
===== Overview =====
* '''Round 1 (blind nonce).''' The delegator runs ''BlindNonceGen'' to produce ''blindsecnonce'' and ''blindpubnonce'' and sends ''blindpubnonce'' to the delegatee.
* '''Round 2 (challenge).''' The delegatee runs ''BlindChallengeGen'' using the message ''m'', ''blindpubnonce'', the base public key ''pk'', and a list of ordinary and X-only tweaks, to produce a ''session context'' (kept locally for unblinding), a ''blindchallenge'', and two booleans ''pk_parity'' and ''nonce_parity''. The delegatee sends ''blindchallenge'', ''pk_parity'', and ''nonce_parity'' to the signer.
* '''Round 3 (blind signature).''' The delegator runs ''BlindSign'' with ''sk'', ''blindchallenge'', ''blindsecnonce'', ''pk_parity'', and ''nonce_parity'' and returns ''blindsignature''. The delegatee completes by calling ''UnblindSignature'' with the stored session context and ''blindsignature'' to obtain the final BIP340 signature ''sig''.
''BlindSign'' '''MUST NOT''' be executed twice with the same ''blindsecnonce''. As a defense, implementations '''SHOULD''' overwrite the first 64 bytes of ''blindsecnonce'' with zeros after they have been read by ''BlindSign''.
=====Key Tweaking=====
======Tweak Context======
The Tweak Context is a data structure consisting of the following elements:
* The point ''Q'' representing the potentially tweaked public key: an elliptic curve point
* The accumulated tweak ''tacc'': an integer with ''0 ≤ tacc < n''
* The value ''gacc'' : 1 or -1 mod n
We write "Let ''(Q, gacc, tacc) = tweak_ctx''" to assign names to the elements of a Tweak Context.
Algorithm ''TweakCtxInit(pk)'':
* Input:
** The base public key pk: a 33-byte array
* Let ''Q = cpoint(pk)''
* Fail if ''is_infinite(Q)''
* Let ''gacc = 1''
* Let ''tacc = 0''
* Return ''tweak_ctx = (Q, gacc, tacc)''
Algorithm ''ApplyTweak(tweak_ctx, tweak, is_xonly_t)'':
* Inputs:
** The ''tweak_ctx'': a [[#tweak-context|Tweak Context]] data structure
** The ''tweak'': a 32-byte array
** The tweak mode ''is_xonly_t'': a boolean
* Let ''(Q, gacc, tacc) = tweak_ctx''
* If ''is_xonly_t'' and ''not has_even_y(Q)'':
** Let ''g = -1 mod n''
* Else:
** Let ''g = 1''
* Let ''t = int(tweak)''; fail if ''t ≥ n''
* Let ''Q' = g⋅Q + t⋅G''
** Fail if ''is_infinite(Q')''
* Let ''gacc' = g⋅gacc mod n''
* Let ''tacc' = t + g⋅tacc mod n''
* Return ''tweak_ctx' = (Q', gacc', tacc')''
=====Blind Nonce Generation=====
Algorithm ''BlindNonceGen(sk, pk, aggpk, m, extra_in)'':
* Inputs:
** The base secret signing key ''sk'': a 32-byte array (optional argument)
** The base public key ''pk'': a 33-byte array (optional argument)
** The auxiliary input ''extra_in'': a byte array with ''0 ≤ len(extra_in) ≤ 232-1'' (optional argument)
* Let ''rand' '' be a 32-byte array freshly drawn uniformly at random
* If the optional argument ''sk'' is present:
** Let ''rand'' be the byte-wise xor of ''sk'' and ''hash256CCD/aux(rand')''The random data is hashed (with a unique tag) as a precaution against situations where the randomness may be correlated with the secret signing key itself. It is xored with the secret key (rather than combined with it in a hash) to reduce the number of operations exposed to the actual secret key.
* Else:
** Let ''rand = rand' ''
* If the optional argument ''extra_in'' is not present:
** Let ''extra_in = empty_bytestring''
* Let ''k' = int(hash256CCD/blindnonce(rand || bytes(1, len(pk)) || pk || bytes(4, len(extra_in)) || extra_in )) mod n''
* Fail if ''k' = 0''
* Let ''R' = k'⋅G''
* Let ''blindpubnonce = cbytes(R')''
* Let ''blindsecnonce = bytes(32, k' || pk)''The algorithms as specified here assume that the ''blindsecnonce'' is stored as a 65-byte array using the serialization ''blindsecnonce = bytes(32, k') || pk''. The same format is used in the reference implementation and in the test vectors. However, since the ''blindsecnonce'' is not meant to be sent over the wire, compatibility between implementations is not a concern, and this method of storing the ''blindsecnonce'' is merely a suggestion.
The ''blindsecnonce'' is effectively a local data structure of the signer which comprises the value double ''(k', pk)'', and implementations may choose any suitable method to carry it from ''BlindNonceGen'' (first communication round) to ''BlindSign'' (third communication round). In particular, implementations may choose to hide the ''blindsecnonce'' in internal state without exposing it in an API explicitly, e.g., in an effort to prevent callers from reusing a ''blindsecnonce'' accidentally.
* Return ''(secnonce, pubnonce)''
=====Session Context=====
The Session Context is a data structure consisting of the following elements:
* The base public key ''pk'': a 33-byte array
* The blind factor ''blindfactor'': a 32-byte array
* The challenge hash ''challenge'': a 32-byte array
* The public nonce ''pubnonce'': a 33-byte array
* The number ''v'' of tweaks with ''0 ≤ v < 2^32''
* The tweaks ''tweak1..v'': ''v'' 32-byte arrays
* The tweak modes ''is_xonly_t1..v'' : ''v'' booleans
We write "Let ''(pk, blindfactor, challenge, pubnonce, v, tweak1..v, is_xonly_t1..v) = session_ctx''" to assign names to the elements of a Session Context.
Algorithm ''GetSessionValues(session_ctx)'':
* Let ''(pk, blindfactor, challenge, pubnonce, v, tweak1..v, is_xonly_t1..v) = session_ctx''
* Let ''tweak_ctx0 = TweakCtxInit(pk)''; fail if that fails
* For ''i = 1 .. v'':
** Let ''tweak_ctxi = ApplyTweak(tweak_ctxi-1, tweaki, is_xonly_ti)''; fail if that fails
* Let ''(Q, gacc, tacc) = tweak_ctxv''
* Let ''a = int(blindfactor)''; fail if ''a ≥ n''
* Let ''b = int(blindfactor)''; fail if ''b ≥ n''
* Let ''e = int(challenge)''; fail if ''e ≥ n''
* Let ''R = cpoint(pubnonce)''; fail if that fails
* Return ''(Q, gacc, tacc, a, e, R)''
=====Blind Challenge Generation=====
Algorithm ''BlindChallengeGen(m, blindpubnonce, pk, tweak1..v, is_xonly1..v, extra_in)'':
* Inputs:
** The message ''m'': a byte array
** The blind public nonce ''blindpubnonce'': a 33-byte array
** The base public key ''pk'': a 33-byte array
** The tweaks ''tweak1..v'': ''v'' 32-byte arrays
** The tweak modes ''is_xonly1..v'': ''v'' booleans
** The auxiliary input ''extra_in'': a byte array with ''0 ≤ len(extra_in) ≤ 232-1'' (optional argument)
* If ''extra_in'' is not present:
** Let ''extra_in = empty_bytestring''
* Let ''(Q, gacc, tacc) = TweakCtxInit(pk)''
* For ''i = 1 .. v'':
** Let ''(Q, gacc, tacc) = ApplyTweak((Q, gacc, tacc), tweaki, is_xonlyi)''; fail if that fails
* Let ''cpk = cbytes(Q)''
* Draw 32 random bytes ''rand''
* Let ''z = hash512CCD/blindfactor(rand || bytes(1, len(cpk)) || cpk || bytes(1, len(blindpubnonce)) || blindpubnonce || bytes(8, len(m)) || m || bytes(4, len(extra_in)) || extra_in)''
* Let ''a' = int(z[0:32]) mod n''; fail if ''a' = 0''
* Let ''b' = int(z[32:64]) mod n''; fail if ''b' = 0''
* Let ''g = 1'' if ''has_even_y(Q)'', else ''g = −1 mod n''
* Let ''pk_parity = (g⋅gacc mod n == 1)''
* Let ''X' = cpoint(pk)''; let ''X = X' '' if ''pk_parity'' else ''−X' ''
* Let ''R' = cpoint(blindpubnonce)''
* Let ''R = R' + a'⋅G + b'⋅X''; fail if ''is_infinite(R)''
* Let ''nonce_parity = has_even_y(R)''
* If ''nonce_parity'':
** Let ''a = a' '', ''b = b' ''
* Else:
** Let ''a = n − a' '', ''b = n − b' ''
* Let ''e = int(hashBIP0340/challenge(xbytes(R) || xbytes(Q) || m)) mod n''
* Let ''e' = (e + b) mod n''
* Let ''session_ctx = (pk, bytes(32, a), bytes(32, e), cbytes(R), tweak1..v, is_xonly1..v)''
* Return ''(session_ctx, bytes(32, e'), pk_parity, nonce_parity)''
=====Blind Signing=====
Algorithm ''BlindSign(sk, blindchallenge, blindsecnonce, pk_parity, nonce_parity)'':
* Inputs:
** The secret key ''sk'': a 32-byte array
** The blind challenge ''blindchallenge'': a 32-byte array ''e' ''
** The secret nonce ''blindsecnonce'': a byte array whose first 32 bytes are ''k'' (remaining bytes are implementation-defined)
** ''pk_parity'': boolean (from ''BlindChallengeGen'')
** ''nonce_parity'': boolean (from ''BlindChallengeGen'')
* Let ''d' = int(sk)''; fail if ''d' = 0'' or ''d' ≥ n''
* Let ''P = d'⋅G''; fail if ''is_infinite(P)''
* Let ''d = d' '' if ''pk_parity'' else ''n − d' ''
* Let ''e' = int(blindchallenge)''; fail if ''e' ≥ n''
* Let ''k' = int(blindsecnonce[0:32])''; fail if ''k' = 0'' or ''k' ≥ n''
* Let ''k = k' '' if ''nonce_parity'' else ''n − k' ''
* Overwrite ''blindsecnonce[0:64]'' with 64 zero bytes This helps prevent accidental nonce reuse. A zeroed ''blindsecnonce'' MUST cause subsequent ''BlindSign'' calls to fail.
* Let ''R' = k'⋅G''; fail if ''is_infinite(R')'' This check holds except with negligible probability.
* Let ''s' = (k + e'⋅d) mod n''
* If ''VerifyBlindSignature(cbytes(P), cbytes(R'), blindchallenge, bytes(32, s'), pk_parity, nonce_parity)'' returns failure, abort
* Return ''blindsignature = bytes(32, s')''
Algorithm ''VerifyBlindSignature(pk, blindpubnonce, blindchallenge, blindsignature, pk_parity, nonce_parity)'':
* Inputs:
** ''pk'': a 33-byte compressed public key
** ''blindpubnonce'': the signer’s 33-byte ''R' = k'⋅G''
** ''blindchallenge'': 32-byte ''e' ''
** ''blindsignature'': 32-byte ''s' ''
** ''pk_parity, nonce_parity'': booleans
* Let ''P' ' = cpoint(pk)''; let ''P = P' '' if ''pk_parity'' else ''−P' '' ; fail if ''is_infinite(P)''
* Let ''R' ' = cpoint(blindpubnonce)''; let ''R = R' '' if ''nonce_parity'' else ''−R' ''
* Let ''e' = int(blindchallenge)'', ''s' = int(blindsignature)''
* Return success iff ''s'⋅G == R + e'⋅P''
=====Unblinding=====
Algorithm ''UnblindSignature(session_ctx, blindsignature)'':
* Inputs:
** ''session_ctx'': as defined above
** ''blindsignature'': the 32-byte ''s' '' returned by the signer
* Let ''(Q, gacc, tacc, a, e, R) = GetSessionValues(session_ctx)''; fail if that fails
* Let ''g = 1'' if ''has_even_y(Q)'', else ''g = −1 mod n''
* Let ''s' = int(blindsignature)''; fail if ''s' ≥ n''
* Let ''s = (s' + a + e⋅g⋅tacc) mod n''
* Return the BIP340 signature ''sig = xbytes(R) || bytes(32, s)''
== Security Considerations ==
* Exposure of any delegated tweak scalar t enables signing only for the specific child key(s) that scalar was derived for, and is typically short-lived if disclosed immediately before spending.
* Delegatees MUST ensure every delegated path remains non-hardened and that ''ComputeBIP32Tweak'' yields the correct tweak t; incorrect scalars could render the delegator incapable of producing a signature.
* Delegators MUST verify change outputs when tweak data is provided (for example via ''ChangeOutputVerification'') to avoid authorizing unexpected scripts.
* Reusing the same k' (first 32 bytes in blindsecnonce) across two BlindSign calls allows recovery of the base secret key.
* When using blinded signing, opening multiple sessions concurrently against the same signer can allow an attacker to learn the base secret key. If concurrency is required, use the concurrently secure variant (encryption + ZK) instead (not specified in this BIP).
== Test Vectors ==
A [[bip-0089/vectors|collection of JSON test vectors]] are provided, along with a [[bip-0089/reference.py|python reference implementation]].
It uses a vendored copy of the [https://github.com/secp256k1lab/secp256k1lab/ secp256k1lab] library
(commit [https://github.com/secp256k1lab/secp256k1lab/commit/a265da139aea27386085a2a8760f8698e1bda64e
a265da139aea27386085a2a8760f8698e1bda64e]).
You may also find example code of CCD in action [https://github.com/jurvis/chaincode-delegation here].
== Changelog ==
* '''0.1.3''' (2026-02-02): Upgrade secp256k1lab and add license file; fix type checker and linter issues; clarify Delegator/Delegatee terminology, derivation constraints, signing modes, and verification scope.
* '''0.1.2''' (2025-12-03): Updated to reflect BIP number assignment.
* '''0.1.1''' (2025-11-30): Fix acknowledgments spelling, BIP3 formatting, and use "Chain Code" with a space throughout.
* '''0.1.0''' (2025-10-14): Publication of draft BIP
== Acknowledgements ==
* Arik Sosman and Wilmer Paulino for the initial discussions and validation of this idea.
* Sanket Kajalkar, Jordan Mecom, Gregory Sanders, ZmnSCPxj, Yuval Kogman, and John Cantrell for code and design review.
== Copyright ==
This BIP is licensed under the BSD 3-Clause license.
================================================
FILE: bip-0090.mediawiki
================================================
BIP: 90
Title: Buried Deployments
Authors: Suhas Daftuar
Comments-Summary: Mostly Recommended for implementation, with some Discouragement
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0090
Status: Deployed
Type: Informational
Assigned: 2016-11-08
License: PD
==Abstract==
Prior soft forks (BIP 34, BIP 65, and BIP 66) were activated via miner signaling in block version numbers. Now that the chain has long since passed the blocks at which those consensus rules have triggered, we can (as a simplification) replace the trigger mechanism by caching the block heights at which those consensus rules became enforced.
==Motivation==
BIPs 34, 65 and 66 were deployed on mainnet using miner signaling using block version numbers. In short, new consensus rules were proposed for use in blocks with a higher version number (N+1) than the prevailing block version (N) in use on the network, and those rules became enforced under the following conditions:
# 75% rule: If 750 of the prior 1000 blocks are version N+1 or higher, then blocks with version N+1 or higher must correctly enforce the new consensus rule.
# 95% rule: If 950 of the prior 1000 blocks are version N+1 or higher, then blocks with version less than N+1 are invalid.
Please see those [[#References|BIPs]] for more details.
Note that this trigger mechanism is dependent on the chain history. To validate a block, we must test whether the trigger was met by looking at the previous 1000 blocks in the chain before it, which can be inefficient.
In addition, this mechanism for code deployments have been deprecated in favor of BIP 9 deployments, which offer several advantages (please see [https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP 9]).
Thus we propose elimination of the logic implementing these kinds of deployments, by replacing the test which governs enforcement of BIP 34, BIP 65, and BIP 66 with simple height checks, which we choose to be the block height triggering the 95% activation rule on mainnet for each of those deployments. This simplification of the consensus rules would reduce the technical debt associated with deployment of those consensus changes.
==Considerations==
It is technically possible for this to be a non-backwards compatible change. For example, if an alternate chain were created in which BIP 34's 95% activation triggered at a lower height (H') than it did on the current mainnet chain (H), then older software would enforce that version 1 blocks were invalid at heights between H' and H, while newer software implementing this change would not. Similarly, this BIP proposes doing away with the 75% threshold check altogether, which means, for example, that a version 2 block forking off of mainnet at height H-1 which omitted the height in coinbase would be invalid to older software, while accepted by newer software.
However, while newer software and older software might validate old blocks differently, that could only cause a consensus split if there were an extremely large blockchain reorganization onto a chain built off such a block. As of November 2016, the most recent of these changes (BIP 65, enforced since December 2015) has nearly 50,000 blocks built on top of it. The occurrence of such a reorg that would cause the activating block to be disconnected would raise fundamental concerns about the security assumptions of Bitcoin, a far bigger issue than any non-backwards compatible change.
So while this proposal could theoretically result in a consensus split, it is extremely unlikely, and in particular any such circumstances would be sufficiently damaging to the Bitcoin network to dwarf any concerns about the effects of this proposed change.
==Specification==
The BIP 34, 66, and 65 activation heights are set to 227931, 363725, and 388381, respectively.
The 1000-block lookback test, first described in BIP 34, is no longer performed during validation of any blocks. Instead, a new check is added:
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion),
strprintf("rejected nVersion=0x%08x block", block.nVersion));
Furthermore, rather than consider the block versions of the prior 1000 blocks to determine whether to enforce BIP 34, BIP 65, or BIP 66 on a given block, we instead just compare the height of the block being validated with the stored activation heights:
// Enforce rule that the coinbase starts with serialized block height
if (nHeight >= consensusParams.BIP34Height)
{
CScript expect = CScript() << nHeight;
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase");
}
}
and
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= chainparams.GetConsensus().BIP66Height) {
flags |= SCRIPT_VERIFY_DERSIG;
}
// Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule
if (pindex->nHeight >= chainparams.GetConsensus().BIP65Height) {
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}
Please see the implementation for additional details.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/8391.
==References==
[https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki BIP34 Block v2, Height in Coinbase]
[https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66 Strict DER signatures]
[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP65 OP_CHECKLOCKTIMEVERIFY]
[https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP9 Version bits with timeout and delay]
==Acknowledgements==
Thanks to Nicolas Dorier for drafting an initial version of this BIP, and to Alex Morcos, Matt Corallo, and Greg Maxwell for suggestions and feedback.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0091.mediawiki
================================================
==Abstract==
This document specifies a method to activate the existing BIP9 segwit deployment with a majority hashpower less than 95%.
==Definitions==
"existing segwit deployment" refer to the BIP9 "segwit" deployment using bit 1, between November 15th 2016 and November 15th 2017 to activate BIP141, BIP143 and BIP147.
==Motivation==
Segwit increases the blocksize, fixes transaction malleability, and makes scripting easier to upgrade as well as bringing many other [https://bitcoincore.org/en/2016/01/26/segwit-benefits/ benefits].
This BIP provides a way for a simple majority of miners to coordinate activation of the existing segwit deployment with less than 95% hashpower. For a number of reasons a complete redeployment of segwit is difficult to do until the existing deployment expires. This is due to 0.13.1+ having many segwit related features active already, including all the P2P components, the new network service flag, the witness-tx and block messages, compact blocks v2 and preferential peering. A redeployment of segwit will need to redefine all these things and doing so before expiry would greatly complicate testing.
==Specification==
While this BIP is active, all blocks must set the nVersion header top 3 bits to 001 together with bit field (1<<1) (according to the existing segwit deployment). Blocks that do not signal as required will be rejected.
==Deployment==
This BIP will be deployed by a "version bits" with an 80%(this can be adjusted if desired) 269 block activation threshold and 336 block confirmation window BIP9 with the name "segsignal" and using bit 4.
This BIP will have a start time of midnight June 1st, 2017 (epoch time 1496275200) and timeout on midnight November 15th 2017 (epoch time 1510704000). This BIP will cease to be active when segwit (BIP141) is locked-in, active, or failed
=== Reference implementation ===
https://github.com/segsignal/bitcoin
==Backwards Compatibility==
This deployment is compatible with the existing "segwit" bit 1 deployment scheduled between midnight November 15th, 2016 and midnight November 15th, 2017. Miners will need to upgrade their nodes to support segsignal otherwise they may build on top of an invalid block. While this bip is active users should either upgrade to segsignal or wait for additional confirmations when accepting payments.
==Rationale==
Historically we have used IsSuperMajority() to activate soft forks such as BIP66 which has a mandatory signalling requirement for miners once activated, this ensures that miners are aware of new rules being enforced. This technique can be leveraged to lower the signalling threshold of a soft fork while it is in the process of being deployed in a backwards compatible way.
By orphaning non-signalling blocks during the BIP9 bit 1 "segwit" deployment, this BIP can cause the existing "segwit" deployment to activate without needing to release a new deployment.
==References==
*[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-March/013714.html Mailing list discussion]
*[https://github.com/bitcoin/bitcoin/blob/v0.6.0/src/main.cpp#L1281-L1283 P2SH flag day activation]
*[[bip-0009.mediawiki|BIP9 Version bits with timeout and delay]]
*[[bip-0016.mediawiki|BIP16 Pay to Script Hash]]
*[[bip-0141.mediawiki|BIP141 Segregated Witness (Consensus layer)]]
*[[bip-0143.mediawiki|BIP143 Transaction Signature Verification for Version 0 Witness Program]]
*[[bip-0147.mediawiki|BIP147 Dealing with dummy stack element malleability]]
*[[bip-0148.mediawiki|BIP148 Mandatory activation of segwit deployment]]
*[[bip-0149.mediawiki|BIP149 Segregated Witness (second deployment)]]
*[https://bitcoincore.org/en/2016/01/26/segwit-benefits/ Segwit benefits]
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0093.mediawiki
================================================
BIP: 93
Layer: Applications
Title: codex32: Checksummed SSSS-aware BIP32 seeds
Authors: Leon Olsson Curr and Pearlwort Sneed
Andrew Poelstra
Status: Draft
Type: Informational
Assigned: 2023-02-13
License: BSD-3-Clause
Discussion: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-February/021469.html
==Introduction==
===Abstract===
This document proposes a checksummed base32 format, "codex32", and a standard for backing up and restoring the master seed of a
[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-0032] hierarchical deterministic wallet using it.
It includes an encoding format, a BCH error-correcting checksum, and optional Shamir's secret sharing algorithms for share generation and secret recovery.
Secret data can be encoded directly, or split into up to 31 shares.
A minimum threshold of shares, which can be between 2 and 9, is needed to recover the secret, whereas without sufficient shares, no information about the secret is recoverable.
===Copyright===
This document is licensed under the 3-clause BSD license.
===Motivation===
BIP-0032 master seed data is the source entropy used to derive all private keys in an HD wallet.
Safely storing this secret data is the hardest and most important part of self-custody.
However, there is a tension between security, which demands limiting the number of backups, and resilience, which demands widely replicated backups.
Encrypting the seed does not change this fundamental tradeoff, since it leaves essentially the same problem of how to back up the encryption key(s).
To allow users freedom to make this tradeoff, we use Shamir's secret sharing, which guarantees that any number of shares less than the threshold leaks no information about the secret.
This approach allows increasing safety by widely distributing the generated shares, while also providing security against the compromise of one or more shares (as long as fewer than the threshold have been compromised).
[https://github.com/satoshilabs/slips/blob/master/slip-0039.md SLIP-0039] has essentially the same motivations as this standard.
However, unlike SLIP-0039,
* this standard aims to be simple enough for hand computation
* we use the bech32 alphabet rather than a word list, resulting in fixed-length compact encodings
* we do not support multi-level secret sharing (splitting of shares), although it is technically possible and may be added in a future BIP
* because of the need to support hand computation, we '''do not''' support passphrases or key hardening
Users who demand a higher level of security for particular secrets, or have a general distrust in digital electronic devices, have the option of using hand computation to backup and restore secret data in an interoperable manner.
In particular, all computations can be done with simple lookup tables.
'''It is therefore possible to compute and verify checksums, and to split and recover seeds, entirely using pen and paper.'''
For long-lived rarely-used seeds, the ability to hand-verify checksums has a significant benefit even for users who do not care to do any other part of this process by hand.
It means that they can verify the integrity (against non-malicious tampering) of their shares regularly, say, on an annual basis, without needing to continually expose secret data to new hardware.
The ability to compute properties by hand comes from our choice of a small field and our use of linear error correcting codes.
It does not come with any reduction in security, as long as users use high-quality randomness.
Note that hand computation is optional, the particular details of hand computation are outside the scope of this standard, and implementers do not need to be concerned with this possibility.
[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP-0039] serves the same purpose as this standard: encoding master seeds for storage by users.
However, BIP-0039 has no error-correcting ability, cannot sensibly be extended to support secret sharing, has no support for versioning or other metadata, and has many technical design decisions that make implementation and interoperability difficult (for example, the use of SHA-512 to derive seeds, or the use of 11-bit words).
==Specification==
We first describe the general checksummed base32'''Why use base32 at all?''' The lack of mixed case makes it more
efficient to read out loud, write, type or to put into QR codes. format called
''codex32'' and then define a BIP-0032 master seed encoding using it.
===codex32===
A codex32 string is similar to a bech32 string defined in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP-0173].
It reuses the base-32 character set from BIP-0173, and consists of:
* A human-readable part, which is the string "ms" (or "MS").
* A separator, which is always "1".
* A data part which is in turn subdivided into:
** A threshold parameter, which MUST be a single digit between "2" and "9", or the digit "0".
*** If the threshold parameter is "0" then the share index, defined below, MUST have a value of "s" (or "S").
** An identifier consisting of 4 bech32 characters.
** A share index, which is any bech32 character. Note that a share index value of "s" (or "S") is special and denotes the unshared secret (see section "Unshared Secret").
** A payload which is a sequence of up to 74 bech32 characters. (However, see '''Long codex32 Strings''' below for an exception to this limit.)
** A checksum which consists of 13 bech32 characters as described below.
As with bech32 strings, a codex32 string MUST be entirely uppercase or entirely lowercase.
Note that per BIP-0173, the lowercase form is used when determining a character's value for checksum purposes.
In particular, given an all uppercase codex32 string, we still use lowercase ms as the human-readable part during checksum construction.
For presentation, lowercase is usually preferable, but uppercase SHOULD be used for handwritten codex32 strings.
If a codex32 string is encoded in a QR code, it SHOULD use the uppercase form, as this is encoded more compactly.
====Checksum====
The last thirteen characters of the data part form a checksum and contain no information.
Valid strings MUST pass the criteria for validity specified by the Python 3 code snippet below.
The function ms32_verify_checksum must return true when its argument is the data part as a list of integers representing the characters converted using the bech32 character table from BIP-0173.
To construct a valid checksum given the data-part characters (excluding the checksum), the ms32_create_checksum function can be used.
MS32_CONST = 0x10ce0795c2fd1e62a
def ms32_polymod(values):
GEN = [
0x19dc500ce73fde210,
0x1bfae00def77fe529,
0x1fbd920fffe7bee52,
0x1739640bdeee3fdad,
0x07729a039cfc75f5a,
]
residue = 0x23181b3
for v in values:
b = (residue >> 60)
residue = (residue & 0x0fffffffffffffff) << 5 ^ v
for i in range(5):
residue ^= GEN[i] if ((b >> i) & 1) else 0
return residue
def ms32_verify_checksum(data):
if len(data) >= 96: # See Long codex32 Strings
return ms32_verify_long_checksum(data)
if len(data) <= 93:
return ms32_polymod(data) == MS32_CONST
return False
def ms32_create_checksum(data):
if len(data) > 80: # See Long codex32 Strings
return ms32_create_long_checksum(data)
values = data
polymod = ms32_polymod(values + [0] * 13) ^ MS32_CONST
return [(polymod >> 5 * (12 - i)) & 31 for i in range(13)]
This implements a [https://en.wikipedia.org/wiki/BCH_code BCH code] that
guarantees detection of '''any error affecting at most 8 characters'''
and has less than a 3 in 1020 chance of failing to detect more
random errors.
====Error Correction====
A codex32 string without a valid checksum MUST NOT be used.
The checksum is designed to be an error correcting code that can correct up to 4 character substitutions, up to 8 unreadable characters (called erasures), or up to 13 consecutive erasures.
Implementations SHOULD provide the user with a corrected valid codex32 string if possible.
However, implementations SHOULD NOT automatically proceed with a corrected codex32 string without user confirmation of the corrected string, either by prompting the user, or returning a corrected string in an error message and allowing the user to repeat their action.
We do not specify how an implementation should implement error correction. However, we recommend that:
* Implementations make suggestions to substitute non-bech32 characters with bech32 characters in some situations, such as replacing "B" with "8", "O" with "0", "I" with "l", etc.
* Implementations interpret "?" as an erasure.
* Implementations optionally interpret other non-bech32 characters, or characters with incorrect case, as erasures.
* If a string with 8 or fewer erasures can have those erasures filled in to make a valid codex32 string, then the implementation suggests such a string as a correction.
* If a string consisting of valid bech32 characters in the proper case can be made valid by substituting 4 or fewer characters, then the implementation suggests such a string as a correction.
===Unshared Secret===
When the share index of a valid codex32 string (converted to lowercase) is the letter "s", we call the string a codex32 secret.
The secret is decoded by converting the payload to bytes:
* Translate the characters to 5 bits values using the bech32 character table from BIP-0173, most significant bit first.
* Re-arrange those bits into groups of 8 bits. Any incomplete group at the end MUST be 4 bits or less, and is discarded.
Note that unlike the decoding process in BIP-0173, we do NOT require that the incomplete group be all zeros.
For an unshared secret, the threshold parameter (the first character of the data part) is ignored (beyond the fact it must be a digit for the codex32 string to be valid).
We recommend using the digit "0" for the threshold parameter in this case.
The 4 character identifier also has no effect beyond aiding users in distinguishing between multiple different secrets in cases where they have more than one.
The function ms32_encode constructs a codex32 string when its argument is the converted data-part characters (excluding the checksum).
To validate a codex32 string and determine the data-part (excluding the checksum) as a list of 5-bit values, the ms32_decode function can be used.
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
def ms32_encode(data):
combined = data + ms32_create_checksum(data)
return "ms" + "1" + ''.join([CHARSET[d] for d in combined])
def ms32_decode(codex):
if ((any(ord(x) < 33 or ord(x) > 126 for x in codex)) or
(codex.lower() != codex and codex.upper() != codex)):
return None
codex = codex.lower()
pos = codex.rfind("1")
if pos < 2 or not (48 <= len(codex) <= 127):
return None
if not all(x in CHARSET for x in codex[pos+1:]):
return None
if codex[:pos] != "ms" or codex[pos+1].isalpha() or codex[pos+1] == "0" and codex[pos+6] != "s":
return None
data = [CHARSET.index(x) for x in codex[pos+1:]]
if not ms32_verify_checksum(data):
return None
return data[:-13 if len(data) < 94 else -15] # See Long codex32 Strings
===Master seed format===
When the human-readable part of a valid codex32 secret (converted to lowercase) is the string "ms", we call it a codex32-encoded master seed or secret seed. The payload in this case is a direct encoding of a BIP-0032 HD master seed.
A secret seed is a codex32 encoding of:
* The human-readable part "ms" for master seed.
* The data-part values:
** A threshold parameter, which MUST be a single digit between "2" and "9", or the digit "0".
** An identifier consisting of 4 bech32 characters.
*** We do not define how to choose the identifier, beyond noting that it SHOULD be distinct for every master seed and share set the user may need to disambiguate.
** The share index "s".
** A conversion of the 16-to-64-byte BIP-0032 HD master seed to bech32:
*** Start with the bits of the master seed, most significant bit per byte first.
*** Re-arrange those bits into groups of 5, and pad with arbitrary bits at the end if needed.
*** Translate those bits to characters using the bech32 character table from BIP-0173.
** A valid checksum in accordance with the Checksum section.
===Recovering Secret===
When the share index of a valid codex32 string (converted to lowercase) is not the letter "s", we call the string a codex32 share.
The first character of the data part indicates the threshold of the share, and it is required to be a non-"0" digit.
In order to recover a secret, one needs a set of valid shares such that:
* All shares have the same threshold value, the same identifier, and the same length.
* All of the share index values are distinct.
* The number of shares is exactly equal to the (common) threshold value.
If all the above conditions are satisfied, the ms32_recover function will return a codex32 secret when its argument is the list of codex32 shares with each share represented as a list of integers representing the characters converted using the bech32 character table from BIP-0173.
BECH32_INV = [
0, 1, 20, 24, 10, 8, 12, 29, 5, 11, 4, 9, 6, 28, 26, 31,
22, 18, 17, 23, 2, 25, 16, 19, 3, 21, 14, 30, 13, 7, 27, 15,
]
def bech32_mul(a, b):
res = 0
for i in range(5):
res ^= a if ((b >> i) & 1) else 0
a *= 2
a ^= 41 if (32 <= a) else 0
return res
def bech32_lagrange(l, x):
n = 1
c = []
for i in l:
n = bech32_mul(n, i ^ x)
m = 1
for j in l:
m = bech32_mul(m, (x if i == j else i) ^ j)
c.append(m)
return [bech32_mul(n, BECH32_INV[i]) for i in c]
def ms32_interpolate(l, x):
w = bech32_lagrange([s[5] for s in l], x)
res = []
for i in range(len(l[0])):
n = 0
for j in range(len(l)):
n ^= bech32_mul(w[j], l[j][i])
res.append(n)
return res
def ms32_recover(shares):
return ms32_interpolate(shares, 16)
===Generating Shares===
If we already have ''k'' valid codex32 strings such that:
* All strings have the same threshold value ''k'', the same identifier, and the same length
* All of the share index values are distinct
Then we can derive additional shares with the ms32_interpolate function by passing it a list of exactly ''k'' of these codex32 strings, together with a fresh share index distinct from all of the existing share indexes.
The newly derived share will have the provided share index.
Once a user has generated ''n'' shares, they may discard the codex32 secret (if it exists).
The ''n'' shares form a ''k'' of ''n'' Shamir's secret sharing scheme of a codex32 secret.
There are two ways to create an initial set of ''k'' valid codex32 strings, depending on whether the user already has an existing secret to split.
====For a fresh secret====
In the case that the user wishes to generate a fresh secret, the user generates random initial shares, as follows:
# Choose a bitsize, between 128 and 512, which must be a multiple of 8
# Choose a threshold value ''k'' between 2 and 9, inclusive
# Choose a 4 bech32 character identifier
#* We do not define how to choose the identifier, beyond noting that it SHOULD be distinct for every secret the user may need to disambiguate
# ''k'' many times, generate a random share by:
## Take the next available letter from the bech32 alphabet, in alphabetical order, as a, c, d, ..., to be the share index
## Set the first nine characters to be the prefix ms1, the threshold value ''t'', the 4-character identifier, and then the share index
## Choose the next ceil(''bitlength / 5'') characters uniformly at random
## Generate a valid checksum in accordance with the Checksum section, and append this to the resulting shares
The result will be ''k'' distinct shares, all with the same initial 8 characters, and a distinct share index as the 9th character.
With this set of ''k'' shares, new shares can be derived as discussed above. This process generates a fresh secret, whose value can be retrieved by running the recovery process on any ''k'' of these shares.
====For an existing secret====
Before generating shares for an existing secret, it first must be codex32-encoded.
The conversion process consists of:
# Choose a threshold value ''k'' between 2 and 9, inclusive
# Choose a 4 bech32 character identifier
#* We do not define how to choose the identifier, beyond noting that it SHOULD be distinct for every set of shares the user may need to disambiguate
# Set the share index to s
# Set the payload to a bech32 encoding of the secret data, padded with arbitrary bits
# Generate a valid checksum in accordance with the Checksum section
Along with the codex32 secret, the user must generate ''k''-1 other codex32 shares, each with the same threshold value, the same identifier, and a distinct share index.
These shares should be generated as described in the "fresh secret" section.
The codex32 secret and the ''k''-1 codex32 shares form a set of ''k'' valid initial codex32 strings from which additional shares can be derived as described above.
===Long codex32===
The 13 character checksum design only supports up to 80 data characters.
Excluding the threshold, identifier and index characters, this limits the payload to 74 characters or 46 bytes.
While this is enough to support the 32-byte advised size of BIP-0032 master seeds, BIP-0032 allows seeds to be up to 64 bytes in size.
We define a long codex32 format to support these longer seeds by defining an alternative checksum.
MS32_LONG_CONST = 0x43381e570bf4798ab26
def ms32_long_polymod(values):
GEN = [
0x3d59d273535ea62d897,
0x7a9becb6361c6c51507,
0x543f9b7e6c38d8a2a0e,
0x0c577eaeccf1990d13c,
0x1887f74f8dc71b10651,
]
residue = 0x23181b3
for v in values:
b = (residue >> 70)
residue = (residue & 0x3fffffffffffffffff) << 5 ^ v
for i in range(5):
residue ^= GEN[i] if ((b >> i) & 1) else 0
return residue
def ms32_verify_long_checksum(data):
return ms32_long_polymod(data) == MS32_LONG_CONST
def ms32_create_long_checksum(data):
values = data
polymod = ms32_long_polymod(values + [0] * 15) ^ MS32_LONG_CONST
return [(polymod >> 5 * (14 - i)) & 31 for i in range(15)]
This implements a [https://en.wikipedia.org/wiki/BCH_code BCH code] that
guarantees detection of '''any error affecting at most 8 characters'''
and has less than a 3 in 1023 chance of failing to detect more
random errors.
A long codex32 string follows the same specification as a regular codex32 string with the following changes.
* The payload is a sequence of between 75 and 103 bech32 characters.
* The checksum consists of 15 bech32 characters as defined above.
A codex32 string with a data part of 94 or 95 characters is never legal as a regular codex32 string is limited to 93 data characters and a long codex32 string is at least 96 data characters.
Generation of long shares and recovery of the long secret from long shares proceeds in exactly the same way as for regular shares with the ms32_interpolate function.
The long checksum is designed to be an error correcting code that can correct up to 4 character substitutions, up to 8 unreadable characters (called erasures), or up to 15 consecutive erasures.
As with regular checksums we do not specify how an implementation should implement error correction, and all our recommendations for error correction of regular codex32 strings also apply to long codex32 strings.
==Rationale==
This scheme is based on the observation that the Lagrange interpolation of valid codewords in a BCH code will always be a valid codeword.
This means that derived shares will always have valid checksum, and a sufficient threshold of shares with valid checksums will derive a secret with a valid checksum.
The header system is also compatible with Lagrange interpolation, meaning all derived shares will have the same identifier and will have the appropriate share index.
This fact allows the header data to be covered by the checksum.
The checksum size and identifier size have been chosen so that the encoding of 128-bit master seeds and shares fit within 48 characters.
This is a standard size for many common seed storage formats, which has been popularized by the 12 four-letter word format of the BIP-0039 mnemonic.
The 13 character checksum is adequate to correct 4 errors in up to 93 characters (80 characters of data and 13 characters of the checksum).
We can correct up to 8 erasures (errors with known locations), and up to 13 consecutive errors (burst errors).
Beyond that, our code is guaranteed to detect up to 8 errors.
More generally, any number of random errors will be detected with overwhelming (1 - 2^65) probability. However, the checksum does not protect against maliciously constructed errors.
These parameters are slightly better than those of the checksum used in SLIP-0039.
For 256-bit seeds and shares our strings are 74 characters, which fits into the 96 character format of the 24 four-letter word format of the BIP-0039 mnemonic, with plenty of room to spare.
A longer checksum is needed to support up to 512-bit seeds, the longest seed length specified in BIP-0032, as the 13 character checksum isn't adequate for more than 80 data characters.
While we could use the 15 character checksum for both cases, we prefer to keep the strings as short as possible for the more common cases of 128-bit and 256-bit master seeds.
We only guarantee to correct 4 characters no matter how long the string is.
Longer strings mean more chances for transcription errors, so shorter strings are better.
The longest data part using the regular 13 character checksum is 93 characters and corresponds to a 368-bit secret.
At this length, the prefix MS1 is not covered by the checksum.
This is acceptable because the checksum scheme itself requires you to know that the MS1 prefix is being used in the first place.
If the prefix is damaged and a user is guessing that the data might be using this scheme, then the user can enter the available data explicitly using the suspected MS1 prefix.
===Not BIP-0039 Entropy===
Instead of encoding a BIP-0032 master seed, an alternative would be to encode BIP-0039 entropy.
However this alternative approach is fraught with difficulties.
On approach would be to encode the BIP-0039 entropy along with the BIP-0039 checksum data.
This data can directly be recovered from the BIP-0039 mnemonic, and the process can be reversed if one knows the target language.
However, for a 128-bit seed, there is a 4 bit checksum yielding 132 bits of data that needs to be encoded.
This exceeds the 130-bits of room that we have for storing 128 bit seeds.
We would have to compromise on the 48 character size, or the size of the headers, or the size of the checksum in order to add room for an additional character of data.
This approach would also eliminate our short cut generation of a fresh master secret from generating random shares.
One would be required to first generate BIP-0039 entropy, and then add a BIP-0039 checksum, before adding a Codex32 checksum and then generate other shares.
In particular, this process could no longer be performed by hand since it is effectively impossible to hand compute a BIP-0039 checksum.
An alternative approach is to discard the BIP-0039 checksum, since it is inadequate for error correction anyways, and rely on the Codex32 checksum.
However, this approach ends up eliminating the benefits of BIP-0039 compatibility.
While it is now possible to hand generate fresh shares, it is impossible to recover compatible BIP-0039 words by hand because, again, the BIP-0039 checksum is not hand computable.
The only way of generating the compatible BIP-0039 mnemonic is to use wallet software.
But if the wallet software is need to support this approach to decoding entropy, we may as well bypass all of the overhead of BIP-0039 and directly encode the entropy of a BIP-0032 master seed, which is what we do in our Codex32 proposal.
Beyond the problems above, BIP-0039 does not define a single transformation from entropy to BIP-0032 master seed.
Instead every different language has it own word list (or word lists) and each choice of word list yields a different transformation from entropy to master seed.
We would need to encode the choice of word list in our share's meta-data, which takes up even more room, and is difficult to specify due to the ever-evolving choice of word lists.
Alternatively we could standardize on the choice of the English word list, something that is nearly a de facto standard, and simply be incompatible with BIP-0039 wallets of other languages.
Such a choice also risks users of BIP-0039 recovering their entropy from their language, encoding it in Codex32 and then failing to recover their wallet because the English word lists has replaced their language's word list.
The main advantage of this alternative approach would be that wallets could give users an option switch between backing up their entropy as a BIP-0039 mnemonic and in Codex32 format, but again, only if their language choice happens to be the English word list.
In practice, we do not expect users in switch back and forth between backup formats, and instead just generate a fresh master seed using Codex32.
Seeing little value with BIP-0039 compatibility (English-only), all the difficulties with BIP-0039 language choice, not to mention the PBKDF2 overhead of using BIP-0039, we think it is best to abandon BIP-0039 and encode BIP-0032 master seeds directly.
Our approach is semi-convertible with BIP-0039's 512-bit master seeds (in all languages, see Backwards Compatibility) and fully interconvertible with SLIP-39 encoded master seeds or any other encoding of BIP-0032 master seeds.
==Backwards Compatibility==
codex32 is an alternative to BIP-0039 and SLIP-0039.
It is technically possible to derive the BIP32 master seed from seed words encoded in one of these schemes, and then to encode this seed in codex32.
For BIP-0039 this process is irreversible, since it involves hashing the original words.
Furthermore, the resulting seed will be 512 bits long, which may be too large to be safely and conveniently handled.
SLIP-0039 seed words can be reversibly converted to master seeds, so it is possible to interconvert between SLIP-0039 and codex32.
However, SLIP-0039 '''shares''' cannot be converted to codex32 shares because the two schemes use a different underlying field.
The authors of this BIP do not recommend interconversion.
Instead, users who wish to switch to codex32 should generate a fresh seed and sweep their coins.
==Reference Implementation==
Our [https://github.com/BlockstreamResearch/codex32 reference implementation repository] contains implementations in Rust and PostScript.
The inline code in this BIP text can be used as a Python reference.
==Test Vectors==
===Test vector 1===
This example shows the codex32 format, when used without splitting the secret into any shares.
The payload contains 26 bech32 characters, which corresponds to 130 bits. We truncate the last two bits in order to obtain a 128-bit master seed.
codex32 secret (bech32): ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw
Master seed (hex): 318c6318c6318c6318c6318c6318c631
* human-readable part: ms
* separator: 1
* k value: 0 (no secret splitting)
* identifier: test
* share index: s (the secret)
* payload: xxxxxxxxxxxxxxxxxxxxxxxxxx
* checksum: 4nzvca9cmczlw
* master node xprv: xprv9s21ZrQH143K3taPNekMd9oV5K6szJ8ND7vVh6fxicRUMDcChr3bFFzuxY8qP3xFFBL6DWc2uEYCfBFZ2nFWbAqKPhtCLRjgv78EZJDEfpL
===Test vector 2===
This example shows generating a new master seed using "random" shares, as well as deriving an additional share, using ''k''=2 and an identifier of NAME.
Although codex32 strings are canonically all lowercase, it's also valid to use all uppercase.
Share with index A: MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM
Share with index C: MS12NAMECACDEFGHJKLMNPQRSTUVWXYZ023FTR2GDZMPY6PN
* Derived share with index D: MS12NAMEDLL4F8JLH4E5VDVULDLFXU2JHDNLSM97XVENRXEG
* Recovered secret seed with index S: MS12NAMES6XQGUZTTXKEQNJSJZV4JV3NZ5K3KWGSPHUH6EVW
* Master seed (hex): d1808e096b35b209ca12132b264662a5
* master node xprv: xprv9s21ZrQH143K2NkobdHxXeyFDqE44nJYvzLFtsriatJNWMNKznGoGgW5UMTL4fyWtajnMYb5gEc2CgaKhmsKeskoi9eTimpRv2N11THhPTU
===Test vector 3===
This example shows splitting an existing 128-bit master seed into "random" shares, using ''k''=3 and an identifier of cash.
We appended two zero bits in order to obtain 26 bech32 characters (130 bits of data) from the 128-bit master seed.
Master seed (hex): ffeeddccbbaa99887766554433221100
codex32-encoded master seed with index s: ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln
Share with index a: ms13casha320zyxwvutsrqpnmlkjhgfedca2a8d0zehn8a0t
Share with index c: ms13cashcacdefghjklmnpqrstuvwxyz023949xq35my48dr
* Derived share with index d: ms13cashd0wsedstcdcts64cd7wvy4m90lm28w4ffupqs7rm
* Derived share with index e: ms13casheekgpemxzshcrmqhaydlp6yhms3ws7320xyxsar9
* Derived share with index f: ms13cashf8jh6sdrkpyrsp5ut94pj8ktehhw2hfvyrj48704
* master node xprv: xprv9s21ZrQH143K266qUcrDyYJrSG7KA3A7sE5UHndYRkFzsPQ6xwUhEGK1rNuyyA57Vkc1Ma6a8boVqcKqGNximmAe9L65WsYNcNitKRPnABd
Any three of the five shares among acdef can be used to recover the secret.
Note that the choice to append two zero bits was arbitrary, and any of the following four codex32 secrets would have been valid choices.
However, each choice would have resulted in a different set of derived shares.
* ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln
* ms13cashsllhdmn9m42vcsamx24zrxgs3qpte35dvzkjpt0r
* ms13cashsllhdmn9m42vcsamx24zrxgs3qzfatvdwq5692k6
* ms13cashsllhdmn9m42vcsamx24zrxgs3qrsx6ydhed97jx2
===Test vector 4===
This example shows converting a 256-bit secret into a codex32 secret, without splitting the secret into any shares.
We appended four zero bits in order to obtain 52 bech32 characters (260 bits of data) from the 256-bit secret.
Master seed (hex): ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100
* codex32 secret: ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma
* master node xprv: xprv9s21ZrQH143K3s41UCWxXTsU4TRrhkpD1t21QJETan3hjo8DP5LFdFcB5eaFtV8x6Y9aZotQyP8KByUjgLTbXCUjfu2iosTbMv98g8EQoqr
Note that the choice to append four zero bits was arbitrary, and any of the following sixteen codex32 secrets would have been valid:
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pgv99ycma
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqpj82dp34u6lqtd
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqzsrs4pnh7jmpj5
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqrfcpap2w8dqezy
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqy5tdvphn6znrf0
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq9dsuypw2ragmel
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqx05xupvgp4v6qx
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq8k0h5p43c2hzsk
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqgum7hplmjtr8ks
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqf9q0lpxzt5clxq
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq28y48pyqfuu7le
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqt7ly0paesr8x0f
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqvrvg7pqydv5uyz
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqd6hekpea5n0y5j
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqwcnrwpmlkmt9dt
* ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq0pgjxpzx0ysaam
===Test vector 5===
This example shows generating a new 512-bit master seed using "random" bech32 characters and appending a checksum.
The payload contains 103 bech32 characters, which corresponds to 515 bits. The last three bits are discarded when converting to a 512-bit master seed.
This is an example of a '''Long codex32''' string.
k value (bech32): 0
identifier (bech32): 0C8V
payload (bech32): M32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD6AN074RXVCEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06F
* checksum: HPV80UNDVARHRAK
* codex32 secret: MS100C8VSM32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD6AN074RXVCEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06FHPV80UNDVARHRAK
* Master seed (hex): dc5423251cb87175ff8110c8531d0952d8d73e1194e95b5f19d6f9df7c01111104c9baecdfea8cccc677fb9ddc8aec5553b86e528bcadfdcc201c17c638c47e9
* master node xprv: xprv9s21ZrQH143K4UYT4rP3TZVKKbmRVmfRqTx9mG2xCy2JYipZbkLV8rwvBXsUbEv9KQiUD7oED1Wyi9evZzUn2rqK9skRgPkNaAzyw3YrpJN
===Invalid test vectors===
These examples have incorrect checksums.
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxve740yyge2ghq
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxve740yyge2ghp
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxlk3yepcstwr
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx6pgnv7jnpcsp
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxx0cpvr7n4geq
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxm5252y7d3lr
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxrd9sukzl05ej
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxc55srw5jrm0
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxgc7rwhtudwc
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx4gy22afwghvs
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxe8yfm0
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvm597d
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxme084q0vpht7pe0
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxme084q0vpht7pew
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxqyadsp3nywm8a
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzvg7ar4hgaejk
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcznau0advgxqe
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxch3jrc6j5040j
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx52gxl6ppv40mcv
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7g4g2nhhle8fk
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx63m45uj8ss4x8
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy4r708q7kg65x
These examples use the wrong checksum for their given data sizes.
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxurfvwmdcmymdufv
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxcsyppjkd8lz4hx3
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxu6hwvl5p0l9xf3c
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwqey9rfs6smenxa
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxv70wkzrjr4ntqet
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3hmlrmpa4zl0v
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxrfggf88znkaup
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpt7l4aycv9qzj
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxus27z9xtyxyw3
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxcwm4re8fs78vn
These examples have improper lengths.
They are either too short, too long, or would decode to byte sequence with an incomplete group greater than 4 bits.
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxw0a4c70rfefn4
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxk4pavy5n46nea
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxx9lrwar5zwng4w
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxr335l5tv88js3
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvu7q9nz8p7dj68v
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxpq6k542scdxndq3
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkmfw6jm270mz6ej
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxzhddxw99w7xws
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxx42cux6um92rz
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxarja5kqukdhy9
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxky0ua3ha84qk8
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9eheesxadh2n2n9
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9llwmgesfulcj2z
* ms12fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx02ev7caq6n9fgkf
This example uses a "0" threshold with a non-"s" index
* ms10fauxxxxxxxxxxxxxxxxxxxxxxxxxxxx0z26tfn0ulw3p
This example has a threshold that is not a digit.
* ms1fauxxxxxxxxxxxxxxxxxxxxxxxxxxxxxda3kr3s0s2swg
These examples do not begin with the required "ms" or "MS" prefix and/or are missing the "1" separator.
* 0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* 10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* ms0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* m10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* s10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* 0fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxhkd4f70m8lgws
* 10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxhkd4f70m8lgws
* m10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxx8t28z74x8hs4l
* s10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxh9d0fhnvfyx3x
These examples all incorrectly mix upper and lower case characters.
* Ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* mS10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* MS10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* ms10FAUXsxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* ms10fauxSxxxxxxxxxxxxxxxxxxxxxxxxxxuqxkk05lyf3x2
* ms10fauxsXXXXXXXXXXXXXXXXXXXXXXXXXXuqxkk05lyf3x2
* ms10fauxsxxxxxxxxxxxxxxxxxxxxxxxxxxUQXKK05LYF3X2
==Appendix==
===Mathematical Companion===
Below we use the bech32 character set to denote values in GF[32].
In bech32, the letter Q denotes zero and the letter P denotes one.
The digits 0 and 2 through 9 do ''not'' denote their numeric values.
They are simply elements of GF[32].
The generating polynomial for our BCH code is as follows.
We extend GF[32] to GF[1024] by adjoining a primitive cube root of unity, ζ, satisfying ζ^2 = ζ + P.
We select β := G ζ which has order 93, and construct the product (x - β^i) for i in {17, 20, 46, 49, 52, 77, 78, 79, 80, 81, 82, 83, 84}.
The resulting polynomial is our generating polynomial for our 13 character checksum:
x^13 + E x^12 + M x^11 + 3 x^10 + G x^9 + Q x^8 + E x^7 + E x^6 + E x^5 + L x^4 + M x^3 + C x^2 + S x + S
For our long checksum, we select γ := E + X ζ, which has order 1023, and construct the product (x - γ^i) for i in {32, 64, 96, 895, 927, 959, 991, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026}.
The resulting polynomial is our generating polynomial for our 15 character checksum for long strings:
x^15 + 0 x^14 + 2 x^13 + E x^12 + 6 x^11 + F x^10 + E x^9 + 4 x^8 + X x^7 + H x^6 + 4 x^5 + X x^4 + 9 x^3 + K x^2 + Y x^1 + H
(Reminder: the character 0 does ''not'' denote the zero of the field.)
================================================
FILE: bip-0094.mediawiki
================================================
== Abstract ==
A new test network with the goal to replace Testnet 3. This network comes with small but important improvements of the consensus rules, that should make it impractical to attack the network using only CPU mining.
== Motivation ==
Quoting the original mailing list post from Jameson Lopphttps://gnusha.org/pi/bitcoindev/CADL_X_eXjbRFROuJU0b336vPVy5Q2RJvhcx64NSNPH-3fDCUfw@mail.gmail.com/:
Testnet3 has been running for 13 years. It's on block 2.5 million something and the block reward is down to ~0.014 TBTC, so mining is not doing a great job at distributing testnet coins anymore.
The reason the block height is insanely high is due to a rather amusing edge case bug that causes the difficulty to regularly get reset to 1, which causes a bit of havoc. If you want a deep dive into the quirk: https://blog.lopp.net/the-block-storms-of-bitcoins-testnet/
Testnet3 is being actively used for scammy airdrops; those of us who tend to be generous with our testnet coins are getting hounded by non-developers chasing cheap gains.
As a result, TBTC is being actively bought and sold; one could argue that the fundamental principle of testnet coins having no value has been broken.
Since then the issue with block storms has been further demonstrated on Testnet 3 when three years' worth of blocks were mined in a few weeks while rendering the network practically unusable at the same time.
== Specification ==
Testnet 4 follows the same consensus rules as mainnet with the following three exceptions. Additionally, all soft forks that are active on mainnet as of May 2024 are enforced from genesis.
=== 1. 20-minute Exception Rule ===
This rule was implemented in Testnet 3https://github.com/bitcoin/bitcoin/pull/686 and is preserved in Testnet 4.
==== Rule Specification ====
1. For any block except the first block in a difficulty period:
a. If the block's timestamp is >20 minutes past the timestamp of the previous block
b. Then the block MUST use the minimum difficulty value (nBits = 0x1d00ffff), regardless of the network's actual difficulty
2. The first block of each difficulty period MUST use the actual network difficulty.
This rule enables CPU mining on testnet but has led to block stormshttps://blog.lopp.net/the-block-storms-of-bitcoins-testnet/ which rule #2 below addresses.
=== 2. Block Storm Fix ===
This is a new rule to address block storms caused by the 20-minute exception.
==== Problem Statement ====
In Mainnet and Testnet 3, the difficulty adjustment calculation uses the difficulty value of the last block in the previous period as its base. When the 20-minute exception is applied to this last block, it is mined at difficulty 1, causing the next period's difficulty to be constrained between 1-4, leading to block storms.
==== Rule Specification ====
1. For difficulty adjustment calculations between periods:
a. The base difficulty value MUST be taken from the first block of the previous difficulty period
b. NOT from the last block as in previous implementations
2. The adjustment factor calculation remains unchanged:
a. Multiplication factor based on the duration of the previous difficulty period
b. Limited to no less than 1/4 and no more than 4x
This change ensures that the actual network difficulty is used for adjustment calculations rather than potentially manipulated values from the last block in a period.
=== 3. Time Warp Attack Prevention ===
This rule prevents time warp attacks that could otherwise be used to amplify block stormsA perpetual block storm attack with entire difficulty periods being authored in less than 3.5 days that resets the difficulty to the minimum in the last block of every difficulty period would adjust to a new actual difficulty of 4 every period. An attacker that additionally leverages a time warp attack would start their attack by holding back timestamps until the latest block's timestamp is at least two weeks in the past, and then limiting their block rate to six blocks per second, incrementing the timestamp on every sixth block. Only on the last block they would use the current time, which both resets the difficulty to one per the 20-minute exception and would result in a difficulty adjustment keeping the difficulty at the minimum due to the elapsed time exceeding the target. This would allow lower the difficulty for all blocks to difficulty 1 instead of difficulty 4.
==== Rule Specification ====
1. For any block whose height modulo 2016 equals 0 (i.e., the first block of each difficulty period):
a. The block's nTime field MUST be greater than or equal to the nTime field of the immediately prior block minus 600 seconds
2. These blocks MUST still comply with existing Median-Time-Past nTime restrictions
This rule is based on The Great Consensus Cleanup proposalhttps://github.com/TheBlueMatt/bips/blob/cleanup-softfork/bip-XXXX.mediawiki and prevents miners from manipulating timestamps to artificially lower difficulty.
== Rationale ==
The applied changes were the result of discussions on the mailing list and the PR. The selected changes try to strike a balance between minimal changes to the network (keeping it as close to mainnet as possible) while making it more robust against attackers that try to disrupt the network. Several alternative designs were considered:
* For the block storm fix an alternative fix could have been to prevent the last block in a difficulty period from applying the existing difficulty exception. Both solutions were deemed acceptable and there was no clear preference among reviewers.
* Removal of the 20-minute exception was discussed but dismissed since several reviewers insisted that it was a useful feature allowing non-standard transactions to be mined with just a CPU. The 20-minute exception also allows CPU users to move the chain forward (except on the first block that needs to be mined at actual difficulty) in case a large amount of hash power suddenly leaves the network. This would allow the chain to recover to a normal difficulty level faster if left stranded at high difficulty.
* Increase of minimum difficulty was discussed but dismissed as it would categorically prevent participation in the network using a CPU miner (utilizing the 20-minute exception).
* Increase of the delay in the 20-minute exception was suggested but did not receive significant support.
* Re-enabling acceptnonstdtxn in bitcoin core by default was dismissed as it had led to confusion among layer-2s that had used testnet for transaction propagation tests and expected it to behave similarly to mainnet.
* Motivating miners to re-org min difficulty blocks was suggested, but was considered out of scope for this BIP, since adoption of such a mining policy remains available after Testnet 4 is deployed. As 20-minute exception blocks only contribute work corresponding to difficulty one to the chaintip, and actual difficulty blocks should have a difficulty magnitudes higher, a block mined at actual difficulty could easily replace even multiple 20-minute exception blocks.
* Persisting the real difficulty in the version field was suggested to robustly prevent exploits of the 20-minute exception while allowing it to be used on any block, but did not receive a sufficient level of support to justify the more invasive change.
One known downside of the chosen approach is that if the difficulty is gradually raised by a miner with significant hash rate, and this miner disappears, then each difficulty adjustment period requires one block at the actual difficulty.
This would cause the network to stall once per difficulty adjustment period until the real difficulty is adjusted downwards enough for the remaining hash rate to find this block in reasonable time.
== Network Parameters ==
=== Consensus Rules ===
All consensus rules active on mainnet at the time of this proposal are enforced from block 1, the newest of these rules being the Taproot softfork.
=== Genesis Block ===
* Message: 03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e
* Pubkey: 000000000000000000000000000000000000000000000000000000000000000000
* Time stamp: 1714777860
* Nonce: 393743547
* Difficulty: 0x1d00ffff
* Version: 1
The resulting genesis block hash is 00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043, and the block hex is 0100000000000000000000000000000000000000000000000000000000000000000000004e7b2b9128fe0291db0693af2ae418b767e657cd407e80cb1434221eaea7a07a046f3566ffff001dbb0c78170101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff5504ffff001d01044c4c30332f4d61792f323032342030303030303030303030303030303030303030303165626435386332343439373062336161396437383362623030313031316662653865613865393865303065ffffffff0100f2052a010000002321000000000000000000000000000000000000000000000000000000000000000000ac00000000.
=== Message Start ===
The message start is defined as 0x1c163f28. These four bytes were randomly generated and have no special meaning.
=== Network Parameters ===
The default p2p port for Testnet 4 is `48333`.
== Backwards Compatibility ==
The rules used by Testnet 4 are backwards compatible to the rules of Testnet 3. Existing software that implements support for Testnet 3 would only require addition of the network parameters (magic number, genesis block, etc.) to be able to follow Testnet 4.
However, implementations that only implement Testnet 3's rules would accept a chain that violates Testnet 4's rules and are therefore susceptible to being forked off. It is recommended that any implementations check blocks in regard to all the new rules of Testnet 4 and reject blocks that fail to comply.
== Reference implementation ==
Pull request at https://github.com/bitcoin/bitcoin/pull/29775
== References ==
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
================================================
FILE: bip-0098/build.sh
================================================
#!/bin/sh
dot -Tpng -o node-variants.png node-variants.dot
dot -Tpng -o skip-skip.png skip-skip.dot
dot -Tpng -o traversal-example.png traversal-example.dot
dot -Tpng -o unbalanced-hash-tree.png unbalanced-hash-tree.dot
================================================
FILE: bip-0098/node-variants.dot
================================================
digraph G {
row1 [shape=none, label=""]
A [label="000"]
A -> Al [label="L"]
Al [label="VERIFY"]
A -> Ar [label="R"]
Ar [label="SKIP"]
B [label="001"]
B -> Bl [label="L"]
Bl [label="VERIFY"]
B -> Br [label="R"]
Br [label="VERIFY"]
{ rank = same; row1; A; B; }
C [label="010"]
C -> Cl [label="L"]
Cl [label="VERIFY"]
C -> Cr [label="R"]
Cr [label="DESCEND"]
Cr -> Crl
Crl [label="..."]
Cr -> Crr
Crr [label="..."]
D [label="011"]
D -> Dl [label="L"]
Dl [label="DESCEND"]
Dl -> Dll
Dll [label="..."]
Dl -> Dlr
Dlr [label="..."]
D -> Dr [label="R"]
Dr [label="SKIP"]
E [label="100"]
E -> El [label="L"]
El [label="DESCEND"]
El -> Ell
Ell [label="..."]
El -> Elr
Elr [label="..."]
E -> Er [label="R"]
Er [label="VERIFY"]
row1 -> invis [style=invis]
invis [shape=none, label=""]
invis -> C [style=invis]
{ rank = same; C; D; E; }
F [label="101"]
F -> Fl [label="L"]
Fl [label="DESCEND"]
Fl -> Fll
Fll [label="..."]
Fl -> Flr
Flr [label="..."]
F -> Fr [label="R"]
Fr [label="DESCEND"]
Fr -> Frl
Frl [label="..."]
Fr -> Frr
Frr [label="..."]
G [label="110"]
G -> Gl [label="L"]
Gl [label="SKIP"]
G -> Gr [label="R"]
Gr [label="VERIFY"]
H [label="111"]
H -> Hl [label="L"]
Hl [label="SKIP"]
H -> Hr [label="R"]
Hr [label="DESCEND"]
Hr -> Hrl
Hrl [label="..."]
Hr -> Hrr
Hrr [label="..."]
Crl -> F [style=invis]
{ rank = same; F; G; H; }
}
================================================
FILE: bip-0098/skip-skip.dot
================================================
digraph G {
A [label="???"]
A -> Al [label="L"]
Al [label="SKIP"]
A -> Ar [label="R"]
Ar [label="SKIP"]
}
================================================
FILE: bip-0098/traversal-example.dot
================================================
digraph G {
a [label="A\n101"]
a -> b
a -> c
b [label="B\n111"]
b -> s0
s0 [label="SKIP\n0x00..."]
b -> d
d [label="D\n011"]
d -> f
d -> s1
s1 [label="SKIP\n0x22..."]
f [label="F\n000"]
f -> v1
v1 [label="VERIFY\n0x55..."]
f -> s2
s2 [label="SKIP\n0x66..."]
c [label="C\n010"]
c -> v2
v2 [label="VERIFY\n0x11..."]
c -> e
e [label="E\n001"]
e -> v3
v3 [label="VERIFY\n0x33..."]
e -> v4
v4 [label="VERIFY\n0x44..."]
}
================================================
FILE: bip-0098/unbalanced-hash-tree.dot
================================================
digraph G {
0 [label="Root\nH(A || H(B || C))"]
0 -> A
A [label="A\nskip"]
0 -> 1
1 [label="Node\nH(B || C)"]
1 -> B
B [label="B\nskip"]
1 -> C
C [label="C\nverify"]
}
================================================
FILE: bip-0098.mediawiki
================================================
BIP: 98
Layer: Consensus (soft fork)
Title: Fast Merkle Trees
Authors: Mark Friedenbach
Kalle Alm
BtcDrak
Status: Draft
Type: Specification
Assigned: 2017-08-24
License: CC-BY-SA-4.0
License-Code: MIT
==Abstract==
In many applications it is useful to prove membership of a data element in a set without having to reveal the entire contents of that set.
The Merkle hash-tree, where inner/non-leaf nodes are labeled with the hash of the labels or values of its children, is a cryptographic tool that achieves this goal.
Bitcoin uses a Merkle hash-tree construct for committing the transactions of a block into the block header.
This particular design, created by Satoshi, suffers from a serious flaw related to duplicate entries documented in the National Vulnerability Database as CVE-2012-2459[1], and also suffers from less than optimal performance due to unnecessary double-hashing.
This Bitcoin Improvement Proposal describes a more efficient Merkle hash-tree construct that is not vulnerable to CVE-2012-2459
and achieves an approximate 55% decrease in hash-tree construction and validation times as compared with fully optimized implementations of the Satoshi Merkle hash-tree construct.
==Copyright==
This BIP is licensed under a Creative Commons Attribution-ShareAlike license. All provided source code is licensed under the MIT license.
==Motivation==
A Merkle hash-tree is a directed acyclic graph data structure where all non-terminal nodes are labeled with the hash of combined labels or values of the node(s) it is connected to.
Bitcoin uses a unique Merkle hash-tree construct invented by Satoshi for calculating the block header commitment to the list of transactions in a block.
While it would be convenient for new applications to make use of this same data structure so as to share implementation and maintenance costs, there are three principal drawbacks to reuse.
First, Satoshi's Merkle hash-tree has a serious vulnerability[1] related to duplicate tree entries that can cause bugs in protocols that use it.
While it is possible to secure protocols and implementations against exploit of this flaw, it requires foresight and it is a bit more tricky to design secure protocols that work around this vulnerability.
Designers of new protocols ought avoid using the Satoshi Merkle hash-tree construct where at all possible in order to responsibly decrease the likelihood of downstream bugs in naïve implementations.
Second, Satoshi's Merkle hash-tree performs an unnecessary number of cryptographic hash function compression rounds, resulting in construction and validation times that are approximately three (3) times more computation than is strictly necessary in a naïve implementation, or 2.32x more computation in an implementation specialized for this purpose only[2].
New implementations that do not require backwards compatibility ought to consider hash-tree implementations that do not carry this unnecessary performance hit.
Third, Satoshi's algorithm presumes construction of a tree index from an ordered list, and therefore is designed to support balanced trees with a uniform path length from root to leaf for all elements in the tree.
Many applications, on the other hand, benefit from having unbalanced trees, particularly if the shorter path is more likely to be used.
While it is possible to make a few elements of a Satoshi hash-tree have shorter paths than the others, the tricks for doing so are dependent on the size of the tree and not very flexible.
Together these three reasons provide justification for specifying a standard Merkle hash-tree structure for use in new protocols that fixes these issues.
This BIP describes such a structure, and provides an example implementation.
==Specification==
A Merkle hash-tree as defined by this BIP is an arbitrarily-balanced binary tree whose terminal/leaf nodes are labelled with the double-SHA256 hashes of data, whose format is outside the scope of this BIP, and inner nodes with labels constructed from the fast-SHA256 hash of its children's labels.
The following image depicts an example unbalanced hash-tree:
:: [[File:bip-0098/unbalanced-hash-tree.png]]
'''A''', '''B''', and '''C''' are leaf labels, 32-byte double-SHA256 hashes of the data associated with the leaf.
'''Node''' and '''Root''' are inner nodes, whose labels are fast-SHA256 (defined below) hashes of their respective children's labels.
'''Node''' is labelled with the fast-SHA256 hash of the concatenation of '''B''' and '''C'''.
'''Root''' is labelled with the fast-SHA256 hash of the concatenation of '''A''' and '''Node''', and is the ''Merkle root'' of the tree.
Nodes with single children are not allowed.
The ''double-SHA256'' cryptographic hash function takes an arbitrary-length data as input and produces a 32-byte hash by running the data through the SHA-256 hash function as specified in FIPS 180-4[3], and then running the same hash function again on the 32-byte result, as a protection against length-extension attacks.
The ''fast-SHA256'' cryptographic hash function takes two 32-byte hash values, concatenates these to produce a 64-byte buffer, and applies a single run of the SHA-256 hash function with a custom 'initialization vector' (IV) and without message padding.
The result is a 32-byte 'midstate' which is the combined hash value and the label of the inner node.
The changed IV protects against path-length extension attacks (grinding to interpret a hash as both an inner node and a leaf).
fast-SHA256 is only defined for two 32-byte inputs.
The custom IV is the intermediate hash value generated after performing a standard SHA-256 of the following hex-encoded bytes and extracting the midstate:
cbbb9d5dc1059ed8 e7730eaff25e24a3 f367f2fc266a0373 fe7a4d34486d08ae
d41670a136851f32 663914b66b4b3c23 1b9e3d7740a60887 63c11d86d446cb1c
This data is the first 512 fractional bits of the square root of 23, the 9th prime number.
The resulting midstate is used as IV for the fast-SHA256 cryptographic hash function:
static unsigned char _MidstateIV[32] =
{ 0x89, 0xcc, 0x59, 0xc6, 0xf7, 0xce, 0x43, 0xfc,
0xf6, 0x12, 0x67, 0x0e, 0x78, 0xe9, 0x36, 0x2e,
0x76, 0x8f, 0xd2, 0xc9, 0x18, 0xbd, 0x42, 0xed,
0x0e, 0x0b, 0x9f, 0x79, 0xee, 0xf6, 0x8a, 0x24 };
As fast-SHA256 is only defined for two (2) 32-byte hash inputs, there are necessarily two special cases:
an empty Merkle tree is not allowed, nor is any root hash defined for such a "tree";
and a Merkle tree with a single value has a root hash label equal to that self-same value of the leaf branch, the only node in the tree (a passthrough operation with no hashing).
===Rationale===
The fast-SHA256 hash function can be calculated 2.32x faster than a specialized double-SHA256 implementation[2], or three (3) times faster than an implementation applying a generic SHA-256 primitive twice,
as hashing 64 bytes of data with SHA-256 as specified by FIPS 180-4[3] takes two compression runs (because of message padding) and then a third compression run for the double-SHA256 construction.
Validating a fast-SHA256 Merkle root is therefore more than twice as fast as the double-SHA256 construction used by Satoshi in bitcoin.
Furthermore the fastest fast-SHA256 implementation ''is'' the generic SHA-256 implementation, enabling generic circuitry and code reuse without a cost to performance.
The application of fast-SHA256 to inner node label updates is safe in this limited domain because the inputs are hash values and fixed in number and in length,
so the sorts of attacks prevented by message padding and double-hashing do not apply.
The 'initialization vector' for fast-SHA256 is changed in order to prevent a category of attacks on higher level protocols where a partial collision can serve as both a leaf hash and as an inner node commitment to another leaf hash.
The IV is computed using standard SHA-256 plus midstate extraction so as to preserve compatibility with cryptographic library interfaces that do not support custom IVs, at the cost of a 2x performance hit if neither custom IVs nor resuming from midstate are supported.
The data hashed is a nothing-up-my-sleeve number that is unlikely to have a known hash preimage.
The prime 23 was chosen as the leading fractional bits of the first eight (8) primes, two (2) through nineteen (19), are constants used in the setup of SHA-256 itself.
Using the next prime in sequence reduces the likelihood of introducing weakness due to reuse of a constant factor.
The Merkle root hash of a single element tree is a simple pass-through of the leaf hash without modification so as to allow for chained validation of split proofs.
This is particularly useful when the validation environment constrains proof sizes, such as push limits in Bitcoin script.
Chained validation allows a verifier to split one proof into two or more, where the leaf is shown to be under an inner node, and that inner node is shown to be under the root.
Without pass-through hashing in a single-element tree, use of chained validation would unnecessarily introduce a minimum path length requirement equal to the number of chain links.
Pass-through hashing of single elements allows instead for one or more of the chained validations to use a "NOP" proof consisting of a zero-length path,
thereby allowing, for example, a fixed series of four (4) chained validations to verify a length three (3) or shorter path.
==Inclusion Proofs==
An important use of Merkle hash-trees is the ability to compactly prove membership with log-sized proofs.
This section specifies a standard encoding for a multi-element inclusion proof.
To prove that a set of hashes is contained within a Merkle tree with a given root requires four pieces of information:
# The root hash of the Merkle tree;
# The hash values to be verified, a set usually consisting of the double-SHA256 hash of data elements, but potentially the labels of inner nodes instead, or both;
# The paths from the root to the nodes containing the values under consideration, expressed as a serialized binary tree structure; and
# The hash values of branches not taken along those paths.
Typically the last two elements, the paths and the elided branch hashes, are lumped together and referred to as the ''proof''.
Serialization begins with a variable-length integer (VarInt) used to encode N, the number of internal nodes in the proof.
Next the structure of the tree is traversed using depth-first, left-to-right, pre-order algorithm to visit each internal nodes, which are serialized using a packed 3-bit representation for the configuration of each node, consuming (3*N + 7) / 8 bytes.
Then the number skipped hashes (those included in the proof, not verified by the proof) is serialized as a variable-length integer (VarInt),
followed by the hashes themselves in the order previously traversed.
There are eight possible configurations of internal nodes, as given in the following diagram:
:: [[File:bip-0098/node-variants.png]]
In this diagram, DESCEND means the branch links to another internal node, as indicated by its child graph elements labeled "...";
SKIP means the branch contains a hash of an elided subtree or element, and the fast-SHA256 root hash of this subtree or double-SHA256 hash of the element is included in the proof structure; and
VERIFY means the branch contains an externally provided hash that is needed as witness for the verification of the proof.
In tabular form, these code values are:
{| class="wikitable"
|-
| scope="col"| Code
| scope="col"| Left
| scope="col"| Right
|-
| scope="row"| 000
| VERIFY
| SKIP
|-
| scope="row"| 001
| VERIFY
| VERIFY
|-
| scope="row"| 010
| VERIFY
| DESCEND
|-
| scope="row"| 011
| DESCEND
| SKIP
|-
| scope="row"| 100
| DESCEND
| VERIFY
|-
| scope="row"| 101
| DESCEND
| DESCEND
|-
| scope="row"| 110
| SKIP
| VERIFY
|-
| scope="row"| 111
| SKIP
| DESCEND
|}
These 3-bit codes are packed into a byte array such that eight (8) codes would fit in every three (3) bytes.
The order of filling a byte begins with the most significant bit 0x80 and ends with the least significant bit 0x01.
Unless the number of inner nodes is a multiple of eight (8), there will be excess low-order bits in the final byte of serialization.
These excess bits must be zero.
Note that the tree serialization is self-segmenting.
By tracking tree structure a proof reader will know when the parser has reached the last internal node.
The number of inner nodes serialized in the proof MUST equal the number of nodes inferred from the tree structure itself.
Similarly, the number of SKIP hashes can also be inferred from the tree structure as serialized, and MUST equal the number of hashes provided within the proof.
The single-hash proof has N=0 (the number of inner nodes),
the tree structure is not serialized (as there are no inner nodes),
and the number of SKIP hashes can be either 0 or 1.
===Example===
Consider the following Merkle tree structure:
:: [[File:bip-0098/traversal-example.png]]
There are six (6) internal nodes.
The depth-first, left-to-right, pre-order traversal of the tree visits these nodes in the following order: A, B, D, F, C, then E.
There are three (3) skipped hashes, visited in the following order: 0x00..., 0x66..., and 0x22...
The remaining four (4) hashes are provided at runtime to be verified by the proof.
{|
| scope="col"|
| scope="col"| Byte 1
| scope="col"| Byte 2
| scope="col"| Byte 3
|-
| scope="row"| Bits
| 76543210
| 76543210
| 76543210
|-
| scope="row"| Nodes
| AAABBBDD
| DFFFCCCE
| EE------
|-
| scope="row"| Code
| 10111101
| 10000100
| 01000000
|}
The serialization begins with the VarInt encoded number of inner nodes, 0x06, followed by the tree serialization itself, 0xbd8440.
Next the number of SKIP hashes is VarInt encoded, 0x03, followed by the three (3) hashes in sequence.
The resulting 101 byte proof, encoded in base64:.
Br2EQAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGZmZmZmZmZmZmZmZmZmZmZmZmZm
ZmZmZmZmZmZmZmZmREREREREREREREREREREREREREREREREREREREREREQ=
===Rationale===
The 3-bit encoding for inner nodes allows encoding all relevant configurations of the nodes where the left and right branches can each be one of {DESCEND, SKIP, VERIFY}.
The excluded 9th possibility would have both branches as SKIP:
:: [[File:bip-0098/skip-skip.png]]
This possibility is not allowed as for verification purposes it is entirely equivalent to the shorter proof where the branch to that node was SKIP'ed.
Disallowing a node with two SKIP branches eliminates what would otherwise be a source of proof malleability.
The number of hashing operations required to verify a proof is one less than the number of hashes (SKIP and VERIFY combined),
and is exactly equal to the number of inner nodes serialized as the beginning of the proof as N.
The variable-length integer encoding has the property that serialized integers, sorted lexicographically, will also be sorted numerically.
Since the first serialized item is the number of inner nodes, sorting proofs lexicographically has the effect of sorting the proofs by the amount of work required to verify.
The number of hashes required as input for verification of a proof is N+1 minus the number of SKIP hashes,
and can be quickly calculated without parsing the tree structure.
The coding and packing rules for the serialized tree structure were also chosen to make lexicographical comparison useful (or at least not meaningless).
If we consider a fully-expanded tree (no SKIP hashes, all VERIFY) to be encoding a list of elements in the order traversed depth-first from left-to-right,
then we can extract proofs for subsets of the list by SKIP'ing the hashes of missing values and recursively pruning any resulting SKIP,SKIP nodes.
Lexicographically comparing the resulting serialized tree structures is the same as lexicographically comparing lists of indices from the original list verified by the derived proof.
Because the number of inner nodes and the number of SKIP hashes is extractible from the tree structure,
both variable-length integers in the proof are redundant and could have been omitted.
However that would require either construction and storage of the explicit tree in memory at deserialization time,
or duplication of the relatively complicated tree parsing code in both the serialization and verification methods.
For that reason (as well as to handle the single-hash edge case) the redundant inner node and SKIP hash counts are made explicit in the serialization,
and the two values must match what is inferred from the tree structure for a proof to be valid.
This makes deserialization trivial and defers tree construction until verification time,
which has the additional benefit of enabling log-space verification algorithms.
==Fast Merkle Lists==
Many applications use a Merkle tree to provide indexing of, or compact membership proofs about the elements in a list.
This addendum specifies an algorithm that constructs a canonical balanced tree structure for lists of various lengths.
It differs in a subtle but important way from the algorithm used by Satoshi so as to structurally prevent the vulnerability described in [1].
# Begin with a list of arbitrary data strings.
# Pre-process the list by replacing each element with its double-SHA256 hash.
# If the list is empty, return the zero hash.
# While the list has 2 or more elements,
#* Pass through the list combining adjacent entries with the fast-SHA256 hash. If the list has an odd number of elements, leave the last element as-is (this fixes [1]). This step reduces a list of N elements to ceil(N/2) entries.
# The last remaining item in the list is the Merkle root.
This algorithm differs from Merkle lists used in bitcoin in two ways.
First, fast-SHA256 is used instead of double-SHA256 for inner node labels.
Second, final entries on an odd-length list are not duplicated and hashed, which is the mistake that led to CVE-2012-2459[1].
==Implementation==
An implementation of this BIP for extraction of Merkle branches and fast, log-space Merkle branch validation is available at the following Github repository:
[https://github.com/maaku/bitcoin/tree/fast-merkle-tree]
Also included in this repo is a 'merklebranch' RPC for calculating root values and extracting inclusion proofs for both arbitrary trees and trees constructed from lists of values using the algorithm in this BIP,
and a 'mergemerklebranch' RPC for unifying two or more fast Merkle tree inclusion proofs--replacing SKIP hashes in one proof with a subtree extracted from another.
==Deployment==
This BIP is used by BIP116 (MERKLEBRANCHVERIFY)[4] to add Merkle inclusion proof verification to script by means of a soft-fork NOP expansion opcode.
Deployment of MERKLEBRANCHVERIFY would make the contents of this BIP consensus critical.
The deployment plan for BIP116 is covered in the text of that BIP.
==Compatibility==
This BIP on its own does not cause any backwards incompatibility.
==References==
[1] [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2459 National Vulnerability Database: CVE-2012-2459]
[2] [https://github.com/sipa/bitcoin/tree/201709_dsha256_64 github.com:sipa/bitcoin 201709_dsha256_64] Pieter Wuille, September 2017, personal communication. By making use of knowledge that the inputs at each stage are fixed length, Mr. Wuille was able to achieve a 22.7% reduction in the time it takes to compute the double-SHA256 hash of 64 bytes of data, the hash aggregation function of the Satoshi Merkle tree construction.
[3] [http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf Secure Hash Standard]
[4] [https://github.com/bitcoin/bips/blob/master/bip-0116.mediawiki BIP 116 MERKLEBRANCHVERIFY]
================================================
FILE: bip-0099.mediawiki
================================================
==Abstract==
This BIP attempts to create a taxonomy of the different types of
consensus forks and proposes a deployment mechanism for each of them.
==Motivation==
The security assumptions of p2p consensus-based systems like Bitcoin are
not always well-understood, and the best upgrade mechanisms to the
consensus validation rules may vary depending on the type of change being deployed.
Discussing such changes without a uniform view on the deployment
paths often leads to misunderstandings and unnecessarily delays the
deployment of changes.
==Definitions==
;Software fork
: A copy of an existing project. In free software, this can be done without the permission of the original project's maintainers.
;Consensus fork
: A divergence in the implementation of the verification consensus rules can impede the expected eventual convergence of the network in a single chain that has the most proof of work and also satisfies the rules. This can be intentional or be caused by a bug in consensus validation reimplementations.
;Softfork
: A consensus fork wherein everything that was previously invalid remains invalid while blocks that would have previously considered valid become invalid. A hashrate majority of miners can impose the new rules. They have some deployment advantages like backward compatibility.
;Hardfork
: A consensus fork that makes previously invalid blocks valid. Hardforks require all users to upgrade.
;Libconsensus
: a theoretical piece of software that contains the specifications that define the validity of a block for a given state and chain parameters (ie it may act differently on, for example, regtest).
;Libbitcoinconsensus
: the existing implementation is a library that is compiled by default with Bitcoin Core master and exposes a single C function named bitcoinconsensus_verify_script(). Although it has a deterministic build and implements the most complex rules (most of the cryptography, which is itself heavily based on libsecp256k1 after #REPLACE_libsecp256k1_PR), it is still not a complete specification of the consensus rules. Since libconsensus doesn't manage the current state but only the validation of the next block given that state, it is known that this long effort of encapsulation and decoupling will eventually finish, and that the person who moves the last line
==Taxonomy of consensus forks==
===Accidental consensus fork===
Software forks are very different in nature from consensus rules forks. No software
maintainer has special powers over consensus rules changes. There's
many good reasons (experimentation, lack of features, independent
development, diversity, etc) to fork the Bitcoin Core software and it's good
that there's many alternative implementations of the protocol (forks
of Bitcoin Core or written from scratch).
But sometimes a bug in the reimplementation of the consensus
validation rules can prevent users of alternative implementation from
following the longest (most work) valid chain. This can result in
those users losing coins or being defrauded, making reimplementations
of the consensus validation rules very risky. Note that a natural
language specification of those rules doesn't help since the
consensus is not determined by such specification but by the software
that the majority of the network runs. That's why "the implementation
is the specification".
But Bitcoin Core contains many more things than just consensus
validation and it would be unreasonable for all alternative
implementations to depend on it. Bitcoin Core should not be the
specification. That's why the consensus validation is being separated
into a libbitcoinconsensus library with a C API easily accessible from
any language. This makes alternative implementations much more secure
without burdening them with specific design choices made by Bitcoin
Core. It is to be noted that sharing the same code for consensus
validation doesn't prevent alternative implementations from
independently changing their consensus rules: they can always fork
the libbitcoinconsensus project (once it is in a separate repository).
Hopefully libbitcoinconsensus will remove this type of consensus fork
which - being accidental - obviously doesn't need a deployment plan.
====11/12 March 2013 Chain Fork====
There is a precedent of an accidental consensus fork at height 225430.
Without entering into much detail (see https://github.com/bitcoin/bips/blob/master/bip-0050.mediawiki), the situation was different from
what's being described from the alternative implementation risks (today alternative implementation
still usually rely in different degrees on Bitcoin Core trusted proxies, which
is very reasonable considering the lack of a complete libconsensus).
The two conflicting consensus validation implementations were two
different versions of Bitcoin Core (Bitcoin-qt at the time): 0.8
against all versions prior to it. Most miners had been fast on
upgrading to 0.8 and they were also fast on downgrading to 0.7 as an
emergency when they were asked to by the developers community.
A short summary would be that BDB was being
abandoned in favor of levelDB, and - at the same time - the miner's
policy block size limit was being lift (it was not a consensus rule,
not even enforced via softfork). Even after testing, a case where
levelDB couldn't correctly validate certain bigger blocks only appeared after
deployment in production. Fortunately this was handled very well and
rapidly by the whole worldwide community and nobody is unhappy about
the solution.
But there's some philosophical disagreements on the terms of what the
solution was: we can add a pedantic note on that.
If "the implementation is the specification", then those
levelDB-specific limitations were part of the consensus rules.
Then additional rules were necessary and any alternative
implementation (including 0.8) would have to implement it. Then a
planned consensus fork to migrate all Bitcoin-qt 0.7- users could
remove those additional consensus restrictions.
Had libconsensus being implemented without depending on levelDB,
those additional restrictions wouldn't have been part of "the specification"
and this would just have been a bug in the
consensus rules, just a consensus-critical bug in a set of
implementations, concretely all satoshi-bitcoin-0.7-or-less (which
happened to be a huge super majority of the users), but other
implementations (like libbitcoin) would be free from such bug and
implementing the correct libconsensus specification. But since the
buggy implementation was a super-majority, the solution would have
been to instantly (from a specific block) change the rules to not let
the super-majority deviate from the specification and then have
another consensus fork to remove them. Two theoretical consensus forks
instead of one but the first one deployed practically for free. The
practical result would have been identical and only the definitions
change. This means discussing something that went uncontroversially
well further is "philosophical bike-shed" (TM).
===Unilateral softforks===
If it is in their best interest of miners to softfork it should be
assumed that they may likely enforce it. In some cases, even against the will of a
super-majority of users. This is practically an attack on the network
and the only solution is to carefully design the incentives so that
the case is simply impossible. If that fails, miners should still
consider the risk of motivating a schism hardfork before attempting
such a consensus fork. A deployment plan for this case is also
unnecessary.
===Schism hardforks===
Fundamental disagreements and controversies are part of social
systems, like the one defined as the human participants in the Bitcoin
network. Without judging the motivation of the rule discrepancies or
what rules were in place first, we're defining schismhttps://en.wikipedia.org/wiki/Schism hardforks as
those in which - for whatever reason - users are consciously going to validate 2
different sets of consensus rules. Since they will validate different
rulesets, they will end up following 2 different chains for at least
some time, maybe forever.
One possible result observed in the past
is that one of the chains rapidly disappears, but nothing indicates
that this must always be the case.
While 2 chains coexist, they can be considered two different
currencies.
We could say that bitcoin becomes bitcoinA and bitcoinB. The implications for market
capitalization are completely unpredictable,
maybe mc(bitcoinA) = mc(bitcoinB) = mc(old_bitcoin),
maybe mc(bitcoinA) + mc(bitcoinB) = mc(old_bitcoin),
maybe mc(bitcoinA) + mc(bitcoinB) = 1000 * mc(old_bitcoin),
maybe mc(bitcoinA) + mc(bitcoinB) = 0,
...
Schism hardforks have been compared to one type of altcoins called
"spinoffs"https://bitcointalk.org/index.php?topic=563972.0 that distribute all or part of its initial seigniorage to
bitcoin owners at a given block height.
This is very disruptive and hopefully will never be needed. But if
it's needed the best deployment path is just to activate the rule
changes after certain block height in the future. On the other hand,
it is healthy decentralization-wise that many independent software
projects are ready to deploy a schism hardfork.
In all of the following examples there's clearly a confrontation that
is being resolved using an intentional consensus hardfork.
====ASIC-reset hardfork====
Imagine ASIC production has been consolidated to a single company and
distribution is simply not happening: the company is keeping them to
mine itself. For that or another reason, a single entity controls
40%+ of the hashrate and there's no hope for an spontaneous
improvement in decentralization. Such an untenable centralization could
be fixed (with great risks) by switching the hash function used in the
proof of work, effectively "pressing the restart button" on the ASIC
market. The next function should be simple to implement in ASIC as
well so that the market can more easily develop as a healthy and
competitive one (as opposed to what the "ASIC-hard" proponents would
want), but that's another story...]
Since in this case the confrontation is clearly against the current
miners any notion of "miners' voting" is utterly irrelevant.
====Anti-Block-creator hardfork====
There's less extreme cases where changing the pow function would not
be necessary. For example, let's imagine a bright future where
commoditized ASICs are running in millions home-heaters all over the
world, but the block size has been completely removed and the network has devolved to a
very centralized system where only 2 big pools have the resources to
fully validate full blocks and create block templates with competitive levels of
transaction fees. In that case, changing the pow function would be a
terrible waste and a risk that could be avoided. A hardfork restoring
a block size limit could help fixing this situation. Please don't
take it as an argument for or against raising the block size limit:
it's just an example. But in this case, again, those 2 big pools
would probably be against the fork and, again, their voting is
irrelevant.
Like in the previous example, miners are expected to oppose and they
have to be ignored.
====Anti-cabal hardfork====
Let's imagine BIP66 had a crypto backdoor
that nobody noticed and allows an evil developer cabal to steal
everyone's coins. The users and non-evil developers could join, fork
libconsensus and use the forked version in their respective bitcoin
implementations.
Should miner's "vote" be required to express their consent? What if some miners
are part of the cabal? In the unlikely event that most miners are
part of such an evil cabal, changing the pow function may be
required. In other cases, mining "vote" doesn't have much value
either since this kind of hardfork would not qualify as
uncontroversial anyway.
===Uncontroversial consensus upgrades===
"Uncontroversial" is something tough to define in this context. What
if a single user decides he won't upgrade no matter what and
he doesn't even attempt to explain his decision? Obviously, such
a user should be just ignored. But what if the circumstances are
slightly different? What if they're 2, 10 users? where's the line.
It is possible that we can never have a better definition than "I know
it when I see it" [citation needed].
====Uncontroversial softforks====
If a majority of miners adopts a softfork, users will follow that
chain, even without understanding the new rules. For them is like
if blocks are created in a certain way or certain valid transactions
are being rejected by miners for some reason. For old nodes it just
looks like the new rules are policy rules rather than consensus rules.
This greatly reduces the deployment risks, making softforks the
preferred consensus rules upgrade mechanism.
The first precedent of a softfork was the introduction of P2SH
documented in BIP16. There were competing proposals, but BIP12 had
clear disadvantage and BIP17 was considered a less tested but
functionally equivalent version by most of the reviewers. Although it
was later discovered that BIP16 had unnecessary limitations and BIP17
is now considered superior, this probably still qualified for our
vague concept of "uncontroversial".
At the time, there was no "mining voting" implementation and it was
simply deployed using the timestamp of the blocks at some time in the
future as the activation trigger. This can't guarantee the assumption
that most miners have upgraded before enforcing the new rules and
that's why the voting mechanism and first used for BIP30 and BIP66.
The current voting threshold for softfork enforcement is 95%. There's
also a 75% threshold for miners to activate it as a policy rule, but
it should be safe for miners to activate such a policy from the start
or later than 75%, as long as they enforce it as consensus rule after 95%.
The current miners' voting mechanism can be modified to allow for
changes to be deployed in parallel, the rejection of a concrete
softfork without getting locked for the deployment of the next one,
and also a more efficient use of the version field in block
headershttps://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki. BIP65 is expected to be deployed with the improved
mechanism.
====Uncontroversial hardforks====
Some consensus changes require all participants to upgrade their software
before the new rules can be safely activated or they will face serious
risk of following the wrong chain and being defrauded. Even if the
exact same mechanism used for softforks would be more risky in these
cases, that doesn't mean that this type of changes cannot be deployed
in an uncontroversial and safe manner.
The simplest approach is to select a block height far enough in the
future that everybody has plenty of time to change their software.
But if you're aiming for universal adoption, that includes miners'
adoption, so it seems reasonable to use a mining voting on top of
that. In this case there's only one relevant threshold and it could
be different from the softfork one. Probably 100% is too strict,
since it would allow a relatively small miner to attack the network
and block a consensus upgrade. Something between 99% and 95% is
probably a sensible choice for this parameter.
====Uncontroversial emergency hardforks====
Emergency forks may not have time to consult miners and have to be
deployed simply by choosing a block height not so far in the future.
But emergency forks could be prepared ahead of time. For example, an
intermediary version of software could allow blocks
that are double the size of old blocks (after a certain height in the
future) while still making miners reject bigger blocks as a softfork
rule. Then miners can start the regular process for uncontroversial
softfork (or a unilateral softfork if they're a majority) at any
point in the future if it is required, and both intermediary and new
versions would be prepared for it (which would make deployment much
easier). Other related consensus changes could be deployed in the
meantime (say, quadrupling the block size) making the emergency
softfork unnecessary.
==Code==
This BIP is complemented with a concrete code proposalhttps://github.com/jtimon/bitcoin/tree/hardfork-timewarp-0.11 for an
uncontroversial hardfork which acts as a precedent and removes the
perception that hardforks are impossible in Bitcoin. The deployment of
the proposal should not block any other potential hardforks (thus it
will required the version bits proposal to be implemented). The
change itself doesn't add much complexity to Bitcoin Core and is simple
enough that is trivial to apply to diverse implementations (that
currently can only use libbitcoinconsensus to validate script-related
rules). The change has been already widely tested in many altcoins.
The chosen consensus change is the fix of the timewarp attack
discovered and also fixed with a simple patch
Original References:
https://bitcointalk.org/index.php?topic=114751.0,
https://bitcointalk.org/index.php?topic=43692.msg521772#msg521772;
Rebased patch:
https://github.com/freicoin/freicoin/commit/beb2fa54745180d755949470466cbffd1cd6ff14
by @ArtForz. This
change has been deployed by most altcoins that made any minimally
meaningful change to bitcoin and thus can be considered somewhat
tested (in fact, most SHA256d altcoins that didn't implement it have
died or being forced to implement it as an emergency hardfork). When
deploying this change has been discussed, usually arguments in the
lines of "if we get to the point when this matters to bitcoin, we
would be already in serious trouble" were used against it. This
shouldn't be seen as a disadvantage in this context, since it means we
can safely activate the fix very far away in the future (say, 4 years
worth of blocks).
==Footnotes==
==Attribution==
Incorporated corrections and suggestions from: Andy Chase, Bryan Bishop,
Btcdrak, Gavin Andresen, Gregory Sanders, Luke Dashjr, Marco Falke.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0100.mediawiki
================================================
BIP: 100
Layer: Consensus (hard fork)
Title: Dynamic maximum block size by miner vote
Authors: Jeff Garzik
Tom Harding
Dagur Valberg Johannsson
Status: Closed
Type: Specification
Assigned: 2015-06-11
License: BSD-2-Clause
==Abstract==
Replace the static 1M block size hard limit with a hard limit set by coinbase vote, conducted on the same schedule as difficulty retargeting.
==Motivation==
Miners directly feel the effects, both positive and negative, of any maximum block size change imposed by their peers. Larger blocks allow more growth in the on-chain ecosystem, while smaller blocks reduce resource requirements network-wide. Miners also act as an efficient proxy for the rest of the ecosystem, since they are paid in the tokens collected for the blocks they create.
A simple deterministic system is specified, whereby a 75% mining supermajority may activate a change to the maximum block size each 2016 blocks. Each change is limited to a 5% increase from the previous block size hard limit, or a decrease of similar magnitude. Among adopting nodes, there will be no disagreement on the evolution of the maximum block size.
The system is compatible with emergent consensus, but whereas under that system a miner may choose to accept any size block, a miner following BIP100 observes the 75% supermajority rule, and the 5% change limit rule. Excessive-block values signaled by emergent consensus blocks are considered in the calculation of the BIP100 block size hard limit, and the BIP100 calculated maximum block size is signaled as an excessive-block value for the benefit of all observers.
==Specification==
===Dynamic Maximum Block Size===
# Initial value of hardLimit is 1000000 bytes, preserving current system.
# Changing hardLimit is accomplished by encoding a proposed value, a vote, within a block's coinbase scriptSig, and by processing the votes contained in the previous retargeting period.
## Vote encoding
### A vote is represented as a megabyte value using the BIP100 pattern
/BIP100/B[0-9]+/
Example: /BIP100/B8/ is a vote for a 8000000-byte hardLimit.
### If the block height is encoded at the start of the coinbase scriptSig, as per BIP34, it is ignored.
### Only the first BIP100 pattern match is processed in "Maximum block size recalculation" below.
### A megabyte value is represented by consecutive base-ten digits.
### If no BIP100 pattern is matched, the first matching emergent consensus pattern /EB[0-9]+/, if any, is accepted as the megabyte vote.
## Maximum block size recalculation
### A new hardLimit is calculated after each difficulty adjustment period of 2016 blocks, and applies to the next 2016 blocks.
### Absent/zero-valued votes are counted as votes for the current hardLimit.
### The votes of the previous 2016 blocks are sorted by megabyte vote.
### Raising hardLimit
#### The raise value is defined as the vote of the 1512th highest block, converted to bytes.
#### If the resultant raise value is greater than (current hardLimit * 1.05) rounded down, it is set to that value.
#### If the resultant raise value is greater than current hardLimit, the raise value becomes the new hardLimit and the recalculation is complete.
### Lowering hardLimit
#### The lower value is defined as the vote of the 1512th lowest block, converted to bytes.
#### If the resultant lower value is less than (current hardLimit / 1.05) rounded down, it is set to that value.
#### If the resultant lower value is less than current hardLimit, the lower value becomes the new hardLimit and the recalculation is complete.
### Otherwise, new hardLimit remains the same as current hardLimit.
===Signature Hashing Operations Limits===
# The per-block signature hashing operations limit is scaled to (actual block size, fractional megabyte rounded to next higher megabyte) / 50.
# A maximum serialized transaction size of 1000000 bytes is imposed.
==Recommendations==
===Publication of hardLimit===
# For the benefit of all observers, it is recommended that hardLimit be published. Example: a complete coinbase string might read
/BIP100/B8/EB2.123456/
which indicates a vote for 8M maximum block size, and an enforced hardLimit of 2.123456 megabytes for the block containing the coinbase string.
==Deployment==
This BIP is presumed deployed and activated as of block height 449568 by implementing nodes on the bitcoin mainnet. It has no effect until a raise value different from 1M is observed, which requires at least 1512 of 2016 blocks to vote differently from 1M.
==Backward compatibility==
The first block larger than 1M will create a network partition, as nodes with a fixed 1M hard limit reject that block.
==Implementations==
https://github.com/bitcoinxt/bitcoinxt/pull/188
https://github.com/bitcoinxt/bitcoin/pull/1
https://github.com/BitcoinUnlimited/BitcoinUnlimited/pull/398
==Copyright==
This document is licensed under the BSD 2-clause license.
================================================
FILE: bip-0101.mediawiki
================================================
==Abstract==
This BIP proposes replacing the fixed one megabyte maximum block size with a maximum size that grows over time at a predictable rate.
==Motivation==
Transaction volume on the Bitcoin network has been growing, and will soon reach the one-megabyte-every-ten-minutes limit imposed by the one megabyte maximum block size. Increasing the maximum size reduces the impact of that limit on Bitcoin adoption and growth.
==Specification==
After deployment (see the Deployment section for details), the maximum allowed size of a block on the main network shall be calculated based on the timestamp in the block header.
The maximum size shall be 8,000,000 bytes at a timestamp of 2016-01-11 00:00:00 UTC (timestamp 1452470400), and shall double every 63,072,000 seconds (two years, ignoring leap years), until 2036-01-06 00:00:00 UTC (timestamp 2083190400). The maximum size of blocks in between doublings will increase linearly based on the block's timestamp. The maximum size of blocks after 2036-01-06 00:00:00 UTC shall be 8,192,000,000 bytes.
Expressed in pseudo-code, using integer math, assuming that block_timestamp is after the activation time (as described in the Deployment section below):
function max_block_size(block_timestamp):
time_start = 1452470400
time_double = 60*60*24*365*2
size_start = 8000000
if block_timestamp >= time_start+time_double*10
return size_start * 2^10
// Piecewise-linear-between-doublings growth:
time_delta = block_timestamp - time_start
doublings = time_delta / time_double
remainder = time_delta % time_double
interpolate = (size_start * 2^doublings * remainder) / time_double
max_size = size_start * 2^doublings + interpolate
return max_size
==Deployment==
Deployment shall be controlled by hash-power supermajority vote (similar to the technique used in BIP34), but the earliest possible activation time is 2016-01-11 00:00:00 UTC.
Activation is achieved when 750 of 1,000 consecutive blocks in the best chain have a version number with the first, second, third, and thirtieth bits set (0x20000007 in hex). The activation time will be the timestamp of the 750'th block plus a two week (1,209,600 second) grace period to give any remaining miners or services time to upgrade to support larger blocks. If a supermajority is achieved more than two weeks before 2016-01-11 00:00:00 UTC, the activation time will be 2016-01-11 00:00:00 UTC.
Block version numbers are used only for activation; once activation is achieved, the maximum block size shall be as described in the specification section, regardless of the version number of the block.
==Test network==
Test network parameters are the same as the main network, except starting earlier with easier supermajority conditions and a shorter grace period:
starting time: 1 Aug 2015 (timestamp 1438387200)
activation condition: 75 of 100 blocks
grace period: 24 hours
==Rationale==
The initial size of 8,000,000 bytes was chosen after testing the current reference implementation code with larger block sizes and receiving feedback from miners on bandwidth-constrained networks (in particular, Chinese miners behind the Great Firewall of China).
The doubling interval was chosen based on long-term growth trends for CPU power, storage, and Internet bandwidth. The 20-year limit was chosen because exponential growth cannot continue forever. If long-term trends do not continue, maximum block sizes can be reduced by miner consensus (a soft-fork).
Calculations are based on timestamps and not blockchain height because a timestamp is part of every block's header. This allows implementations to know a block's maximum size after they have downloaded it's header, but before downloading any transactions.
The deployment plan is taken from Jeff Garzik's proposed BIP100 block size increase, and is designed to give miners, merchants, and full-node-running-end-users sufficient time to upgrade to software that supports bigger blocks. A 75% supermajority was chosen so that one large mining pool does not have effective veto power over a blocksize increase. The version number scheme is designed to be compatible with Pieter's Wuille's proposed "Version bits" BIP, and to not interfere with any other consensus rule changes in the process of being rolled out.
==Objections to this proposal==
Raising the 1MB block size has been [https://www.google.com/webhp?#q=1mb+limit+site%3Abitcointalk.org discussed and debated for years].
===Centralization of full nodes===
The number of fully-validating nodes reachable on the network has been steadily declining. Increasing the capacity of the network to handle transactions by increasing the maximum block size may accelerate that decline, meaning a less distributed network that is more vulnerable to disruption. The size of this effect is debatable; the author of this BIP believes that the decline in fully validating nodes on the network is largely due to the availability of convenient, attractive, secure, lightweight wallet software and the general trend away from computing on desktop computers to mobile phones and tablets.
Increasing the capacity of the network to handle transactions should enable increased adoption by users and businesses, especially in areas of the world where existing financial infrastructure is weak. That could lead to a more robust network with nodes running in more political jurisdictions.
===Centralization of mining: costs===
Miners benefit from low-latency, high-bandwidth connections because they increase their chances of winning a "block race" (two or more blocks found at approximately the same time). With the current peer-to-peer networking protocol, announcing larger blocks requires more bandwidth. If the costs grow high enough, the result will be a very small number of very large miners.
The limits proposed by this BIP are designed so that running a fully validating node has very modest costs, which, if current trends in the cost of technology continue, will become even less expensive over time.
===Centralization of mining: big-block attacks===
[http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/008820.html Simulations show] that with the current peer-to-peer protocol, miners behind high-latency or low-bandwidth links are at a disadvantage compared to miners connected to a majority of hashpower via low-latency, high-bandwidth links. Larger blocks increase the advantage of miners with high-bandwidth connections, although that advantage can be minimized with changes to the way new blocks are announced (e.g. http://bitcoinrelaynetwork.org/ ).
If latency and bandwidth to other miners were the only variable that affected the profitability of mining, and miners were driven purely by profit, the end result would be one miner running on one machine, where latency was zero and bandwidth was essentially infinite.
However, many other factors influence miner profitability, including cost of electricity and labor and real estate, ability to use waste heat productively, access to capital to invest in mining equipment, etc. Increasing the influence of bandwidth in the mining profitability equation will not necessarily lead to more centralization.
===Unspent Transaction Output Growth===
This BIP makes no attempt to restrict the approximately 100% per-year growth in unspent transaction outputs (see http://gavinandresen.ninja/utxo-uhoh for details), because the author believe that problem should be solved by a further restriction on blocks described in a separate BIP (perhaps an additional limit on how much the transactions in any block may increase the UTXO set size).
==Long-term fee incentives==
http://gavinandresen.ninja/block-size-and-miner-fees-again
==Other solutions considered==
There have been dozens of proposals for increasing the block size over the years. Some notable ideas:
===One-time increase===
A small, quick one-time increase to, for example, 2MB blocks, would be the most conservative option.
However, a one-time increase requires just as much care in testing and deployment as a longer-term fix. And the entire debate over how large or small a limit is appropriate would be repeated as soon as the new limit was reached.
===Dynamic limit proposals===
BIP 100 proposes a dynamic limit determined by miner preferences expressed in coinbase transactions, with limits on the rate of growth. It gives miners more direct control over the maximum block size, which some people see as an advantage over this proposal and some see as a disadvantage. It is more complex to implement, because the maximum allowed size for a block depends on information contained in coinbase transactions from previous blocks (which may not be immediately known if block contents are being fetched out-of-order in a 'headers-first' mode).
[https://bitcointalk.org/index.php?topic=1078521.0 Meni Rosenfeld has proposed] that miners sacrifice mining reward to "pay for" bigger blocks, so there is an incentive to create bigger blocks only if transaction fees cover the cost of creating a larger block. This proposal is significantly more complex to implement, and it is not clear if a set of parameters for setting the cost of making a block bigger can be found that is not equivalent to a centrally-controlled network-wide minimum transaction fee.
==Compatibility==
This is a hard-forking change to the Bitcoin protocol; anybody running code that fully validates blocks must upgrade before the activation time or they will risk rejecting a chain containing larger-than-one-megabyte blocks.
Simplified Payment Verification software is not affected, unless it makes assumptions about the maximum depth of a transaction's merkle branch based on the minimum size of a transaction and the maximum block size.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/6341
================================================
FILE: bip-0102.mediawiki
================================================
==Abstract==
Simple, one-time increase in total amount of transaction data permitted in a block from 1MB to 2MB.
==Motivation==
# Continue current economic policy.
# Exercise hard fork network upgrade.
==Specification==
# MAX_BLOCK_SIZE increased to 2,000,000 bytes at trigger point.
# Increase maximum block sigops by similar factor, preserving SIZE/50 formula.
# Trigger: (1) Block time 00:00:00 on flag day, AND (2) 95% of the last 1,000 blocks have signaled support.
==Backward compatibility==
Fully validating older clients are not compatible with this change.
The first block exceeding 1,000,000 bytes will partition older clients
off the new network.
==Discussion==
In the short term, an increase is needed to continue to current
economic policies with regards to fees and block space, matching
market expectations and preventing market disruption.
In the long term, this limit should focus on reflecting the maximum
network engineering limit.
==Implementation==
https://github.com/jgarzik/bitcoin/tree/2015_2mb_blocksize
================================================
FILE: bip-0103.mediawiki
================================================
==Abstract==
This BIP proposes a block size growth intended to accommodate for hardware and other technological improvements for the foreseeable future.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
Many people want to see Bitcoin scale over time, allowing an increasing number of transactions on the block chain. It would come at an increased cost for the ecosystem (bandwidth, processing, and storage for relay nodes, as well as an impact on propagation speed of blocks on the network), but technology also improves over time. When all technologies depended on have improved as well as their availability on the market, there is no reason why Bitcoin's fundamental transaction rate cannot improve proportionally.
Currently, there is a consensus rule in place that limits the size of blocks to 1000000 bytes. Changing this requires a hard-forking change: one that will require every full node in the network to implement the new rules. The new chain created by those changed nodes will be rejected by old nodes, so this would effectively be a request to the ecosystem to migrate to a new and incompatible network. Doing this while controversy exists is dangerous to the network and the ecosystem.
Furthermore, the effective space available is always constrained by a hash rate majority and its ability to process transactions. No hard forking change that relaxes the block size limit can be guaranteed to provide enough space for every possible demand - or even any particular demand - unless strong centralization of the mining ecosystem is expected. Because of that, the development of a fee market and the evolution towards an ecosystem that is able to cope with block space competition should be considered healthy. This does not mean the block size or its limitation needs to be constant forever. However, the purpose of such a change should be evolution with technological growth, and not kicking the can down the road because of a fear of change in economics.
Bitcoin's advantage over other systems does not lie in scalability. Well-designed centralized systems can trivially compete with Bitcoin's on-chain transactions in terms of cost, speed, reliability, convenience, and scale. Its power lies in transparency, lack of need for trust in network peers, miners, and those who influence or control the system. Wanting to increase the scale of the system is in conflict with all of those. Attempting to buy time with a fast increase is not wanting to face that reality, and treating the system as something whose scale trumps all other concerns. A long term scalability plan should aim on decreasing the need for trust required in off-chain systems, rather than increasing the need for trust in Bitcoin.
In summary, hard forks are extremely powerful, and we need to use them very responsibly as a community. They have the ability to fundamentally change the technology or economics of the system, and can be used to disadvantage those who expected certain rules to be immutable. They should be restricted to uncontroversial changes, or risk eroding the expectation of low trust needed in the system in the longer term. As the block size debate has been controversial so far - for good or bad reasons - this BIP aims for gradual change and its effects start far enough in the future.
==Specification==
The block size limitation is replaced by the function below, applied to the median of the timestamps of the previous 11 blocks, or in code terms: the block size limit for pindexBlock is GetMaxBlockSize(pindexBlock->pprev->GetMedianTimePast()).
The sigop limit scales proportionally.
It implements a series of block size steps, one every ~97 days, between January 2017 and July 2063, each increasing the maximum block size by 4.4%. This allows an overall growth of 17.7% per year.
uint32_t GetMaxBlockSize(int64_t nMedianTimePast) {
// The first step is on January 1st 2017.
if (nMedianTimePast < 1483246800) {
return 1000000;
}
// After that, one step happens every 2^23 seconds.
int64_t step = (nMedianTimePast - 1483246800) >> 23;
// Don't do more than 11 doublings for now.
step = std::min(step, 175);
// Every step is a 2^(1/16) factor.
static const uint32_t bases[16] = {
// bases[i] == round(1000000 * pow(2.0, (i + 1) / 16.0))
1044274, 1090508, 1138789, 1189207,
1241858, 1296840, 1354256, 1414214,
1476826, 1542211, 1610490, 1681793,
1756252, 1834008, 1915207, 2000000
};
return bases[step & 15] << (step / 16);
}
==Rationale==
Waiting 1.5 years before the hard fork takes place should provide ample time to minimize the risk of a hard fork, if found uncontroversial.
Because every increase (including the first) is only 4.4%, risk from large market or technological changes is minimized.
The growth rate of 17.7% growth per year is consistent with the average growth rate of bandwidth the last years, which seems to be the bottleneck. If over time, this growth factor is beyond what the actual technology offers, the intention should be to soft fork a tighter limit.
Using a time-based check is very simple to implement, needs little context, is efficient, and is trivially reviewable. Using the "median time past" guarantees monotonic behaviour, as this median is required to be increasing, according to Bitcoin's existing consensus rules. Using the "median time past" of the block before means we know in advance what the limit of each block will be, without depending on the actual block's timestamp.
==Compatibility==
This is a hard forking change, thus breaks compatibility with old fully-validating node. It should not be deployed without widespread consensus.
==Acknowledgements==
Thanks to Gregory Maxwell and Wladimir J. van der Laan for their suggestions.
================================================
FILE: bip-0104.mediawiki
================================================
BIP: 104
Layer: Consensus (hard fork)
Title: 'Block75' - Max block size like difficulty
Authors: t.khan
Status: Closed
Type: Specification
Assigned: 2017-01-13
License: BSD-2-Clause OR FSFAP
==Abstract==
Automatic adjustment of max block size with the target of keeping blocks 75% full, based on the average block size of the previous 2016 blocks. This would be done on the same schedule as difficulty.
==Motivation==
Blocks are already too full and cannot support further transaction growth. While SegWit and Lightning (and other off-chain solutions) will help, they will not solve this problem.
Bitcoin needs a reasonably effective and predictable way of managing the maximum block size which allows moderate growth, keeps max block size as small as possible, and prevents wild swings in transaction fees.
The every two-week and automatic adjustment of difficulty has proven to be a reasonably effective and predictable way of managing how quickly blocks are mined. It works well because humans aren’t involved (except for setting the original target of a 10 minute per block average), and therefore it isn’t political or contentious. It’s simply a response to changing network resources.
It’s clear at this point that human beings should not be involved in the determination of max block size, just as they’re not involved in deciding the difficulty. Therefore, it is logical and consistent with Bitcoin’s design to implement a permanent solution which, as with the difficulty adjustment, is simply an automatic response to changing transaction volumes. With the target of keeping blocks 75% full on average, this is the goal of Block75.
==Specification==
The max block size will be recalculated every 2016 blocks, along with difficulty, using Block75’s simple algorithm:
new max block size = x + (x * (AVERAGE_CAPACITY - TARGET_CAPACITY))
* TARGET_CAPACITY = 0.75 //Block75's target of keeping blocks 75% full
* AVERAGE_CAPACITY = average percentage full of the last 2016 blocks, as a decimal
* x = current max block size
All code which generates/validates blocks or uses/references the current hardcoded limits will need to be changed to support Block75.
==Rationale==
The 75% full block target was selected because:
* it is the middle ground between blocks being too small (average 100% full) and blocks being unnecessarily large (average 50% full)
* it can handle short-term spikes in transaction volume of up to 33%
* it limits the growth of max block size to less than 25% over the previous period
* it will maintain average transaction fees at a stable level similar to that of May/June 2016
The 2016 block (~2 weeks) period was selected because:
* it has been shown to be reasonably adaptive to changing network resources (re: difficulty)
* the frequent and gradual adjustments that result will be relatively easy for miners and node operators to predict and adapt to, as any unforeseen consequences will be visible well in advance
* it minimizes any effect a malicious party could have in an attempt to manipulate max block size
The Block75 algorithm will adjust the max block size up and down in response to transaction volume, including changes brought on by SegWit and Lightning. This is important as it will keep average transaction fees stable, thereby allowing miners and businesses using Bitcoin more certainty regarding future income/expenses.
==Other solutions considered==
A hardcoded increase to max block size (2MB, 8MB, etc.), rejected because:
* only a temporary solution, whatever limit was chosen would inevitably become a problem again
* would cause transaction fees to vary wildly over time
Allow miners to vote for max block size, rejected because:
* overly complex and political
* human involvement makes this slow to respond to changing transaction volumes
* focuses power over max block size to a relatively small group of people
* unpredictable transaction fees caused by this would create uncertainty in the ecosystem
==Backward Compatibility==
This BIP is not backward compatible (hard fork). Any code which fully validates blocks must be upgraded prior to activation, as failure to do so will result in rejection of blocks over the current 1MB limit.
==Activation==
To help negate some of the risks associated with a hard fork and to prevent a single relatively small mining pool from preventing Block75's adoption, activation would occur at the next difficulty adjustment once 900 of the last 1,000 blocks mined signal support and a grace period of 4,032 blocks (~1 month) has elapsed.
==Copyright==
This BIP is dual-licensed under the BSD 2-clause license and the FSF All Permissive License.
================================================
FILE: bip-0105.mediawiki
================================================
==Abstract==
A method of altering the maximum allowed block size of the Bitcoin protocol
using a consensus based approach.
==Motivation==
There is a belief that Bitcoin cannot easily respond to raising the
blocksize limit if popularity was to suddenly increase due to a mass adoption
curve, because co-ordinating a hard fork takes considerable time, and being
unable to respond in a timely manner would irreparably harm the credibility of
bitcoin.
Additionally, predetermined block size increases are problematic because they
attempt to predict the future, and if too large could have unintended
consequences like damaging the possibility for a fee market to develop
as block subsidy decreases substantially over the next 9 years; introducing
or exacerbating mining attack vectors; or somehow affect the network in unknown
or unpredicted ways. Since fixed changes are hard to deploy, the damage could be
extensive.
Dynamic block size adjustments also suffer from the potential to be gamed by the
larger hash power.
Free voting as suggested by BIP100 allows miners to sell their votes out of band
at no risk, and enable the sponsor the ability to manipulate the blocksize.
It also provides a cost free method or the larger pools to vote in ways to
manipulate the blocksize such to disadvantage or attack smaller pools.
==Rationale==
By introducing a cost to increase the block size ensures the mining community
will collude to increase it only when there is a clear necessity, and reduce it
when it is unnecessary. Larger miners cannot force their wishes so easily
because not only will they have to pay extra a difficulty target, then can be
downvoted at no cost by the objecting hash power.
Using difficulty as a penalty is better than a fixed cost in bitcoins because it
is less predictable.
In order to prevent miners having complete control over blocksize, an upper
limit is required at protocol level. This feature ensures full nodes retain
control over consensus, remembering full nodes are the mechanism to keep miners
honest.
==Specification==
The initial block size limit shall be 1MB.
Each time a miner creates a block, they may vote to increase or decrease the
blocksize by a maximum of 10% of the current block size limit. These votes will
be used to recalculate the new block size limit every 2016 blocks.
Votes are cast using the block's coinbase transaction scriptSig.
As per BIP34, the coinbase transaction scriptSig starts with a push of the block
height. The next push is a little-endian number representing the preferred block
size in bytes. For example, 0x4c(OP_PUSHDATA1) 0x03(size of constant) 0x80 0x84 0x1e(2MB)
or 0x4c(OP_PUSHDATA1) 0x04(size of constant) 0x80 0x96 0x98 0x00(10MB).
If a miner votes for an increase, the block hash must meet a difficulty target
which is proportionally larger than the standard difficulty target based on the
percentage increase they voted for.
Votes proposing decreasing the block size limit do not need to meet a higher
difficulty target.
Miners can vote for no change by voting for the current block size.
For blocks to be valid the blockhash must meet the required difficulty target
for the vote otherwise the block is invalid and will be rejected.
Every 2016 blocks, the block size limit will be recalculated by the median of
all votes in the last 2016 blocks. This will redefine the block size limit for
the next 2016 blocks.
Blocks that are larger than the calculated base block size limit are invalid and
will be rejected.
The base block size limit may not reduce below 1MB or increase above 8MB (the exact
number for the upper limit requires further discussion).
==Acknowledgements==
This proposal is based on ideas and concepts derived from the writings of
Meni Rosenfeld and Gregory Maxwell.
==References==
[[bip-0034.mediawiki|BIP34]]
==Copyright==
This work is placed in the public domain.
================================================
FILE: bip-0106.mediawiki
================================================
==Abstract==
This BIP proposes replacing the fixed one megabyte maximum block size with a dynamically controlled maximum block size that may increase or decrease with difficulty change depending on various network factors. I have two proposals regarding this...
i. Depending only on previous block size calculation.
ii. Depending on previous block size calculation and previous Tx fee collected by miners.
==Motivation==
With increased adoption, transaction volume on bitcoin network is bound to grow. If the one megabyte max cap is not changed to a flexible one which changes itself with changing network demand, then adoption will hamper and bitcoin's growth may choke up. Following graph shows the change in average block size since inception...
https://blockchain.info/charts/avg-block-size?timespan=all&showDataPoints=false&daysAverageString=1&show_header=true&scale=0&address=
==Specification==
===Proposal 1 : Depending only on previous block size calculation===
If more than 50% of block's size, found in the first 2000 of the last difficulty period, is more than 90% MaxBlockSize
Double MaxBlockSize
Else if more than 90% of block's size, found in the first 2000 of the last difficulty period, is less than 50% MaxBlockSize
Half MaxBlockSize
Else
Keep the same MaxBlockSize
===Proposal 2 : Depending on previous block size calculation and previous Tx fee collected by miners===
TotalBlockSizeInLastButOneDifficulty = Sum of all Block size of first 2008 blocks in last 2 difficulty period
TotalBlockSizeInLastDifficulty = Sum of all Block size of second 2008 blocks in last 2 difficulty period (This actually includes 8 blocks from last but one difficulty)
TotalTxFeeInLastButOneDifficulty = Sum of all Tx fees of first 2008 blocks in last 2 difficulty period
TotalTxFeeInLastDifficulty = Sum of all Tx fees of second 2008 blocks in last 2 difficulty period (This actually includes 8 blocks from last but one difficulty)
If ( ( (Sum of first 4016 block size in last 2 difficulty period)/4016 > 50% MaxBlockSize) AND (TotalTxFeeInLastDifficulty > TotalTxFeeInLastButOneDifficulty) AND (TotalBlockSizeInLastDifficulty > TotalBlockSizeInLastButOneDifficulty) )
MaxBlockSize = TotalBlockSizeInLastDifficulty * MaxBlockSize / TotalBlockSizeInLastButOneDifficulty
Else If ( ( (Sum of first 4016 block size in last 2 difficulty period)/4016 < 50% MaxBlockSize) AND (TotalTxFeeInLastDifficulty < TotalTxFeeInLastButOneDifficulty) AND (TotalBlockSizeInLastDifficulty < TotalBlockSizeInLastButOneDifficulty) )
MaxBlockSize = TotalBlockSizeInLastDifficulty * MaxBlockSize / TotalBlockSizeInLastButOneDifficulty
Else
Keep the same MaxBlockSize
==Rationale==
These two proposals have been derived after discussion on [https://bitcointalk.org/index.php?topic=1154536.0 BitcoinTalk] and [http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010285.html bitcoin-dev mailing list]. The original idea and its evolution in the light of various arguments can be found [http://upalc.com/maxblocksize.php here].
===Proposal 1 : Depending only on previous block size calculation===
This solution is derived directly from the indication of the problem. If transaction volume increases, then we will naturally see bigger blocks. On the contrary, if there are not enough transaction volume, but maximum block size is high, then only few blocks may sweep the mempool. Hence, if block size is itself taken into consideration, then maximum block size can most rationally be derived. Moreover, this solution not only increases, but also decreases the maximum block size, just like difficulty.
===Proposal 2 : Depending on previous block size calculation and previous Tx fee collected by miners===
This solution takes care of stable mining subsidy. It will not increase maximum block size, if Tx fee collection is not increasing and thereby creating a Tx fee pressure on the market. On the other hand, though the block size max cap is dynamically controlled, it is very difficult to game by any party because the increase or decrease of block size max cap will take place in the same ratio of average block size increase or decrease.
==Compatibility==
This is a hard-forking change to the Bitcoin protocol; anybody running code that fully validates blocks must upgrade before the activation time or they will risk rejecting a chain containing larger-than-one-megabyte blocks.
==Other solutions considered==
[http://gtf.org/garzik/bitcoin/BIP100-blocksizechangeproposal.pdf Making Decentralized Economic Policy] - by Jeff Garzik
[https://bitcointalk.org/index.php?topic=1078521.0 Elastic block cap with rollover penalties] - by Meni Rosenfeld
[https://github.com/bitcoin/bips/blob/master/bip-0101.mediawiki Increase maximum block size] - by Gavin Andresen
[https://gist.github.com/sipa/c65665fc360ca7a176a6 Block size following technological growth] - by Pieter Wuille
[https://lightning.network/lightning-network-paper.pdf The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments] - by Joseph Poon & Thaddeus Dryja
==Deployment==
If consensus is achieved, deployment can be made at a future block number at which difficulty will change.
================================================
FILE: bip-0107.mediawiki
================================================
BIP: 107
Layer: Consensus (hard fork)
Title: Dynamic limit on the block size
Authors: Washington Y. Sanchez
Status: Closed
Type: Specification
Assigned: 2015-09-11
License: PD
==Abstract==
This BIP proposes a dynamic limit to the block size based on transaction volume.
==Motivation==
Over the next few years, large infrastructure investments will be made into:
# Improving global network connectivity
# Improving block propagation across the Bitcoin network
# Layer 2 services and networks for off-chain transactions
# General efficiency improvements to transactions and the blockchain
* While there is a consensus between Bitcoin developers, miners, businesses and users that the block size needs to be increased, there is a lingering concern over the potential unintended consequences that may augment the trend towards network and mining centralization (largely driven by mining hardware such as ASICs) and thereby threaten the security of the network.
* In contrast, failing to respond to elevated on-chain transaction volume may lead to a consumer-failure of Bitcoin, where ordinary users - having enjoyed over 6 years of submitting transactions on-chain at relatively low cost - will be priced out of blockchain with the emergence of a prohibitive 'fee market'.
* These two concerns must be delicately balanced so that all users can benefit from a robust, scalable, and neutral network.
==Specification==
* Increases in the block size will occur in 2 phases
* '''Phase 1'''
** The block size will be increased similar to [[https://twitter.com/adam3us/status/636410827969421312|Adam Back's proposal]], as a safe runway prior to switching to Phase 2, while network and protocol infrastructure is improved
** The schedule:
*** ''2016-2017:'' 2 MB
*** ''2018-2019:'' 4 MB
*** ''2020:'' 6 MB
* '''Phase 2'''
** In 2020, the maximum block size will be increased dynamically according to sustained increases in transaction volume
** Every 4032 blocks (~4 weeks), a CHECK will be performed to determine if a raise in the maximum block size should occur
*** This calculates to a theoretical maximum of 13 increases per year
** IF of the last >= 3025 blocks were >=60% full, the maximum block size will be increased by 10%
** The maximum block size can only ever be increased, not decreased
* The default limitfreerelay will also be raised in proportion to maximum block size increases
** Transactions without fees can continue to be submitted and relayed on the network as per normal
** limitfreerelay also helps counter attempts to trigger a block size increase by 'penny-flooding'
For example:
* When the dynamic rules for increasing the block size go live on January 1st 2020, the starting maximum block size will be 6 MB
* IF >=3025 blocks are >= 3.6 MB, the new maximum block size become 6.6 MB.
* The theoretical maximum block size at the end of 2020 would be ~20.7 MB, assuming all 13 increases are triggered every 4 weeks by the end of the year.
==Rationale==
* '''Phase 1'''
** This runway has a schedule for conservative increases to the block size in order to relieve transaction volume pressure while allowing network and protocol infrastructure improvements to be made, as well as layer 2 services to emerge
* '''Phase 2'''
** Why 60% full blocks?
*** IF blocks are 60% full, they count as a ''vote'' towards increasing the block size
*** If this parameter is too low, the trigger sensitivity may be too high and vulnerable to spam attacks or miner collusion
*** Setting the parameter too high may set the trigger sensitivity too low, causing transaction delays that are trying to be avoided in the first place
*** Between September 2013-2015, the standard deviation measured from average block size (n=730 data points from blockchain.info) was ~ 0.13 MB or 13% of the maximum block size
**** If blocks needed to be 90% full before an increase were triggered, normal variance in the average block size would mean some blocks would be full before an increase could be triggered
*** Therefore, we need a ''safe distance'' away from the maximum block size to avoid normal block size variance hitting the limit. The 60% level represents a 3 standard deviation distance from the limit.
** Why 3025 blocks?
*** The assessment period is 4032 blocks or ~ 4 weeks, with the threshold set as 4032 blocks/0.75 + 1
*** Increases in the maximum block size should only occur after a sustained trend can be observed in order to:
***# Demonstrate a market-driven secular elevation in the transaction volume
***# Increase the cost to trigger an increase by spam attacks or miner collusion with zero fee transactions
*** In other words, increases to the maximum block size must be conservative but meaningful to relieve transaction volume pressure in response to true market demand
** Why 10% increase in the block size?
*** Increases in the block size are designed to be conservative and in balance with the number of theoretical opportunities to increase the block size per year
*** Makes any resources spent for spam attacks or miner collusion relatively expensive to achieve a minor increase in the block size. A sustained attack would need to be launched that may be too costly, and ideally detectable by the community
==Deployment==
Similar deployment model to BIP101:
Activation is achieved when 750 of 1,000 consecutive blocks in the best chain have a version number with the first, second, third, and thirtieth bits set (0x20000007 in hex). The activation time will be the timestamp of the 750'th block plus a two week (1,209,600 second) grace period to give any remaining miners or services time to upgrade to support larger blocks.
==Acknowledgements==
Thanks to Austin Williams, Brian Hoffman, Angel Leon, Bulukani Mlalazi, Chris Pacia, and Ryan Shea for their comments.
==Copyright==
This work is placed in the public domain.
================================================
FILE: bip-0109.mediawiki
================================================
BIP: 109
Layer: Consensus (hard fork)
Title: Two million byte size limit with sigop and sighash limits
Authors: Gavin Andresen
Status: Closed
Type: Specification
Assigned: 2016-01-28
License: PD
==Abstract==
One-time increase in total amount of transaction data permitted in a block from 1MB to 2MB, with limits on signature operations and hashing.
==Motivation==
# Continue current economic policy.
# Exercise hard fork network upgrade.
# Mitigate potential CPU exhaustion attacks
==Specification==
=== MAX_BLOCK_SIZE increased to 2,000,000 bytes ===
The maximum number of bytes in a canonically serialized block shall be increased from
1,000,000 bytes to 2,000,000 bytes.
=== Switch to accurately-counted sigop limit of 20,000 per block ===
The existing MAX_SIGOPS limit of 20,000 signature operations per block shall be retained,
but only ECDSA verifications actually performed to validate the block shall be counted.
In particular:
* The coinbase scriptSig is not counted
* Signature operations in un-executed branches of a Script are not counted
* OP_CHECKMULTISIG evaluations are counted accurately; if the signature for a 1-of-20 OP_CHECKMULTISIG is satisfied by the public key nearest the top of the execution stack, it is counted as one signature operation. If it is satisfied by the public key nearest the bottom of the execution stack, it is counted as twenty signature operations.
* Signature operations involving invalidly encoded signatures or public keys are not counted towards the limit
=== Add a new limit of 1,300,000,000 bytes hashed to compute transaction signatures per block ===
The amount of data hashed to compute signature hashes is limited to 1,300,000,000 bytes per block. The same rules for counting are used as for counting signature operations.
=== Activation: 75% hashpower support trigger, followed by 28-day 'grace period' ===
Solo miners or mining pool operators express their support for this BIP by setting the fourth-highest-bit in the block's 32-bit version number (0x10000000 in hex). The first block with that bit set, a timestamp less than or equal to the expiration time, and with at least 750 out of 1000 blocks preceding it (with heights H-1000..H-1) with that bit set, shall define the beginning of a grace period. Blocks with timestamps greater than or equal to the triggering block's timestamp plus 28 days (60*60*24*28 seconds) shall be subject to the new limits.
As always, miners are expected to use their best judgement for what is best for the entire Bitcoin ecosystem when making decisions about what consensus-level changes to support.
=== Expiration: 1-Jan-2018 ===
If this BIP is not triggered before 1-Jan-2018 00:00:00 GMT it should be considered withdrawn.
Miners that support this BIP should set bit 0x10000000 in the block version until 1-Jan-2018. After that date, that bit can be safely re-used for future consensus rule upgrades.
==Backward compatibility==
Fully validating older clients are not compatible with this change.
The first block exceeding the old limits on block size or inaccurately counted signature operations will partition older clients off the new network.
SPV (simple payment validation) wallets are compatible with this change.
==Rationale==
In the short term, an increase is needed to handle increasing transaction volume.
The limits on signature operations and amount of signature hashing done prevent possible CPU exhaustion attacks by "rogue miners" producing very expensive-to-validate two megabyte blocks. The signature hashing limit is chosen to be impossible to reach with any non-attack transaction or block, to minimize the impact on existing mining or wallet software.
The choices of constants for the deployment scheme were motivated by prior experience with upgrades to the Bitcoin consensus rules:
* 0x10000000 was chosen to be compatible with the BIP 9 proposal for parallel deployment of soft forks
* 75% was chosen instead of 95% to minimize the opportunity for a single large mining pool or miner to be able to veto an increase, either because of ideological opposition or threat of violence or extortion.
* A four-week grace period after the voting period was chosen as a balance between giving people sufficient time to upgrade and keeping people's attention on the urgent need to upgrade.
==Implementation==
https://github.com/gavinandresen/bitcoin-git/tree/two_mb_bump
See also http://gavinandresen.ninja/a-guided-tour-of-the-2mb-fork
==Copyright==
This work is placed in the public domain.
================================================
FILE: bip-0110.mediawiki
================================================
==Abstract==
Temporarily limit the size of data fields at the consensus level, in order to correct distorted incentives caused by standardizing support for arbitrary data, and to refocus priorities on improving Bitcoin as money.
==Copyright==
This document is licensed under the 3-clause BSD license.
==Specification==
Blocks during a temporary, one-year deployment are checked with these additional rules:
# New output scriptPubKeys exceeding 34 bytes are invalid, unless the first opcode is OP_RETURN, in which case up to 83 bytes are valid.
# OP_PUSHDATA* payloads and [[#script-argument-witness-items|script argument witness items]] exceeding 256 bytes are invalid, except for the redeemScript push in BIP16 scriptSigs.
# Spending undefined witness (or Tapleaf) versions (ie, not Witness v0/BIP 141, Taproot/BIP 341, or P2A) is invalid. (Creating outputs with undefined witness versions is still valid.)
# Witness stacks with a Taproot annex are invalid.
# Taproot control blocks larger than 257 bytes (a merkle tree with 128 script leaves) are invalid.
# Tapscripts including OP_SUCCESS* opcodes anywhere (even unexecuted) are invalid.
# Tapscripts executing the OP_IF or OP_NOTIF instruction (regardless of result) are invalid.
Inputs spending UTXOs that were created before the activation height are exempt from the new rules.
Once the softfork expires, UTXOs of all heights are once again unrestricted.
===GetBlockTemplate===
This deployment uses the GBT deployment name "reduced_data" as defined in [[bip-0009.mediawiki#getblocktemplate_changes|BIP 9]]. During mandatory signaling, the deployment's bit is included in "vbrequired".
==Motivation==
In order to protect Bitcoin's intended function as the Internet's native money, the Bitcoin community has historically treated techniques for embedding arbitrary data into Bitcoin transactions with antagonism.
Such data embedding must be resisted at all times in order to ensure it doesn't become load-bearing and start to produce negative externalities, especially for node operators.
Starting with the "inscription" hack first exploited in 2022, a trend has emerged around embedding arbitrary data into Bitcoin transactions, creating significant unnecessary burdens on node operators and diverting development focus and incentives away from Bitcoin's fundamental purpose of being sound, permissionless, borderless money.
This BIP aims to set Bitcoin back on the path to becoming the world's money by rejecting the standardization of data storage as a supported use case at the consensus level.
It achieves this by temporarily invalidating several of the most harmful methods of data abuse by consensus, while preserving all known monetary use cases.
Specifically, this proposal invalidates all methods of embedding contiguous arbitrary data larger than 256 bytes; it also invalidates large scriptPubKey and Tapleaf formats that are abused almost exclusively for data embedding; and finally, it restores, in consensus, the long-established 83-byte policy limit on OP_RETURN outputs.
In software development, it is a common practice to disable unsupported use cases, because not doing so quickly becomes unsustainable and causes development to grind to a standstill.
Activation of these new rules thus sends a clear message that arbitrary data storage will continue to be actively resisted, and that such unsupported usage should not be permitted to derail network priorities.
It also reinforces Bitcoin's core function as a censorship-resistant payment system, because data storage competes unfairly with payments, making Bitcoin payments unnecessarily costly. This encourages reliance on third-party payment processors, making Bitcoin payments easier to censor.
Finally, it improves decentralization of the node network by re-establishing the long-held commitment towards minimizing the cost (financial or otherwise) of operating a node.
Bitcoin should "do one thing, and do it well". By rejecting data storage, this BIP liberates Bitcoin developers from endless scope creep, enabling them to focus on what's really important: Bitcoin's success as money.
==Rationale==
===Specification nuance===
'''Why limit scriptPubKeys to 34 bytes?'''
Unspent scriptPubKeys (OP_RETURN excepted) must be stored indefinitely in the UTXO set, which nodes must store on fast media and cannot prune.
Fast storage (usually RAM) is much more costly per byte than slower, non-volatile storage, so as the UTXO set size increases, the burden on node operators increases, harming decentralization.
They are also a direct cost to the sender rather than the receiver.
For these reasons, modern usage is all 34 bytes or smaller in practice; actual spending conditions have been moved to the witness, and the scriptPubKey simply commits to them in advance with a hash.
Furthermore, large scriptPubKeys, in addition to being a data embedding vector, can be abused to create malicious transactions and blocks ("poison blocks") that take a long time to validate.
Large scriptPubKeys, thus carrying a large abuse potential and no benefit, are invalidated by this BIP.
'''What about OP_RETURN? Why not get rid of it entirely?'''
OP_RETURN outputs are provably unspendable, and nodes do not need to store them in the UTXO set.
Historically, up to 83 bytes have been tolerated only to avoid unprovably unspendable spam in other output scripts, and with the possible exception of commitment schemes that use OP_RETURN in coinbase transaction outputs (notably Segwit), using OP_RETURN is not the optimal solution to any known use case.
With the advent of pay-to-contract and Taproot, it is now also possible to commit to external data in the Taptree, making even hypothetical use of OP_RETURN deprecated.
However, to avoid breaking legacy protocols that still include such outputs, this proposal allows these outputs.
'''Why limit other data to 256/257 bytes?'''
With modern compression, it is plausible to represent images in as few as 300-400 bytes. Images are likely the most harmful use case for data storage, as they have huge demand and supporting them can engender high fees and UTXO-set bloat, as well as content that a large majority of node operators might object to.
256 bytes (2048 bits) is also more than sufficient for reasonably large numbers that might be potentially needed in legitimate cryptography, reinforcing Bitcoin's intended purpose as a monetary network.
'''Won't spammers just spread their data over multiple fields?'''
While it is impossible to fully prevent steganography, limiting data sizes ensures such abuses are non-contiguous and obfuscated within another intended meaning (script code, structure, etc).
As far as Bitcoin is concerned, the data has some meaning other than the spammers' misinterpretation, and any external code to "reassemble" the unintended data is responsible for producing it
(it is possible to write code that transforms *any* data into any other data - what matters is that Bitcoin has a well-defined meaning that is distinct from the unsupported one).
Requiring users to divide their files into chunks of at most 256 bytes, raising the cost both in fees and in effort, sends a clear message that data storage abuses in general are unwelcome rather than sanctioned or supported.
'''What are "script argument witness items", referred to in rule 2?'''
Script argument witness items are the witness stack elements that are placed on the script interpreter's stack as inputs before the script is executed - the witness equivalent of data pushes in scriptSigs.
The following witness stack elements are '''not''' script argument witness items, and are thus excluded from rule 2 (though some are limited/invalidated by other rules):
* Some items are part of a spend that invokes the script interpreter, but are popped from the witness stack before the remaining elements are passed to it as inputs:
** Witness scripts and Tapleaf scripts (not limited)
** Control blocks (limited by rule 5)
** Annexes (invalidated by rule 4)
* Others are not part of a script-path spend at all, so the script interpreter is not invoked:
** Taproot key path signatures (limited to exactly 64 or 65 bytes by BIP 341 signature validation)
** Witness stacks in spends of undefined witness versions (invalidated by rule 3)
All '''other''' witness stack elements are script argument witness items, and are thus limited to 256 bytes by rule 2.
'''Why are BIP16 redeemScripts, witness scripts, and Tapleaf scripts exempt from rule 2?'''
BIP16 redeemScripts, witness scripts, and Tapleaf scripts are scripts, not data. Their contents are subject to the same OP_PUSHDATA* restrictions during execution.
Restricting them is not only unnecessary, but would reduce the ability to make use of the intended script capabilities, and could impact legitimate real-world usage.
'''Why make spending undefined witness/Tapleaf versions invalid?'''
Since they are undefined, witness stacks spending these versions are completely unlimited currently to allow maximum flexibility in future upgrades.
Any future upgrade, however, would need more than a year of coordination, so this softfork will not actually restrict it, and only safeguards against abuse in the meantime.
'''Why not make it invalid to send to undefined witness versions?'''
This would require the senders of transactions to check the witness version prior to sending, and require additional coordination when a new witness version is intended to become used.
'''Why not allow spending undefined witness versions with an empty witness?'''
This has no use case, but would require nodes to track these UTXOs in case of potential spending.
By making spending invalid, it is possible for nodes to store them instead in slow memory not needed until this softfork expires.
(With proper planning, it also makes it possible for a future softfork making use of these witness versions to allow users to receive with an upgraded wallet even prior to activation of the upgrade.)
'''Why make the Taproot annex invalid?'''
The annex is currently undefined data with unlimited size.
It exists for future upgrades, but has no legitimate usage today.
Any future upgrade, however, would need more than a year of coordination, so this softfork will not actually restrict it, and only safeguards against abuse in the meantime.
'''Why is the Taproot control block limited to 257 bytes instead of 256?'''
The control block is a series of hashes proving the Tapscript is part of the Taptree, plus a single byte with the leaf version and parity bit.
See BIP 341 for details.
'''Why make OP_SUCCESS* invalid?'''
OP_SUCCESS* is meant for future upgrades. See above regarding undefined witness versions.
'''Why make OP_IF/OP_NOTIF invalid?'''
OP_IF/OP_NOTIF originated in pre-Taproot Bitcoin script language as a way to execute different subscripts based on a condition.
With Taproot, the conditions can instead be evaluated off-chain, revealing only the intended verification execution path.
Furthermore, when the conditions are met, the intent is that the keypath spend path should be used instead, avoiding publishing any scripts at all.
OP_IF is not only redundant for Tapscript, it is also commonly abused today to inject spam that gets skipped at execution.
While it is impossible to fully prevent steganography, closing this gap eliminates one common abuse today basically for free, and sends a message that such abuses are not welcome.
There are some potential experimental use cases for OP_IF in Tapscript. See the Tradeoffs section for more details.
'''Why is the proposal so simple?'''
A more complicated proposal could be envisioned that better balances innovation with safety, but implementing this properly would require extensive refactoring and review, delaying deployment when the change is already urgent.
The rules proposed herein have been intentionally kept very simple to minimise review time and avoid unnecessary risks of overlooking unexpected side effects.
'''Why is this softfork temporary?'''
The impact of these restrictions would severely constrain future upgrades, potentially forcing them to be designed as a hardfork instead of a softfork.
Some restrictions are also not ideal, but an improved limit would be more complicated to develop and test -
by deploying these simpler restrictions now, we avoid making the perfect the enemy of the good enough, while still allowing for upgrading the limits to better variants in the future.
Over the next year, interested developers can implement and propose a longer-term solution to address the needs of the protocol without the tradeoffs or blunt/simplified changes.
===Tradeoffs===
'''Are there any tradeoffs?'''
Yes:
# Limiting Taproot control blocks to 257 bytes directly constrains the size of the on-chain, consensus-enforced script tree. This could complicate or possibly even impede advanced smart contracting like BitVM, which relies on a large number of executable scripts. In the worst case scenario, these use cases may just need to wait until this softfork expires. As they are still in early development, testnet and sidechains should be sufficient for the next year while a more scalable rule is implemented.
# Upgrade hooks are not available for other softforks. As softforks adding new opcodes typically need at least a year to activate, this shouldn't be a practical issue.
# Some wallet software such as Miniscript habitually creates Tapleaves containing OP_IF. To mitigate the risk of these funds being frozen for a year, this proposal exempts inputs that spend outputs that were created before activation, and provides a two-week grace period between lock-in and activation, to give users time to prepare.
'''Isn't the limit on Taproot control blocks too restrictive?'''
Possibly.
The previous limit allows for 340,282,366,920,938,463,463,374,607,431,768,211,456 scripts, which is obviously way more than anyone could ever need.
257 bytes allows for 128 scripts, which is sufficient for modern and complex transactions.
However, it may prove too limiting for advanced off-chain functionality such as used by BitVM.
This is an unfortunate tradeoff that (if this softfork is accepted) we have chosen to accept in the short-term for the immediate benefits of this softfork.
The intent is to relax this restriction later, when this softfork expires, with a new approach allowing larger trees, yet to be developed.
Do note that non-script (or non-Bitcoin-L1 scripts) usage of the taptree does not have this same limitation:
just a single of the 128 leaves could very well be an extension of the merkle tree to greater depths than enforced by this softfork.
'''Aren't Taptrees intended to be unbalanced?'''
While it is true that optimal use of Taptrees may often be unbalanced to favour more-likely-executed scripts, this is optional, and the full capacity (in this case, 128 scripts) can still be used if needed.
Additionally, in ideal/ordinary circumstances, neither the Taptree nor a merkle branch through it is ever published:
all counterparties ought to evaluate the conditions for spending off-chain and rebroadcast the transaction using the keypath spending.
Tapscripts are designed to be used when one or more parties is unreachable or uncooperative; their existence mainly only serves to deter intentional non-cooperation by making it pointless.
An exception to this is protocols employing a NUMS point to restrict an output to only being spendable via the script path.
'''Is there any risk of funds being frozen or lost?'''
In theory, yes. This proposal goes to great pains to make sure it does not affect any known use cases, and it is reasonably certain that no one will be affected. However, there are a couple of experimental use cases involving pre-signed Taproot transactions that could end up being affected.
Specifically:
* The restriction on OP_IF/OP_NOTIF could temporarily invalidate some edge-case Tapleaves produced by the current version of the Miniscript compiler. There are no verified uses of these constructions currently in production, but there are some popular wallets that could, in theory, produce them.
* The restriction on Taptree depth will invalidate any Tapleaves deeper than 7 levels. Since Taptrees are usually designed with the more common spending conditions positioned higher in the tree, any funds encumbered by such a Taptree will almost certainly be easily spendable by Tapleaves higher up in the tree.
In both scenarios, funds are spendable either by other Tapleaves in the tree, or by the keypath (unless the keypath is provably invalidated using a NUMS point).
Funds in either scenario could end up being frozen or lost ''only'' if ''all'' of the following conditions are met:
* The UTXO is pay-to-Taproot (P2TR);
* The UTXO is in a pre-signed transaction;
* The UTXO being spent ''must'' be confirmed ''and'' spent during the temporary, one-year deployment of these new rules;
* The Tapleaf the user selects to spend the UTXO contains an OP_IF/OP_NOTIF or exists at a depth greater than 7;
* The keypath is unusable to spend the funds, AND there are no other suitable Tapleaves in the tree to spend the UTXO (in which case funds are frozen), OR there are other Tapleaves that ''can'' spend the UTXO in unexpected ways (in which case funds are lost).
In other words, funds are completely unaffected if:
* They do not use Taproot;
* They use Taproot in standard and well-supported ways;
* UTXOs needed during the temporary deployment are confirmed before the fork activates;
* UTXOs in pre-signed transactions do not lock funds using Tapleaves that violate the new rules;
* UTXOs in pre-signed transactions that lock funds using Tapleaves that violate the new rules do not need to be confirmed ''and'' spent during the deployment;
* UTXOs in pre-signed transactions that lock funds using Tapleaves that violate the new rules and need to be confirmed ''and'' spent during the deployment can be spent either via the keypath OR by other, expected Tapleaves in the tree.
This proposal does everything possible to try to avoid funds being frozen or lost, but ultimately it is impossible to prove that absolutely no one will be affected.
It is therefore up to the Bitcoin community to activate these new rules only if they feel that rejecting data storage is worth this tradeoff.
To prepare for activation, it is recommended that users begin migrating any affected funds now.
In the event that these new rules are activated, there will be at least a two-week period between lock-in and activation, during which all users will have the chance to migrate any remaining funds.
===Alternatives / Alsos===
'''Why not let the fee market manage data storage?'''
The fee market is designed to prioritize transactions based on economic urgency.
However, the market for data storage on the blockchain is a completely different market from the market for payments, with completely different incentives.
Specifically, the fee for a monetary transaction incentivises a miner to include the transaction in a block, representing a one-time transfer of monetary value, i.e., a payment. The miner thus provides the one-time service of securing a payment, for a one-time fee.
Once the payment is secured, the payor does not receive any additional benefit from the Bitcoin network, besides the integrity of Bitcoin's transaction history (a service to which all node operators are happy to contribute, because Bitcoin would not function as money otherwise).
Conversely, the fee for a data storage transaction still goes only to the miner who includes the data in a block, but the burden of storing the data falls on all node operators, who never received even a part of the fee, yet are forced to continue downloading, storing, and serving the data forever.
In this case, the miner accepts a one-time fee, and in exchange, the priceless service of highly-available, uncensorable data storage is provided in perpetuity ''for free'' by node operators.
The problem becomes even worse when the data is objectionable to node operators, as this represents an even larger, unexpected cost for them.
'''How about OP_RETURN2/"blobspace" making the data optional for nodes?'''
This has been attempted multiple times in the past.
There is perhaps no harm in trying yet again, and this proposal does not prevent doing so,
but ultimately these schemes depend on the cooperation of the sender, who usually wants to explicitly force the content on non-consenting node operators
(or they would be using other existing distribution methods already).
These other ideas also do not solve the problem of objectionable content.
'''Why not ban PUSHDATA opcodes/Eliminate the witness discount/Apply a length limit to the Annex rather than eliminating it/Add limits to overall witness or transaction sizes/Make the softfork permanent instead of temporary/Remove the witness discount/Make OP_RETURN cheaper?'''
These are all interesting ideas, but they all increase the complexity of the implementation, and this proposal was optimized to be simple and easy to review for fast deployment. If the community decides to do any of these things, this proposal encourages them to do so once it expires.
'''Why not eliminate one or more of the restrictions?'''
This proposal, as is, represents the strongest possible rejection of the arbitrary data storage use case, while minimizing complexity. Loosening any of the rules would make it less effective at achieving this objective, for not much benefit.
'''Shouldn't spam be fought in policy? Does this proposal affirm that policy is ineffective?'''
It remains true that policy is still the best place to fight spam.
However, it is also true that policy cannot guarantee 100% effectiveness, particularly against bad actors who are mining.
This softfork minimises the impact of such malicious miners, closing the worst-case risks.
'''Does this proposal solve spam completely?'''
No.
It is impossible to solve spam completely, and typically spam is best fought with policy/filters, not consensus.
What this softfork does is require users wanting to store large unencrypted files in the blockchain to disguise the data as financial data and/or break it up into multiple data pushes. Obviously doing so is considered an abuse of bitcoin and should be avoided, but if it does happen, this BIP strengthens the argument that data storage is not a supported use case.
'''Why doesn't this proposal address non-Bitcoin tokens?'''
There are a wide variety of non-Bitcoin tokens, mostly scams, that a significant portion of the community considers spam.
However, these schemes are best countered in policy rather than consensus, and besides, this proposal does not aim to eliminate spam entirely.
'''Is this a slippery slope? If we make rules against data today, will we start banning use cases we don't like tomorrow?'''
No.
These rules may be new at the consensus level, but they are merely enshrining long-standing principles of Bitcoin, as necessary to address a threat to the decentralization of the network and its usability for monetary purposes.
This softfork does not attempt to impose restrictions on monetary activity or the validity of monetary transactions themselves.
By restricting the data storage use case as much as possible, this proposal reinforces Bitcoin's guarantee of sound, permissionless money for the long-term.
This clear distinction between mitigating a systemic risk from non-monetary data abuse and interfering with actual monetary use cases provides a strong barrier against future overreach.
The explicitly temporary nature of the softfork further reinforces that this is a targeted intervention to mitigate a specific crisis, not a commitment or proposal of a new direction of development.
If no further action is taken by you, it will expire in a year.
Even if a followup softfork is proposed for that time, you retain the right to reject it.
'''Doesn't this proposal break user space?'''
Yes, this proposal intentionally breaks user space, specifically the data storage user space. This is necessary in order to communicate that data storage is not supported.
Pains have been taken to avoid breaking monetary use cases, and it is unlikely that any such use cases have been affected, but in theory they might be. See the Tradeoffs section for more details.
==Backwards compatibility==
There are a couple of very unlikely scenarios in which funds could theoretically be frozen or lost. See the Tradeoffs section for more details.
If this proposal activates, the Miniscript compiler will need to be modified not to produce scripts that violate the new rules, at least while the new rules are active.
Users storing arbitrary data in the Bitcoin blockchain should start looking for other places to store their data, such as Nostr, IPFS, BitTorrent, cloud storage, etc, as the Bitcoin network will not support this use case going forward.
All other known use cases are not affected.
==Reference implementation==
https://github.com/bitcoinknots/bitcoin/compare/29.x-knots...dathonohm:bitcoin:uasf-modified-bip9
==Deployment==
This deployment uses a modified version of BIP9 with the following parameters:
* '''name''': reduced_data
* '''bit''': 4
* '''starttime''': 1764547200 (~December 1, 2025)
* '''timeout''': NO_TIMEOUT
* '''min_activation_height''': 0
* '''max_activation_height''': 965664 (~September 1, 2026)
* '''active_duration''': 52416 blocks (~1 year after activation)
* '''threshold''': 1109/2016 (55%)
===Deviations from BIP9===
This deployment deviates from standard BIP9 in five ways:
'''Reduced threshold (55% instead of 95%)''': The standard BIP9 threshold of 95% is designed for permanent consensus changes where near-universal miner readiness is desirable. Since rejecting data storage is a matter of urgency, and since this softfork is temporary and expires after one year, a lower threshold is ideal.
'''No timeout, using max_activation_height instead''': Standard BIP9 uses a time-based timeout that transitions to FAILED if the threshold is not reached. This deployment sets timeout to NO_TIMEOUT and instead uses a BIP8-like, height-based max_activation_height. The deployment transitions to LOCKED_IN at height 963648 (one retarget period before max_activation_height), then to ACTIVE at height 965664.
'''Mandatory signaling period''': Similar to BIP8, this deployment enforces mandatory signaling during the retarget period immediately before mandatory lock-in (blocks 961632 to 963647; lock-in happens no later than block 963648). During this window, blocks that do not signal bit 4 are rejected as invalid. Mandatory signaling ends once the deployment reaches the LOCKED_IN state.
'''Expiry via active_duration''': Standard BIP9 deployments are permanent once ACTIVE. This proposal includes an active_duration of 52416 blocks (~1 year), making the deployment temporary rather than permanent. After active_duration blocks, the state machine transitions from ACTIVE to EXPIRED, a new terminal state. Once EXPIRED, the rules cease to be enforced and UTXOs are once again unrestricted.
'''State transitions''': The state machine follows this progression:
# DEFINED: Initial state until starttime
# STARTED: After starttime; miners may signal with bit 4
# LOCKED_IN: Entered at the start of the first retarget period where the threshold was reached in the previous period; mandatory signaling (blocks 961632-963647) ensures this happens no later than height 963648
# ACTIVE: Entered one retarget period after LOCKED_IN; rules enforced for active_duration blocks
# EXPIRED: Entered when block height >= activation_height + active_duration; rules no longer enforced (terminal state)
The FAILED state is never reached because timeout is disabled. EXPIRED is the final state; there are no transitions after it. Miner signaling after expiry has no effect because the deployment is no longer in the STARTED state, and miner signaling only governs the STARTED -> LOCKED_IN transition.
==Credits==
Original draft and advice: Luke-Jr
================================================
FILE: bip-0111.mediawiki
================================================
BIP: 111
Layer: Peer Services
Title: NODE_BLOOM service bit
Authors: Matt Corallo
Peter Todd
Status: Deployed
Type: Specification
Assigned: 2015-08-20
License: PD
== Abstract ==
This BIP extends BIP 37, Connection Bloom filtering, by defining a
service bit to allow peers to advertise that they support bloom filters
explicitly. It also bumps the protocol version to allow peers to
identify old nodes which allow bloom filtering of the connection despite
lacking the new service bit.
== Motivation ==
BIP 37 did not specify a service bit for the bloom filter service, thus
implicitly assuming that all nodes that serve peers data support it.
However, the connection filtering algorithm proposed in BIP 37, and
implemented in several clients today, has been shown to provide little
to no privacyhttp://eprint.iacr.org/2014/763, as well as being a large DoS risk on some nodes[http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2013-July/003044.html] is one example where the issues were found, though others independently discovered issues as well. Sample DoS exploit code available at https://github.com/petertodd/bloom-io-attack..
Thus, allowing node operators to disable connection bloom filtering is a
much-needed feature.
== Specification ==
The following protocol bit is added:
NODE_BLOOM = (1 << 2)
Nodes which support bloom filters should set that protocol bit.
Otherwise it should remain unset. In addition the protocol version is
increased from 70002 to 70011 in the reference implementation. It is
often the case that nodes which have a protocol version smaller than
70011, but larger than 70000 support bloom filtered connections without
the NODE_BLOOM bit set, however clients which require bloom filtered
connections should avoid making this assumption.
NODE_BLOOM is distinct from NODE_NETWORK, and it is legal to advertise
NODE_BLOOM but not NODE_NETWORK (though there is little reason to do
so now, some proposals may make this more useful in the future)
If a node does not support bloom filters but receives a "filterload",
"filteradd", or "filterclear" message from a peer the node should
disconnect that peer immediately. For backwards compatibility, in
initial implementations, nodes may choose to only disconnect nodes which
have the new protocol version set and attempt to send a filter command.
While outside the scope of this BIP it is suggested that DNS seeds and
other peer discovery mechanisms support the ability to specify the
services required; current implementations simply check only that
NODE_NETWORK is set.
== Design rational ==
A service bit was chosen as applying a bloom filter is a service.
The increase in protocol version is for backwards compatibility. In
initial implementations, old nodes which are not yet aware of NODE_BLOOM
and use a protocol version < 70011 may still send filter messages to a
node without NODE_BLOOM. This feature may be removed after there are
sufficient NODE_BLOOM nodes available and SPV clients have upgraded,
allowing node operators to fully close the bloom-related DoS vectors.
== Reference Implementation ==
https://github.com/bitcoin/bitcoin/pull/6579
== Copyright ==
This document is placed in the public domain.
== References ==
================================================
FILE: bip-0112.mediawiki
================================================
==Abstract==
This BIP describes a new opcode (CHECKSEQUENCEVERIFY) for the Bitcoin
scripting system that in combination with BIP 68 allows execution
pathways of a script to be restricted based on the age of the output
being spent.
==Summary==
CHECKSEQUENCEVERIFY redefines the existing NOP3 opcode.
When executed, if any of the following conditions are true, the script interpreter will terminate with an error:
* the stack is empty; or
* the top item on the stack is less than 0; or
* the top item on the stack has the disable flag (1 << 31) unset; and
** the transaction version is less than 2; or
** the transaction input sequence number disable flag (1 << 31) is set; or
** the relative lock-time type is not the same; or
** the top stack item is greater than the transaction input sequence (when masked according to the BIP68);
Otherwise, script execution will continue as if a NOP had been executed.
BIP 68 prevents a non-final transaction from being selected for inclusion in a block until the corresponding input has reached the specified age, as measured in block-height or block-time. By comparing the argument to CHECKSEQUENCEVERIFY against the nSequence field, we indirectly verify a desired minimum age of
the output being spent; until that relative age has been reached any script execution pathway including the CHECKSEQUENCEVERIFY will fail to validate, causing the transaction not to be selected for inclusion in a block.
==Motivation==
BIP 68 repurposes the transaction nSequence field meaning by giving
sequence numbers new consensus-enforced semantics as a relative
lock-time. However, there is no way to build Bitcoin scripts to make
decisions based on this field.
By making the nSequence field accessible to script, it becomes
possible to construct code pathways that only become accessible some
minimum time after proof-of-publication. This enables a wide variety
of applications in phased protocols such as escrow, payment channels,
or bidirectional pegs.
===Contracts With Expiration Deadlines===
====Escrow with Timeout====
An escrow that times out automatically 30 days after being funded can be
established in the following way. Alice, Bob and Escrow create a 2-of-3
address with the following redeemscript.
IF
2 3 CHECKMULTISIG
ELSE
"30d" CHECKSEQUENCEVERIFY DROP
CHECKSIG
ENDIF
At any time funds can be spent using signatures from any two of Alice,
Bob or the Escrow.
After 30 days Alice can sign alone.
The clock does not start ticking until the payment to the escrow address
confirms.
===Retroactive Invalidation===
In many instances, we would like to create contracts that can be revoked in case
of some future event. However, given the immutable nature of the blockchain, it
is practically impossible to retroactively invalidate a previous commitment that
has already confirmed. The only mechanism we really have for retroactive
invalidation is blockchain reorganization which, for fundamental security
reasons, is designed to be very hard and very expensive to do.
Despite this limitation, we do have a way to provide something functionally similar to retroactive invalidation while preserving irreversibility of past commitments
using CHECKSEQUENCEVERIFY. By constructing scripts with multiple branches of
execution where one or more of the branches are delayed we provide
a time window in which someone can supply an invalidation condition that allows the
output to be spent, effectively invalidating the would-be delayed branch and potentially discouraging
another party from broadcasting the transaction in the first place. If the invalidation
condition does not occur before the timeout, the delayed branch becomes spendable,
honoring the original contract.
Some more specific applications of this idea:
====Hash Time-Locked Contracts====
Hash Time-Locked Contracts (HTLCs) provide a general mechanism for off-chain contract negotiation. An execution pathway can be made to require knowledge of a secret (a hash preimage) that can be presented within an invalidation time window. By sharing the secret it is possible to guarantee to the counterparty that the transaction will never be broadcast since this would allow the counterparty to claim the output immediately while one would have to wait for the time window to pass. If the secret has not been shared, the counterparty will be unable to use the instant pathway and the delayed pathway must be used instead.
====Bidirectional Payment Channels====
Scriptable relative locktime provides a predictable amount of time to respond in
the event a counterparty broadcasts a revoked transaction: Absolute locktime
necessitates closing the channel and reopen it when getting close to the timeout,
whereas with relative locktime, the clock starts ticking the moment the
transactions confirms in a block. It also provides a means to know exactly how
long to wait (in number of blocks) before funds can be pulled out of the channel
in the event of a noncooperative counterparty.
====Lightning Network====
The lightning network extends the bidirectional payment channel idea to allow for payments to be routed over multiple bidirectional payment channel hops.
These channels are based on an anchor transaction that requires a 2-of-2
multisig from Alice and Bob, and a series of revocable commitment
transactions that spend the anchor transaction. The commitment
transaction splits the funds from the anchor between Alice and Bob and
the latest commitment transaction may be published by either party at
any time, finalising the channel.
Ideally then, a revoked commitment transaction would never be able to
be successfully spent; and the latest commitment transaction would be
able to be spent very quickly.
To allow a commitment transaction to be effectively revoked, Alice
and Bob have slightly different versions of the latest commitment
transaction. In Alice's version, any outputs in the commitment
transaction that pay Alice also include a forced delay, and an
alternative branch that allows Bob to spend the output if he knows that
transaction's revocation code. In Bob's version, payments to Bob are
similarly encumbered. When Alice and Bob negotiate new balances and
new commitment transactions, they also reveal the old revocation code,
thus committing to not relaying the old transaction.
A simple output, paying to Alice might then look like:
HASH160 EQUAL
IF
ELSE
"24h" CHECKSEQUENCEVERIFY DROP
ENDIF
CHECKSIG
This allows Alice to publish the latest commitment transaction at any
time and spend the funds after 24 hours, but also ensures that if Alice
relays a revoked transaction, that Bob has 24 hours to claim the funds.
With CHECKLOCKTIMEVERIFY, this would look like:
HASH160 EQUAL
IF
ELSE
"2015/12/15" CHECKLOCKTIMEVERIFY DROP
ENDIF
CHECKSIG
This form of transaction would mean that if the anchor is unspent on
2015/12/16, Alice can use this commitment even if it has been revoked,
simply by spending it immediately, giving no time for Bob to claim it.
This means that the channel has a deadline that cannot be pushed
back without hitting the blockchain; and also that funds may not be
available until the deadline is hit. CHECKSEQUENCEVERIFY allows you
to avoid making such a tradeoff.
Hashed Time-Lock Contracts (HTLCs) make this slightly more complicated,
since in principle they may pay either Alice or Bob, depending on whether
Alice discovers a secret R, or a timeout is reached, but the same principle
applies -- the branch paying Alice in Alice's commitment transaction gets a
delay, and the entire output can be claimed by the other party if the
revocation secret is known. With CHECKSEQUENCEVERIFY, a HTLC payable to
Alice might look like the following in Alice's commitment transaction:
HASH160 DUP EQUAL
IF
"24h" CHECKSEQUENCEVERIFY
2DROP
ELSE
EQUAL
NOTIF
"2015/10/20 10:33" CHECKLOCKTIMEVERIFY DROP
ENDIF
ENDIF
CHECKSIG
and correspondingly in Bob's commitment transaction:
HASH160 DUP EQUAL
SWAP EQUAL ADD
IF
ELSE
"2015/10/20 10:33" CHECKLOCKTIMEVERIFY
"24h" CHECKSEQUENCEVERIFY
2DROP
ENDIF
CHECKSIG
Note that both CHECKSEQUENCEVERIFY and CHECKLOCKTIMEVERIFY are used in the
final branch of above to ensure Bob cannot spend the output until after both
the timeout is complete and Alice has had time to reveal the revocation
secret.
See the [https://github.com/ElementsProject/lightning/blob/master/doc/miscellaneous/deployable-lightning.pdf Deployable Lightning] paper.
====2-Way Pegged Sidechains====
The 2-way pegged sidechain requires a new REORGPROOFVERIFY opcode, the semantics of which are outside the scope of this BIP. CHECKSEQUENCEVERIFY is used to make sure that sufficient time has passed since the return peg was posted to publish a reorg proof:
IF
lockTxHeight nlocktxOut [] reorgBounty Hash160(<...>) REORGPROOFVERIFY
ELSE
withdrawLockTime CHECKSEQUENCEVERIFY DROP HASH160 p2shWithdrawDest EQUAL
ENDIF
==Specification==
Refer to the reference implementation, reproduced below, for the precise
semantics and detailed rationale for those semantics.
/* Below flags apply in the context of BIP 68 */
/* If this flag set, CTxIn::nSequence is NOT interpreted as a
* relative lock-time. */
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
/* If CTxIn::nSequence encodes a relative lock-time and this flag
* is set, the relative lock-time has units of 512 seconds,
* otherwise it specifies blocks with a granularity of 1. */
static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
/* If CTxIn::nSequence encodes a relative lock-time, this mask is
* applied to extract that lock-time from the sequence field. */
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
case OP_NOP3:
{
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
// not enabled; treat as a NOP3
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
}
break;
}
if (stack.size() < 1)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
// Note that elsewhere numeric opcodes are limited to
// operands in the range -2**31+1 to 2**31-1, however it is
// legal for opcodes to produce results exceeding that
// range. This limitation is implemented by CScriptNum's
// default 4-byte limit.
//
// Thus as a special case we tell CScriptNum to accept up
// to 5-byte bignums, which are good until 2**39-1, well
// beyond the 2**32-1 limit of the nSequence field itself.
const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5);
// In the rare event that the argument may be < 0 due to
// some arithmetic being done first, you can always use
// 0 MAX CHECKSEQUENCEVERIFY.
if (nSequence < 0)
return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
// To provide for future soft-fork extensibility, if the
// operand has the disabled lock-time flag set,
// CHECKSEQUENCEVERIFY behaves as a NOP.
if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)
break;
// Compare the specified sequence number with the input.
if (!checker.CheckSequence(nSequence))
return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
break;
}
bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) const
{
// Relative lock times are supported by comparing the passed
// in operand to the sequence number of the input.
const int64_t txToSequence = (int64_t)txTo->vin[nIn].nSequence;
// Fail if the transaction's version number is not set high
// enough to trigger BIP 68 rules.
if (static_cast(txTo->nVersion) < 2)
return false;
// Sequence numbers with their most significant bit set are not
// consensus constrained. Testing that the transaction's sequence
// number do not have this bit set prevents using this property
// to get around a CHECKSEQUENCEVERIFY check.
if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG)
return false;
// Mask off any bits that do not have consensus-enforced meaning
// before doing the integer comparisons
const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK;
const int64_t txToSequenceMasked = txToSequence & nLockTimeMask;
const CScriptNum nSequenceMasked = nSequence & nLockTimeMask;
// There are two kinds of nSequence: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
// nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
//
// We want to compare apples to apples, so fail the script
// unless the type of nSequenceMasked being tested is the same as
// the nSequenceMasked in the transaction.
if (!(
(txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) ||
(txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG)
))
return false;
// Now that we know we're comparing apples-to-apples, the
// comparison is a simple numeric one.
if (nSequenceMasked > txToSequenceMasked)
return false;
return true;
}
==Reference Implementation==
A reference implementation is provided by the following pull request:
https://github.com/bitcoin/bitcoin/pull/7524
==Deployment==
This BIP is to be deployed by "versionbits" BIP9 using bit 0.
For Bitcoin '''mainnet''', the BIP9 '''starttime''' will be midnight 1st May 2016 UTC (Epoch timestamp 1462060800) and BIP9 '''timeout''' will be midnight 1st May 2017 UTC (Epoch timestamp 1493596800).
For Bitcoin '''testnet''', the BIP9 '''starttime''' will be midnight 1st March 2016 UTC (Epoch timestamp 1456790400) and BIP9 '''timeout''' will be midnight 1st May 2017 UTC (Epoch timestamp 1493596800).
This BIP must be deployed simultaneously with BIP68 and BIP113 using the same deployment mechanism.
==Credits==
Mark Friedenbach invented the application of sequence numbers to
achieve relative lock-time, and wrote the reference implementation of
CHECKSEQUENCEVERIFY.
The reference implementation and this BIP was based heavily on work
done by Peter Todd for the closely related BIP 65.
BtcDrak authored this BIP document.
Thanks to Eric Lombrozo and Anthony Towns for contributing example use cases.
==References==
[https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP 9] Versionbits
[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP 68] Relative lock-time through consensus-enforced sequence numbers
[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP 65] OP_CHECKLOCKTIMEVERIFY
[https://github.com/bitcoin/bips/blob/master/bip-0113.mediawiki BIP 113] Median past block time for time-lock constraints
[http://lists.linuxfoundation.org/pipermail/lightning-dev/2015-July/000021.html HTLCs using OP_CHECKSEQUENCEVERIFY/OP_LOCKTIMEVERIFY and revocation hashes]
[http://lightning.network/lightning-network-paper.pdf Lightning Network]
[https://github.com/ElementsProject/lightning/blob/master/doc/miscellaneous/deployable-lightning.pdf Deployable Lightning]
[http://diyhpl.us/diyhpluswiki/transcripts/sf-bitcoin-meetup/2015-02-23-scaling-bitcoin-to-billions-of-transactions-per-day/ Scaling Bitcoin to Billions of Transactions Per Day]
[http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html Softfork deployment considerations]
[https://web.archive.org/web/20210925124425/https://gist.github.com/sipa/bf69659f43e763540550 Version bits]
[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2013-April/002433.html Jeremy Spilman Micropayment Channels]
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0113.mediawiki
================================================
BIP: 113
Layer: Consensus (soft fork)
Title: Median time-past as endpoint for lock-time calculations
Authors: Thomas Kerin
Mark Friedenbach
Status: Deployed
Type: Specification
Assigned: 2015-08-10
License: PD
==Abstract==
This BIP is a proposal to redefine the semantics used in determining a
time-locked transaction's eligibility for inclusion in a block. The
median of the last 11 blocks is used instead of the block's timestamp,
ensuring that it increases monotonically with each block.
==Motivation==
At present, transactions are excluded from inclusion in a block if the
present time or block height is less than or equal to that specified
in the locktime. Since the consensus rules do not mandate strict
ordering of block timestamps, this has the unfortunate outcome of
creating a perverse incentive for miners to lie about the time of
their blocks in order to collect more fees by including transactions
that by wall clock determination have not yet matured.
This BIP proposes comparing the locktime against the median of the
past 11 block's timestamps, rather than the timestamp of the block
including the transaction. Existing consensus rules guarantee this
value to monotonically advance, thereby removing the capability for
miners to claim more transaction fees by lying about the timestamps of
their block.
This proposal seeks to ensure reliable behaviour in locktime calculations
as required by BIP65 (CHECKLOCKTIMEVERIFY) and matching the behavior of
BIP68 (sequence numbers) and BIP112 (CHECKSEQUENCEVERIFY).
==Specification==
The values for transaction locktime remain unchanged. The difference is only in
the calculation determining whether a transaction can be included. Instead of
an unreliable timestamp, the following function is used to determine the current
block time for the purpose of checking lock-time constraints:
enum { nMedianTimeSpan=11 };
int64_t GetMedianTimePast(const CBlockIndex* pindex)
{
int64_t pmedian[nMedianTimeSpan];
int64_t* pbegin = &pmedian[nMedianTimeSpan];
int64_t* pend = &pmedian[nMedianTimeSpan];
for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
*(--pbegin) = pindex->GetBlockTime();
std::sort(pbegin, pend);
return pbegin[(pend - pbegin)/2];
}
Lock-time constraints are checked by the consensus method IsFinalTx().
This method takes the block time as one parameter. This BIP proposes
that after activation calls to IsFinalTx() within consensus code use
the return value of `GetMedianTimePast(pindexPrev)` instead.
The new rule applies to all transactions, including the coinbase transaction.
A reference implementation of this proposal is provided by the
following pull request:
https://github.com/bitcoin/bitcoin/pull/6566
==Deployment==
This BIP is to be deployed by "versionbits" BIP9 using bit 0.
For Bitcoin '''mainnet''', the BIP9 '''starttime''' will be midnight 1st May 2016 UTC (Epoch timestamp 1462060800) and BIP9 '''timeout''' will be midnight 1st May 2017 UTC (Epoch timestamp 1493596800).
For Bitcoin '''testnet''', the BIP9 '''starttime''' will be midnight 1st March 2016 UTC (Epoch timestamp 1456790400) and BIP9 '''timeout''' will be midnight 1st May 2017 UTC (Epoch timestamp 1493596800).
This BIP must be deployed simultaneously with BIP68 and BIP112 using the same deployment mechanism.
==Acknowledgements==
Mark Friedenbach for designing and authoring the reference
implementation of this BIP.
Thanks go to Gregory Maxwell who came up with the original idea,
in #bitcoin-wizards on 2013-07-16.
Thomas Kerin authored this BIP document.
==Compatibility==
Transactions generated using time-based lock-time will take
approximately an hour longer to confirm than would be expected under
the old rules. This is not known to introduce any compatibility
concerns with existing protocols.
==References==
[https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP9: Versionbits]
[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP65: OP_CHECKLOCKTIMEVERIFY]
[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP68: Consensus-enforced transaction replacement signaled via sequence numbers]
[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112: CHECKSEQUENCEVERIFY]
[http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010396.html Softfork deployment considerations]
[https://gist.github.com/sipa/bf69659f43e763540550 Version bits]
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0114.mediawiki
================================================
BIP: 114
Layer: Consensus (soft fork)
Title: Merkelized Abstract Syntax Tree
Authors: Johnson Lau
Status: Closed
Type: Specification
Assigned: 2016-04-02
License: PD
==Abstract==
This BIP defines a new witness program type that uses a Merkle tree to encode mutually exclusive branches in a script. This enables complicated redemption conditions that are currently not possible, improves privacy by hiding unexecuted scripts, and allows inclusion of non-consensus enforced data with very low or no additional cost.
==Motivation==
===Evolution of Bitcoin script system===
Bitcoin uses a script system to specify the conditions for redemption of transaction outputs. In its original design, the conditions for redemption are directly recorded in the scriptPubKey by the sender of the funds. This model has several drawbacks, particularly for complicated scripts:
# It could be difficult for the receiver to specify the conditions;
# Large scripts take up more UTXO space;
# The sender will pay for the additional block space;
# To prevent DoS attack, scripts are limited to 10,000 bytes and 201 op codes;
# Any unexecuted branches and non-consensus enforced data in the script are visible to the public, consuming block space while damaging privacy.
The [[bip-0016.mediawiki|BIP16]] (Pay-to-script-hash, "P2SH") fixes the first 3 problems by using a fixed-length 20-byte script hash in the scriptPubKey, and moving the responsibility for supplying the script to the redeemer. However, due to the data push size limit in script, a P2SH script may not be bigger than 520 bytes. Also, P2SH still requires the redeemer to publish all unexecuted branches of the script.
The [[bip-0141.mediawiki|BIP141]] defines 2 new types of scripts that support segregated witness. The pay-to-witness-script-hash (P2WSH) is similar to P2SH is many ways. By supplying the script in witness, P2WSH restores the original 10,000 byte script limit. However, it still requires publishing of unexecuted branches.
===Merkelized Abstract Syntax Tree===
The idea of Merkelized Abstract Syntax Tree (MAST) is to use a Merkle tree to encode branches in a script. When spending, users may provide only the branches they are executing, and hashes that connect the branches to the fixed size Merkel root. This reduces the size of redemption stack from O(n) to O(log n) (n as the number of branches). This enables complicated redemption conditions that is currently not possible due to the script size and opcode limit, improves privacy by hiding unexecuted branches, and allows inclusion of non-consensus enforced data with very low or no additional cost.
==Specification==
In [[bip-0141.mediawiki|BIP141]], witness programs with a version byte of 1 or larger are considered to be anyone-can-spend scripts. The following new validation rules are applied if the witness program version byte is 1 and the program size is 32 bytes.If the version byte is 1, but the witness program is not 32 bytes, no further interpretation of the witness program or witness stack happens. This is reserved for future extensions. The witness program is the MAST Root.
To redeem an output of this kind, the witness must consist of the following items:
Script_stack_1
Script_stack_2
.
.
Script_stack_X (X ≥ 0)
Subscript_1
Subscript_2
.
.
Subscript_Y (1 ≤ Y ≤ 255)
Position
Path
Metadata (Y|MAST Version)
Metadata is the last witness item. It is a vector of 1 to 5 bytes. The first byte is an unsigned integer between 1 to 255 denoting the number of Subscript (defined hereinafter). The following 0 to 4 byte(s) is an unsigned little-endian integer denoting the MAST version. MAST Version must be minimally encoded (the most significant byte must not be 0).
Path is the second last witness item. It is a serialized Merkle path of the Script Hash (defined hereinafter). Size of Path must be a multiple of 32 bytes, and not more than 1024 bytes. Each 32 byte word is a double-SHA256 merkle node in the merkle branch connecting to the Script Root (defined hereinafter). Depth of the tree (0 to 32) is the size of Path divided by 32.
Position is the third last witness item. It indicates the location of the Script Hash in the Merkle tree, with zero indicating the leftmost position. It is an unsigned little-endian integer with not more than 4 bytes. It must be minimally encoded: the value must not be larger than the maximum number of items allowed by the Depth of the tree, and the most significant byte must not be 0. For example, if Depth is 4, the valid range of Position is 0 to 15 (24-1).
Depends on the first byte of Metadata, there should be 1 to 255 Subscript witness item(s) before Position.
Script Hash is defined as:
Script Hash = H(Y|H(Subscript_1)|H(Subscript_2)|...|H(Subscript_Y))
H() = SHA256(SHA256())
where Y is a 1-byte value denoting number of Subscript, followed by the hash of each SubscriptScript Root is the Merkle root calculated by the ComputeMerkleRootFromBranch function, using Script Hash, Path and Position.
MAST Root is H(MAST Version|Script Root). The pre-image has a fixed size of 36 bytes: 4 bytes for MAST Version (unsigned little-endian integer) and 32 bytes for Script Root.
The script evaluation fails if MAST Root does not match the witness program.
If the MAST Root matches the witness program and MAST Version is greater than 0, the script returns a success without further evaluation. SigOpsCost is counted as 0. This is reserved for future script upgrades.
If the MAST Version is 0, the Subscript(s) are serialized to form the final MAST Script, beginning with Subscript_1. The unused witness item(s) before the Subscript_1 are used as Input Stack to feed to the MASTScript. (Similar to P2WSH in BIP141)
The script fails with one of the following conditions:
* MAST Script is malformed (i.e. not enough data provided for the last push operation). Individual Subscript might be malformed, as long as they are serialized into a valid MAST Script
* Size of MAST Script is larger than 10,000 bytes
* Size of any one of the Input Stack item is larger than 520 bytes
* Number of non-push operations (nOpCount) is more than 201. nOpCount is the sum of the number of non-push operations in MAST Script (counted in the same way as P2WSH witnessScript), number of Subscript (Y), and Depth of the Merkle tree.
The MAST Script is then evaluated with the Input Stack (with some new or redefined opcodes described in BIPXXX). The evaluation must not fail, and result in an exactly empty stack.
Counting of SigOpsCost is based on the MAST Script, described in BIPYYY.
== Rationale ==
=== MAST Structure ===
This proposal is a restricted case of more general MAST. In a general MAST design, users may freely assign one or more script branches for execution. In this proposal, only one branch is allowed for execution, and users are required to transform a complicated condition into several mutually exclusive branches. For example, if the desired redeem condition is:
(A or B) and (C or D or E) and (F or G)
In a general MAST design, the 7 branches (A to G) will form a 3-level Merkle tree, plus an "overall condition" describing the relationship of different branches. In redemption, the "overall condition", executed branches (e.g. B, D, F), and Merkle path data will be provided for validation.
In the current proposal, the user has to transform the redeem condition into 12 mutually exclusive branches and form a 4-level Merkle tree, and present only one branch in redemption:
A and C and F
B and C and F
A and D and F
.
.
B and E and G
One way to implement the general MAST design is using a combination of OP_EVAL, OP_CAT, and OP_HASH256. However, that will suffer from the problems of OP_EVAL, including risks of indefinite program loop and inability to do static program analysis. A complicated implementation is required to fix these problems and is difficult to review.
The advantages of the current proposal are:
* Subscript are located at a fixed position in the witness stack. This allows static program analysis, such as static SigOpsCost counting and early termination of scripts with disabled opcodes.
* If different parties in a contract do not want to expose their scripts to each other, they may provide only H(Subscript) and keep the Subscript private until redemption.
* If they are willing to share the actual scripts, they may combine them into one Subscript for each branch, saving some nOpCount and a few bytes of witness space.
There are some disadvantages, but only when the redemption condition is very complicated:
* It may require more branches than a general MAST design (as shown in the previous example) and take more witness space in redemption
* Creation and storage of the MAST structure may take more time and space. However, such additional costs affect only the related parties in the contract but not any other Bitcoin users.
=== MAST Version ===
This proposal allows users to indicate the version of scripting language in the witness, which is cheaper than doing that in scriptPubKey or scriptSig. Undefined versions remain anyone-can-spend and are reserved for future expansions. A new version could be used for relaxing constraints (e.g. the 10,000 bytes size limit of MAST Script), adding or redefining opcodes, or even introducing a completely novel scripting system.
=== nOpCount limit ===
In version 0 MAST, the extra hashing operations in calculating the MAST Root are counted towards the 201 nOpCount limit to prevent abusive use. This limitation is not applied to undefined MAST Version for flexibility, but it is constrained by the 255 Subscript and 32 Depth limits.
=== Script evaluation ===
This proposal requires script evaluation resulting in an empty stack, instead of a single TRUE value as in P2WSH. This allows each party in a contract to provide its own Subscript, and demonstrate the required Input Stack to clean up its own Subscript. In this case, order of the Subscript is not important since the overall objective is to clean up the stack after evaluation.
== Examples ==
=== Calculation of MAST Root ===
Subscript:
SA = 1 EQUALVERIFY (0x5188)
SB = 2 EQUALVERIFY (0x5288)
SC = 3 EQUALVERIFY (0x5388)
SD = 4 EQUALVERIFY (0x5488)
SE = 5 EQUALVERIFY (0x5588)
SF = 6 EQUALVERIFY (0x5688)
SG = 7 EQUALVERIFY (0x5788)
SH = 8 EQUALVERIFY (0x5888)
M = RETURN "Hello" (0x6a0548656c6c6f)
Hash:
HA = H(0x01|H(SA)) = H(0x015acb54166e0db370cd1b05a29120373568dacea2abc3748459ec3da2106e4b4e) = 0xd385d7268ad7e1ec51660f833d54787d2d8d79b6b1809d9c1d06c9e71f7be204
HB = H(0x02|H(SB)|H(SC)) = 0x7cbfa08e44ea9f4f996873be95d9bffd97d4b91a5af32cc5f64efb8461727cdd
HF = H(0x03|H(SD)|H(SE)|H(SF)) = 0x4611414355945a7c2fcc62a53a0004821b87e68f93048ffba7a55a3cb1e9783b
HG = H(0x01|H(SG)) = 0xaa5fbdf58264650eadec33691ba1e7606d0a62f570eea348a465c55bc86ffc10
HC = H(0x01|H(M)) = 0x70426d480d5b28d93c5be54803681f99abf4e8df4eab4dc87aaa543f0d138159
HD = H(0x0x|H(SH)) = 0x8482f6c9c3fe90dd4d533b4efedb6a241b95ec9267d1bd5aaaee36d2ce2dd6da
HE = H(HA|HB) = 0x049b9f2f94f0a9bdea624e39cd7d6b27a365c6a0545bf0e9d88d86eff4894210
HH = H(HC|HD) = 0xc709fdc632f370f3367da45378d1cf430c5fda6805e731ad5761c213cf2d276e
HI = H(HE|HF) = 0xead5e1a1e7e41b77b794f091df9be3f0e9f41d47304eb43dece90688f69843b7
HJ = H(HG|HH) = 0xd00fc690c4700d0f983f9700740066531ea826b21a4cbc62f80317261723d477
Script Root = H(HI|HJ) = 0x26d5235d20daf1440a15a248f5b5b4f201392128072c55afa64a26ccc6f56bd9
MAST Root = H(MAST Version|Script Root) = H(0x0000000026d5235d20daf1440a15a248f5b5b4f201392128072c55afa64a26ccc6f56bd9) = 0xb4b706e0c02eab9aba58419eb7ea2a286fb1c01d7406105fc12742bf8a3f97c9
The scriptPubKey with native witness program is:
1 <0xb4b706e0c02eab9aba58419eb7ea2a286fb1c01d7406105fc12742bf8a3f97c9>
(0x5120b4b706e0c02eab9aba58419eb7ea2a286fb1c01d7406105fc12742bf8a3f97c9)
To redeem with the SD|SE|SF branch, the witness is
Script_stack_1: 0x06
Script_stack_2: 0x05
Script_stack_3: 0x04
Subscript_1: 0x5488
Subscript_2: 0x5588
Subscript_3: 0x5688
Position: 0x01 (HF is the second hash in its level)
Path (HE|HJ): 0x049b9f2f94f0a9bdea624e39cd7d6b27a365c6a0545bf0e9d88d86eff4894210d00fc690c4700d0f983f9700740066531ea826b21a4cbc62f80317261723d477
Metadata: 0x03 (3 Subscript)
=== Imbalance MAST ===
When constructing a MAST, if the user believes that some of the branches are more likely to be executed, they may put them closer to the Script Root. It will save some witness space when the preferred branches are actually executed.
=== Escrow with Timeout ===
The following is the "Escrow with Timeout" example in [[bip-0112.mediawiki|BIP112]]:
IF
2 3 CHECKMULTISIG
ELSE
"30d" CHECKSEQUENCEVERIFY DROP
CHECKSIG
ENDIF
Using compressed public key, the size of this script is 150 bytes.
With MAST, this script could be broken down into 2 mutually exclusive branches:In BIPXXX, it is proposed that CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY will pop the top stack item
2 3 CHECKMULTISIGVERIFY (105 bytes)
"30d" CHECKSEQUENCEVERIFY CHECKSIGVERIFY (42 bytes)
Since only one branch will be published, it is more difficult for a blockchain analyst to determine the details of the escrow.
=== Hashed Time-Lock Contract ===
The following is the "Hashed TIme-Lock Contract" example in [[bip-0112.mediawiki|BIP112]]:
HASH160 DUP EQUAL
IF
"24h" CHECKSEQUENCEVERIFY
2DROP
ELSE
EQUAL
NOTIF
"Timestamp" CHECKLOCKTIMEVERIFY DROP
ENDIF
ENDIF
CHECKSIG
To create a MAST Root, it is flattened to 3 mutually exclusive branches:
HASH160 EQUALVERIFY "24h" CHECKSEQUENCEVERIFY CHECKSIGVERIFY
HASH160 EQUALVERIFY CHECKSIGVERIFY
"Timestamp" CHECKLOCKTIMEVERIFY CHECKSIGVERIFY
which significantly improves readability and reduces the witness size when it is redeemed.
=== Large multi-signature constructs ===
The current CHECKMULTISIG supports up to 20 public keys. Although it is possible to extend it beyond 20 keys by using multiple CHECKSIGs and IF/ELSE conditions, the construction could be very complicated and soon use up the 10,000 bytes and 201 nOpCount limit.
With MAST, large and complex multi-signature constructs could be flattened to many simple CHECKMULTISIGVERIFY conditions. For example, a 3-of-2000 multi-signature scheme could be expressed as 1,331,334,000 3-of-3 CHECKMULTISIGVERIFY, which forms a 31-level MAST. The scriptPubKey still maintains a fixed size of 34 bytes, and the redemption witness will be very compact, with less than 1,500 bytes.
=== Commitment of non-consensus enforced data ===
Currently, committing non-consensus enforced data in the scriptPubKey requires the use of OP_RETURN which occupies additional block space. With MAST, users may commit such data as a branch. Depends on the number of executable branches, inclusion of such a commitment may incur no extra witness space, or 32 bytes at most.
An useful case would be specifying "message-signing keys", which are not valid for spending, but allow users to sign any message without touching the cold storage "funding key".
== Backward compatibility ==
As a soft fork, older software will continue to operate without modification. Non-upgraded nodes, however, will consider MAST programs as anyone-can-spend scripts. Wallets should always be wary of anyone-can-spend scripts and treat them with suspicion.
== Deployment ==
This BIP depends on [[bip-0141.mediawiki|BIP141]] and will be deployed by version-bits [[bip-0009.mediawiki|BIP9]] after BIP141 is enforced. Exact details TBD.
== Credits ==
The idea of MAST originates from Russell O’Connor, Pieter Wuille, and [https://bitcointalk.org/index.php?topic=255145.msg2757327#msg2757327 Peter Todd].
== Reference Implementation ==
https://github.com/jl2012/bitcoin/tree/bip114v2 (WIP)
//New rules apply if version byte is 1 and witness program size is 32 bytes
if (witversion == 1 && program.size() == 32 && (flags & SCRIPT_VERIFY_MAST)) {
CHashWriter sRoot(SER_GETHASH, 0);
CHashWriter sScriptHash(SER_GETHASH, 0);
uint32_t nMASTVersion = 0;
size_t stacksize = witness.stack.size();
if (stacksize < 4)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
std::vector metadata = witness.stack.back(); // The last witness stack item is metadata
if (metadata.size() < 1 || metadata.size() > 5)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
// The first byte of metadata is the number of subscripts (1 to 255)
uint32_t nSubscript = static_cast(metadata[0]);
if (nSubscript == 0 || stacksize < nSubscript + 3)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
int nOpCount = nSubscript; // Each condition consumes a nOpCount
sScriptHash << metadata[0];
// The rest of metadata is MAST version in minimally-coded unsigned little endian int
if (metadata.back() == 0)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
if (metadata.size() > 1) {
for (size_t i = 1; i != metadata.size(); ++i)
nMASTVersion |= static_cast(metadata[i]) << 8 * (i - 1);
}
// Unknown MAST version is non-standard
if (nMASTVersion > 0 && flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
sRoot << nMASTVersion;
// The second last witness stack item is the pathdata
// Size of pathdata must be divisible by 32 (0 is allowed)
// Depth of the Merkle tree is implied by the size of pathdata, and must not be greater than 32
std::vector pathdata = witness.stack.at(stacksize - 2);
if (pathdata.size() & 0x1F)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
unsigned int depth = pathdata.size() >> 5;
if (depth > 32)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
// Each level of Merkle tree consumes a nOpCount
// Evaluation of version 0 MAST terminates early if there are too many nOpCount
// Not enforced in unknown MAST version for upgrade flexibility
nOpCount = nOpCount + depth;
if (nMASTVersion == 0 && nOpCount > MAX_OPS_PER_SCRIPT)
return set_error(serror, SCRIPT_ERR_OP_COUNT);
// path is a vector of 32-byte hashes
std::vector path;
path.resize(depth);
for (unsigned int j = 0; j < depth; j++)
memcpy(path[j].begin(), &pathdata[32 * j], 32);
// The third last witness stack item is the positiondata
// Position is in minimally-coded unsigned little endian int
std::vector positiondata = witness.stack.at(stacksize - 3);
if (positiondata.size() > 4)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
uint32_t position = 0;
if (positiondata.size() > 0) {
if (positiondata.back() == 0)
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
for (size_t k = 0; k != positiondata.size(); ++k)
position |= static_cast(positiondata[k]) << 8 * k;
}
// Position value must not exceed the number of leaves at the depth
if (depth < 32) {
if (position >= (1U << depth))
return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK);
}
// Sub-scripts are located before positiondata
for (size_t i = stacksize - nSubscript - 3; i <= stacksize - 4; i++) {
CScript subscript(witness.stack.at(i).begin(), witness.stack.at(i).end());
// Evaluation of version 0 MAST terminates early if script is oversize
// Not enforced in unknown MAST version for upgrade flexibility
if (nMASTVersion == 0 && (scriptPubKey.size() + subscript.size()) > MAX_SCRIPT_SIZE)
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
uint256 hashSubScript;
CHash256().Write(&subscript[0], subscript.size()).Finalize(hashSubScript.begin());
sScriptHash << hashSubScript;
scriptPubKey = scriptPubKey + subscript; // Final scriptPubKey is a serialization of subscripts
}
uint256 hashScript = sScriptHash.GetHash();
// Calculate MAST Root and compare against witness program
uint256 rootScript = ComputeMerkleRootFromBranch(hashScript, path, position);
sRoot << rootScript;
uint256 rootMAST = sRoot.GetHash();
if (memcmp(rootMAST.begin(), &program[0], 32))
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
if (nMASTVersion == 0) {
stack = std::vector >(witness.stack.begin(), witness.stack.end() - 3 - nSubscript);
for (unsigned int i = 0; i < stack.size(); i++) {
if (stack.at(i).size() > MAX_SCRIPT_ELEMENT_SIZE)
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}
// Script evaluation must not fail, and return an empty stack
if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_WITNESS_V1, nOpCount, serror))
return false;
if (stack.size() != 0)
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
}
return set_success(serror);
}
Copying from src/consensus/merkle.cpp:
uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector& vMerkleBranch, uint32_t nIndex) {
uint256 hash = leaf;
for (std::vector::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) {
if (nIndex & 1) {
hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
} else {
hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
}
nIndex >>= 1;
}
return hash;
}
== References ==
*[[bip-0141.mediawiki|BIP141 Segregated Witness (Consensus layer)]]
== Copyright ==
This document is placed in the public domain.
================================================
FILE: bip-0115.mediawiki
================================================
==Abstract==
This BIP describes a new opcode (OP_CHECKBLOCKATHEIGHT) for the Bitcoin scripting system that allows construction of transactions which are valid only on specific blockchains.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Specification==
OP_CHECKBLOCKATHEIGHT redefines the existing OP_NOP5 opcode.
When this opcode is executed:
* If the stack has fewer than 2 elements, the script fails.
* If the top item on the stack cannot be interpreted as a minimal-length 32-bit CScriptNum, the script fails.
* The top item on the stack is interpreted as a block height (ParamHeight).
* If the blockchain (in the context of the execution) does not have ParamHeight blocks prior to the one including this transaction, the script fails (this failure must not be cached across blocks; it is equivalent to non-final status).
* If ParamHeight specifies a block deeper than 52596 blocks in the chain (including negative values), the opcode completes successfully and script continues as normal.
* The second-to-top item on the stack is interpreted as a block hash (ParamBlockHash).
* If ParamBlockHash is longer than 28 bytes, the script fails.
* If ParamBlockHash does not match the equivalent ending bytes of the block hash specified by ParamHeight, the script fails.
Otherwise, script execution will continue as if a NOP had been executed.
===Deployment===
This BIP will be deployed by "version bits" [[bip-0009.mediawiki|BIP9]] with the '''name''' "cbah" and using '''bit''' TBD.
For Bitcoin '''mainnet''', the BIP9 '''starttime''' will be TBD (Epoch timestamp TBD) and BIP9 '''timeout''' will be TBD (Epoch timestamp TBD).
For Bitcoin '''mainnet''', the BIP9 '''starttime''' will be TBD (Epoch timestamp TBD) and BIP9 '''timeout''' will be TBD (Epoch timestamp TBD).
==Motivation==
===Securely recovering from double spends===
In some circumstances, users may wish to spend received bitcoins before they have confirmed on the blockchain (Tx B1).
However, if the transaction sending them those bitcoins (Tx A1) is double-spent, the wallet must re-issue their own transaction spending them (Tx B2).
So long as the double-spend of the incoming transaction (Tx A2) also pays the wallet, this can be managed by simply updating the outgoing transaction with the new outpoint and resigning.
However, if the double-spend does not pay the wallet, the situation is presently irrecoverable:
it must spend different, non-conflicting TXOs in Tx B2, which allows an attacker to then reorganise the chain (reversing the incoming transaction's double-spend) and confirm both of his transactions Tx B1 and Tx B2.
By adding OP_CHECKBLOCKATHEIGHT, the wallet can issue Tx B2 with a condition that the block confirming Tx A2 is in the history, thus eliminating this risk.
===Replay protection in the event of a persistent blockchain split===
In the event of a persistent blockchain split, some mechanism is desired by which the UTXOs valid in either chain may be spent without the transaction being validly replayable on the other chain.
This can be guaranteed by choosing a block which exists only on either side of the split, and pinning (using OP_CHECKBLOCKATHEIGHT) common UTXOs to be spent only on chains based on that block.
==Best practices for wallets==
To avoid unnecessary conflicts when a chain is reorganized, wallets should always avoid specifying the last 100 blocks when practical.
Wallets that use recent blocks when unavoidable SHOULD actively monitor the network and re-create transactions that are reorganised out with updated block hashes.
Unless it conflicts with local/user security policies, wallets SHOULD retain the private key in memory to re-sign such transactions until the pinned block is at least 100 blocks deep into the chain.
For ordinary usage, wallets SHOULD specify the ParamBlockHash as 16 bytes.
==Rationale==
How is this different from the transaction's lock-time?
* The lock-time specifies a time or block height before a transaction becomes valid. OP_CHECKBLOCKATHEIGHT, on the other hand, specifies a specific block's hash.
Why are block heights required to be absolute, rather than relative?
* A relative block height would allow for creation of transactions which are valid at block N, but not N+1. This is carefully avoided by Bitcoin to ensure that if any given block is reorganised out, non-malicious transactions can be simply re-confirmed in a later block.
Why are blocks older than 52596 deep in the chain not verified?
* This is to avoid creating an infinite storage requirement from all full nodes which would be necessary to maintain all the block headers indefinitely. 52596 block headers requires a fixed size of approximately 4 MB.
* In any case where you might want to specify a deeper block, you can also just as well specify a more recent one that descends from it.
* It is assumed that 1 year is sufficient time to double-spend any common UTXOs on all blockchains of interest.
* If a deeper check is needed, it can be softforked in. Making the check more shallow, on the other hand, is a hardfork.
Why is ParamBlockHash allowed to match less than the full block hash?
* In a chain split, it is sufficient to check only a few bytes to avoid replay.
* In all scenarios, it is likely sufficient to check only a minority of the full hash to avoid any realistic chance of replay.
* Allowing less than the full hash to be specified saves space in transaction data.
* Using a single byte can be combined with other opcodes (such as OP_LESSTHAN) to enable on-chain gambling logic.
What if ParamBlockHash has leading zeros? Should this be prevented?
* If leading zeros are included, they should be compared to the actual block hash. (If they were truncated, fewer bytes would be compared.)
* It is unlikely that the leading zeros will ever be necessary for sufficient precision, so the additional space is not a concern.
* Since all block hashes are in principle shorter than 29 bytes, ParamBlockHash may not be larger than 28 bytes.
Why is it safe to allow checking blocks as recently as the immediate previous block?
* This should only be used when necessary (ie, the deeper block is not sufficient), and when the wallet can actively issue updates should the blockchain reorganise.
* While this allows intentionally creating a transaction which may be invalid in a reorganization, the same can already be accomplished by creating double spends.
==Backwards Compatibility==
OP_NOP5 ought to be forbidden by policy by all miners for future extensions such as this, so old miners will under no circumstances produce blocks which would now be considered invalid under the new rules.
However, miners must still upgrade to avoid accepting and building on top of such a possible invalid block as part of an attack.
Old nodes will likely also not relay transactions using this opcode for the same extensibility reasons, but this is not important since the rule cannot be verified deterministically outside the context of a block.
==Reference Implementation==
https://github.com/bitcoin/bitcoin/compare/master...luke-jr:cbah
================================================
FILE: bip-0116.mediawiki
================================================
BIP: 116
Layer: Consensus (soft fork)
Title: MERKLEBRANCHVERIFY
Authors: Mark Friedenbach
Kalle Alm
BtcDrak
Status: Draft
Type: Specification
Assigned: 2017-08-25
License: CC-BY-SA-4.0
License-Code: MIT
==Abstract==
A general approach to bitcoin contracts is to fully enumerate the possible spending conditions and then program verification of these conditions into a single script.
At redemption, the spending condition used is explicitly selected, e.g. by pushing a value on the witness stack that cascades through a series of if/else constructs.
This approach has significant downsides, such as requiring all program pathways to be visible in the scriptPubKey or redeem script, even those which are not used at validation.
This wastes space on the block chain, restricts the size of possible scripts due to push limits, and impacts both privacy and fungibility as details of the contract can often be specific to the user.
This BIP proposes a new soft-fork upgradeable opcode, MERKLEBRANCHVERIFY, which allows script writers to commit to a set of data elements and have one or more of these elements be provided at redemption without having to reveal the entire set.
As these data elements can be used to encode policy, such as public keys or validation subscripts, the MERKLEBRANCHVERIFY opcode can be used to overcome these limitations of existing bitcoin script.
==Copyright==
This BIP is licensed under a Creative Commons Attribution-ShareAlike license. All provided source code is licensed under the MIT license.
==Specification==
MERKLEBRANCHVERIFY redefines the existing NOP4 opcode.
When executed, if any of the following conditions are true, the script interpreter will terminate with an error:
# the stack contains less than three (3) items;
# the first item on the stack is more than 2 bytes;
# the first item on the stack, interpreted as an integer, N, is negative or not minimally encoded;
# the second item on the stack is not exactly 32 bytes;
# the third item on the stack is not a serialized Merkle tree inclusion proof as specified by BIP98[1] and requiring exactly floor(N/2) VERIFY hashes; or
# the remainder of the stack contains less than floor(N/2) additional items, together referred to as the input stack elements.
If the low-order bit of N is clear, N&1 == 0, each input stack element is hashed using double-SHA256.
Otherwise, each element must be exactly 32 bytes in length and are interpreted as serialized hashes.
These are the VERIFY hashes.
If the fast Merkle root computed from the Merkle tree inclusion proof, the third item on the stack,
with the VERIFY hashes in the order as presented on the stack, from top to bottom,
does not exactly match the second item on the stack,
the script interpreter will terminate with an error.
Otherwise, script execution will continue as if a NOP had been executed.
==Motivation==
Although BIP16 (Pay to Script Hash)[2] and BIP141 (Segregated Witness)[3] both allow the redeem script to be kept out of the scriptPubKey and therefore out of the UTXO set, the entire spending conditions for a coin must nevertheless be revealed when that coin is spent.
This includes execution pathways or policy conditions which end up not being needed by the redemption.
Not only is it inefficient to require this unnecessary information to be present on the blockchain, albeit in the witness, it also impacts privacy and fungibility as some unused script policies may be identifying.
Using a Merkle hash tree to commit to the policy options, and then only forcing revelation of the policy used at redemption minimizes this information leakage.
Using Merkle hash trees to commit to policy allows for considerably more complex contracts than would otherwise be possible, due to various built-in script size and runtime limitations.
With Merkle commitments to policy these size and runtime limitations constrain the complexity of any one policy that can be used rather than the sum of all possible policies.
==Rationale==
The MERKLEBRANCHVERIFY opcode uses fast Merkle hash trees as specified by BIP98[1] rather than the construct used by Satoshi for committing transactions to the block header as the later has a known vulnerability relating to duplicate entries that introduces a source of malleability to downstream protocols[4].
A source of malleability in Merkle proofs could potentially lead to spend vulnerabilities in protocols that use MERKLEBRANCHVERIFY.
For example, a compact 2-of-N policy could be written by using MERKLEBRANCHVERIFY to prove that two keys are extracted from the same tree, one at a time, then checking the proofs for bitwise equality to make sure the same entry wasn't used twice.
With the vulnerable Merkle tree implementation there are privileged positions in unbalanced Merkle trees that allow multiple proofs to be constructed for the same, single entry.
BIP141 (Segregated Witness)[3] provides support for a powerful form of script upgrades called script versioning, which is able to achieve the sort of upgrades which would previously have been hard-forks.
If script versioning were used for deployment then MERKLEBRANCHVERIFY could be written to consume its inputs, which would provide a small 2-byte savings for many anticipated use cases.
However the more familiar NOP-expansion soft-fork mechanism used by BIP65 (CHECKLOCKTIMEVERIFY)[5] and BIP112 (CHECKSEQUENCEVERIFY)[6] was chosen over script versioning for the following two reasons:
# '''Infrastructure compatibility.''' Using soft-fork NOP extensions allows MERKLEBRANCHVERIFY to be used by any existing software able to consume custom scripts, and results in standard P2SH or P2WSH-nested-in-P2SH addresses without the need for BIP143[7] signing code. This allows MERKLEBRANCHVERIFY to be used immediately by services that need it rather than wait on support for script versioning and/or BIP-143[7] signatures in tools and libraries.
# '''Delayed decision on script upgrade protocol.''' There are unresolved issues with respect to how script versioning should be used for future script upgrades. There are only 16 available script versions reserved for future use, and so they should be treated as a scarce resource. Additionally, script feature versioning should arguably be specified in the witness and the BIP141 script versioning only be used to specify the structure of the witness, however no such protocol exists as of yet. Using the NOP-expansion space prevents MERKLEBRANCHVERIFY from being stalled due to waiting on script upgrade procedure to be worked out, while making use of expansion space that is already available.
The MERKLEBRANCHVERIFY opcode allows for VERIFY hashes to be presented directly, or calculated from the leaf values using double-SHA256.
In most cases the latter approach is expected to be used so that the leaf value(s) can be used for both branch validation and other purposes without any explicit preprocessing.
However allowing already-calculated hash values as inputs enables using chained MERKLEBRANCHVERIFY opcodes to verify branches of trees with proofs large enough that they would not fit in the 520 byte script push limitation.
As specified, a 30-branch path can be verified by proving the path from the leaf to the 15th interior node as the 'root', then proving that node's hash to be a child of the actual Merkle tree root hash.
Validation of a 256-branch path (e.g. a binary prefix tree with a hash value as key) would require 18 chained validations, which would fit within current script limitations.
==Applications==
===1-of-N for large N===
Here is a redeem script that allows a coin to be spent by any key from a large set, without linear scaling in script size:
redeemScript: 2 MERKLEBRANCHVERIFY 2DROP DROP CHECKSIG
witness:
The redeem script looks very similar to the standard pay-to-pubkey-hash, except instead of showing that the pubkey's hash is the same as the commitment given, we demonstrate that the pubkey is one of potentially many pubkeys included in the Merkle tree committed to in the redeem script.
The low-order bit of the first parameter, 2, is clear, meaning that there is one input ((2>>1) == 1), the serialized pubkey, and its VERIFY hash needs to be calculated by MERKLEBRANCHVERIFY using double-SHA256.
===Honeypots===
As described by Pieter Wuille[8] the 1-of-N scheme is particularly useful for constructing honeypots.
The desire is to put a large bounty on a server, larger than the value of the server itself so that if the server is compromised it is highly likely that the hacker will claim the bitcoin, thereby revealing the intrusion.
However if there are many servers, e.g. 1,000, it becomes excessively expensive to lock up separate bounties for each server.
It would be desirable if the same bounty was shared across multiple servers in such a way that the spend would reveal which server was compromised.
This is accomplished by generating 1,000 different keys, building a hash tree of these public keys, and placing each key and associated Merkle path on separate servers.
When the honeypot is claimed, the (previous) owner of the coins can tell which server was compromised from the key and path used to claim the funds.
==Implementation==
An implementation of this BIP, including both consensus code updates and tests is available at the following Github repository:
[https://github.com/maaku/bitcoin/tree/merkle-branch-verify]
==Deployment==
This BIP will be deployed by BIP8 (Version bits with lock-in by height)[10] with the name "merklebranchverify" and using bit 2.
For Bitcoin mainnet, the BIP8 startheight will be at height M to be determined and BIP8 timeout activation will occur on height M + 50,400 blocks.
For Bitcoin testnet, the BIP8 startheight will be at height T to be determined and BIP8 timeout activation will occur on height T + 50,400 blocks.
We note that DISCOURAGE_UPGRADABLE_NOPS means that transactions which use this feature are already considered non-standard by the rules of the network, making deployment easier than was the case with, for example, with BIP68 (Relative lock-time using consensus-enforced sequence numbers)[9].
==Compatibility==
Old clients will consider the OP_MERKLEBRANCHVERIFY as a NOP and ignore it. Proof will not be verified, but the transaction will be accepted.
==References==
[1] [https://github.com/bitcoin/bips/blob/master/bip-0098.mediawiki BIP98: Fast Merkle Trees (Consensus layer)]
[2] [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki BIP16: Pay to Script Hash]
[3] [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141: Segregated Witness (Consensus layer)]
[4] [https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2459 National Vulnerability Database: CVE-2012-2459]
[5] [https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP65: OP_CHECKLOCKTIMEVERIFY]
[6] [https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112: CHECKSEQUENCEVERIFY]
[7] [https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143: Transaction Signature Verification for Version 0 Witness Program]
[8] [https://blockstream.com/2015/08/24/treesignatures.html Multisig on steroids using tree signatures]
[9] [https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP68: Relative lock-time using consensus-enforced sequence numbers]
[10] [https://github.com/bitcoin/bips/blob/master/bip-0008.mediawiki BIP8: Version bits with lock-in by height]
================================================
FILE: bip-0117.mediawiki
================================================
BIP: 117
Layer: Consensus (soft fork)
Title: Tail Call Execution Semantics
Authors: Mark Friedenbach
Kalle Alm
BtcDrak
Status: Draft
Type: Specification
Assigned: 2017-08-25
License: CC-BY-SA-4.0
License-Code: MIT
==Abstract==
BIP16 (Pay to Script Hash)[1] and BIP141 (Segregated Witness)[2] provide mechanisms by which script policy can be revealed at spend time as part of the execution witness.
In both cases only a single script can be committed to by the construct.
While useful for achieving the goals of these proposals, they still require that all policies be specified within the confine of a single script, regardless of whether the policies are needed at the time of spend.
This BIP, in conjunction with BIP116 (MERKLEBRANCHVERIFY)[3] allows for a script to commit to a practically unbounded number of code pathways, and then reveal the actual code pathway used at spend time.
This achieves a form of generalized MAST[4] enabling decomposition of complex branching scripts into a set of non-branching flat execution pathways, committing to the entire set of possible pathways, and then revealing only the path used at spend time.
==Copyright==
This BIP is licensed under a Creative Commons Attribution-ShareAlike license. All provided source code is licensed under the MIT license.
==Specification==
If, at the end of script execution:
* the execution state is non-clean, meaning
*# the main stack has more than one item on it, or
*# the main stack has exactly one item and the alt-stack is not empty;
* the top-most element of the main stack evaluates as true when interpreted as a bool; and
* the top-most element is not a single byte or is outside the inclusive range of 0x51 to 0x60,
then that top-most element of the main stack is popped and interpreted as a serialized script and executed,
while the remaining elements of both stacks remain in place as inputs.
If the above conditions hold except for the last one, such that:
* the top-most element ''is'' a single byte within the inclusive range of 0x51 (OP_1, meaning N=2) to 0x60 (OP_16, meaning N=17); and
* other than this top-most element there are at least N additional elements on the main stack and alt stack combined,
then the top-most element of the main stack is dropped,
and the N=2 (0x51) to 17 (0x60) further elements are popped from the main stack,
continuing from the alt stack if the main stack is exhausted,
and concatenated together in reverse order to form a serialized script,
which is then executed with the remaining elements of both stacks remaining in place as inputs.
The presence of CHECKSIG or CHECKMULTISIG within the subscript do not count towards the global MAX_BLOCK_SIGOPS_COST limit,
and the number of non-push opcodes executed in the subscript is not limited by MAX_OPS_PER_SCRIPT.
Execution state, other than the above exceptions, carries over into the subscript,
and termination of the subscript terminates execution of the script as a whole.
This is known as execution with tail-call semantics.
Only one such tail-call of a subscript is allowed per script execution context, and only from within a segwit redeem script.
Alternatively stated, neither evaluation of witness stack nor execution of the scriptPubKey or scriptSig or P2SH redeem script results in tail-call semantics.
==Motivation==
BIP16 (Pay to Script Hash)[1] and BIP141 (Segregated Witness)[2] allow delayed revelation of a script's policy until the time of spend.
However these approaches are limited in that only a single policy can be committed to in a given transaction output.
It is not possible to commit to multiple policies and then choose, at spend time, which to reveal.
BIP116 (MERKLEBRANCHVERIFY)[3] allows multiple data elements to be committed to while only revealing those necessary at the time of spend.
The MERKLEBRANCHVERIFY opcode is only able to provide commitments to a preselected set of data values, and does not by itself allow for executing code.
This BIP generalizes the approach of these prior methods by allowing the redeem script to perform any type of computation necessary to place the policy script on the stack.
The policy script is then executed from the top of the data stack in a way similar to how BIP16 and BIP141 enable redeem scripts to be executed from the top of the witness stack.
In particular, using MERKLEBRANCHVERIFY[3] in the scriptPubKey or redeem script allows selection of the policy script that contains only the necessary conditions for validation of the spend.
This is a form of generalized MAST[4] where a stage of precomputation splits a syntax tree into possible execution pathways, which are then enumerated and hashed into a Merkle tree of policy scripts.
At spend time membership in this tree of the provided policy script is proven before execution recurses into the policy script.
==Rationale==
This proposal is a soft-fork change to bitcoin's consensus rules because leaving a script that data-wise evaluates as true from its serialized form on the stack as execution terminates would result in the script validation returning true anyway.
Giving the subscript a chance to terminate execution is only further constraining the validation rules.
The only scripts which would evaluate as false are the empty script, or a script that does nothing more than push empty/zero values to the stack.
None of these scripts have any real-world utility, so excluding them to achieve soft-fork compatibility doesn't come with any downsides.
By restricting ourselves to tail-call evaluation instead of a more general EVAL opcode we greatly simplify the implementation.
Tail-call semantics means that execution never returns to the calling script's context, and therefore no state needs to be saved or later restored.
The implementation is truly as simple as pulling the subscript off the stack, resetting a few state variables, and performing a jump back to the beginning of the script interpreter.
The restriction to allow only one layer of tail-call recursion is admittedly limiting, however the technical challenges to supporting multi-layer tail-call recursion are significant.
A new metric would have to be developed to track script resource usage, for which transaction data witness size are only two factors.
This new weight would have to be relayed with transactions, used as the basis for fee calculation, validated in-line with transaction execution, and policy decided upon for DoS-banning peers that propagate violating transactions.
However should these problems be overcome, dropping the single recursion constraint is itself a soft-fork for the same reason, applied inductively.
Allowing only one layer of tail-call recursion allows us to receive the primary benefit of multi-policy commitments / generalized MAST,
while leaving the door open to future generalized tail-call recursion if and when the necessary changes are made to resource accounting and p2p transaction distribution.
The global SIGOP limit and per-script opcode limits do not apply to the policy script
because dynamic selection of the policy script makes it not possible for static analysis tools to verify these limits in general,
and because performance improvements to libsecp256k1 and Bitcoin Core have made these limits no longer necessary as they once were.
The validation costs are still limited by the number of signature operations it is possible to encode within block size limits,
and the maximum script size per input is limited to 10,000 + 17*520 = 18,840 bytes.
To allow for this drop of global and per-script limits,
tail-call evaluation cannot be allowed for direct execution of the scriptPubKey,
as such scripts are fetched from the UTXO and do not count towards block size limits of the block being validated.
Likewise tail-call from P2SH redeem scripts is not supported due to quadratic blow-up vulnerabilities that are fixed in segwit.
==Generalized MAST==
When combined with BIP116 (MERKLEBRANCHVERIFY)[3], tail-call semantics allows for generalized MAST capabilities[4].
The script author starts with a full description of the entire contract they want to validate at the time of spend.
The possible execution pathways through the script are then enumerated, with conditional branches replaced by a validation of the condition and the branch taken.
The list of possible execution pathways is then put into a Merkle tree, with the flattened policy scripts as the leaves of this tree.
The final redeem script which funds are sent to is as follows:
redeemScript: 2 MERKLEBRANCHVERIFY 2DROP DROP
witness: ...
Where policyScript is the flattened execution pathway, proof is the serialized Merkle branch and path that proves the policyScript is drawn from the set used to construct the Merkle tree root, and arg1 through argN are the arguments required by policyScript.
The 2 indicates that a single leaf (1 << 1) follows, and the leaf value is not pre-hashed.
The 2DROP DROP is necessary to remove the arguments to MERKLEBRANCHVERIFY from the stack.
The above example was designed for clarity, but actually violates the CLEANSTACK rule of segwit v0 script execution.
Unless the CLEANSTACK rule is dropped or modified in a new segwit output version, this would script would have to be modified to use the alt-stack, as follows:
redeemScript: [TOALTSTACK]*N 2 MERKLEBRANCHVERIFY 2DROP DROP
witness: ...
Where [TOALTSTACK]*N is the TOALTSTACK opcode repeated N times.
This moves arg1 through argN to the alt-stack in reverse order, such that arg1 is on the top of the alt-stack when execution of policyScript begins.
The policyScript would also have to be modified to fetch its arguments from the alt-stack, of course.
If the total set of policy scripts includes scripts that take a varying number of parameters, that too can be supported, within reasonable limits.
The following redeem script allows between 1 and 3 witness arguments in addition to the policy script and Merkle proof:
witness: ... // N is between 1 and 3
redeemScript: DEPTH TOALTSTACK // Save number of witness elements to alt-stack
TOALTSTACK // Save 1st element (required) to alt-stack
DEPTH 2 SUB // Calculate number of optional elements, ignoring policyScript and proof
DUP IF SWAP TOALTSTACK 1SUB ENDIF // Save 2nd element (optional) to alt-stack, if it is present
IF TOALTSTACK ENDIF // Save 3rd element (optional) to alt-stack, if it is present; consume counter
2 MERKLEBRANCHVERIFY 2DROP DROP
alt-stack: ...
Because the number of witness elements is pushed onto the alt-stack, this enables policy scripts to verify the number of arguments passed, even though the size of the alt-stack is not usually accessible to script.
The following policy script for use with the above redeem script will only accept 2 witness elements on the alt-stack, preventing witness malleability:
policyScript: FROMALTSTACK ...check arg1... FROMALTSTACK ...check&consume arg2/arg1&2... FROMALTSTACK 4 EQUAL
The number 4 is expected as that includes the policyScript and proof.
The verbosity of this example can be prevented by using a uniform number of witness elements as parameters for all policy subscripts, eliminating the conditionals and stack size counts.
Future script version upgrades should also consider relaxing CLEANSTACK rules to allow direct pass-through of arguments from the witness/redeem script to the policy script on the main stack.
===Comparison with BIP114===
BIP114 (Merkelized Abstract Syntax Tree)[5] specifies an explicit MAST scheme activated by BIP141 script versioning[2].
Unlike BIP114, the scheme proposed by this BIP in conjunction with BIP116 (MERKLEBRANCHVERIFY)[3] implicitly enables MAST constructs using script itself to validate membership of the policy script in the MAST.
This has the advantage of requiring vastly fewer consensus code changes, as well as potentially enabling future script-based innovation without requiring any further consensus code changes at all, as the MAST scheme itself is programmable.
Furthermore, by adding MERKLEBRANCHVERIFY and tail-call semantics to all script using the NOP-expansion space, BIP141 style script versioning is not required.
This removes a potentially significant hurdle to deployment by making this feature not dependent on resolving outstanding issues over address formats, how script version upgrades should be deployed, and consensus over what other features might go into a v1 upgrade.
==Implementation==
An implementation of this BIP, including both consensus code changes and tests are available at the following Github repository:
[https://github.com/maaku/bitcoin/tree/tail-call-semantics]
==Deployment==
This BIP will be deployed by BIP8 (Version bits with lock-in by height)[9] with the name "tailcall" and using bit 3.
For Bitcoin mainnet, the BIP8 startheight will be at height M to be determined and BIP8 timeout activation will occur on height M + 50,400 blocks.
For Bitcoin testnet, the BIP8 startheight will be at height T to be determined and BIP8 timeout activation will occur on height T + 50,400 blocks.
We note that CLEANSTACK means that transactions which use this feature are already considered non-standard by the rules of the network, making deployment easier than was the case with, for example, with BIP68 (Relative lock-time using consensus-enforced sequence numbers)[6].
==Compatibility==
The v0 segwit rules prohibit leaving anything on the stack, so for v0 parameters have to be passed on the alt stack for compatibility reasons.
==References==
[1] [https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki BIP16: Pay to Script Hash]
[2] [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141: Segregated Witness (Consensus Layer)]
[3] [https://github.com/bitcoin/bips/blob/master/bip-0116.mediawiki BIP116: MERKLEBRANCHVERIFY]
[4] "[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-September/015028.html An explanation and justification of the tail-call and MBV approach to MAST]", Mark Friedenbach, Bitcoin Development Mailing List, 20 September 2017.
[5] [https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki BIP114: Merkelized Abstract Syntax Tree]
[6] [https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP68: Relative lock-time using consensus-enforced sequence numbers]
[9] [https://github.com/bitcoin/bips/blob/master/bip-0008.mediawiki BIP8: Version bits with lock-in by height]
================================================
FILE: bip-0118.mediawiki
================================================
BIP: 118
Layer: Consensus (soft fork)
Title: SIGHASH_ANYPREVOUT for Taproot Scripts
Authors: Christian Decker
Anthony Towns
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0118
Status: Draft
Type: Specification
Assigned: 2017-02-28
License: BSD-3-Clause
Requires: 340, 341, 342
== Introduction ==
=== Abstract ===
This BIP describes a new type of public key for tapscript ([[bip-0342.mediawiki|BIP 342]]) transactions.
It allows signatures for these public keys to not commit to the exact UTXO being spent.
This enables dynamic binding of transactions to different UTXOs, provided they have compatible scripts.
=== Copyright ===
This document is licensed under the 3-clause BSD license.
=== Motivation ===
Off-chain protocols make use of transactions that are not yet broadcast to the Bitcoin network in order to renegotiate the final state that should be settled on-chain.
In a number of cases it is desirable to respond to a given transaction being seen on-chain with a predetermined reaction in the form of another transaction.
Often the same reaction is desired for a variety of different transactions that may be seen on-chain, but because the input signatures in the response transaction commit to the exact transaction that is being reacted to, this means a new signature must be created for every possible transaction one wishes to be able to react to.
This proposal introduces a new public key type'''Why a new public key type?'''
New public key types for tapscript can be introduced in a soft fork by specifying new rules for ''unknown public key types'' as specified in [[bip-0342.mediawiki|BIP 342]], as this only requires adding restrictions to the pre-existing signature opcodes.
Possible alternative approaches would be to define new script opcodes, to use a different taproot leaf version, or to use a different set of SegWit outputs than those specified by [[bip-0341.mediawiki|BIP 341]]; however all of these approaches are more complicated, and are better reserved for other upgrades where the additional flexibility is actually needed.
In this case, we specify a new transaction digest, but retain the same elliptic curve and signature algorithm (ie, secp256k1 and [[bip-0340.mediawiki|BIP 340]]).
that modifies the behavior of the transaction digest algorithm used in the signature creation and verification, by excluding the commitment to the previous output (and, optionally, the witness script'''Why (and why not) commit to the witness script?'''
The [https://blockstream.com/eltoo.pdf eltoo] paper provides an example of why committing to the witness script is not always appropriate.
It uses script and the transaction nLockTime to make signatures asymmetric, so that a transaction with an earlier signature can be spent by a transaction with a later signature, but a transaction with a later signature cannot be spent by a transaction with an earlier signature.
As a result, a single signature for a third, even later transaction must be able to spend both the prior transactions, even though they have a different tapscript.
On the other hand, these cases also provide a good reason to have the option to commit to the script: because each transaction has a new script, committing to the script allows you to produce a signature that applies to precisely one of these transactions.
In the eltoo case, this allows you to have a signature for an update transaction that can be applied to any prior update, and a signature for a settlement transaction that applies only to the corresponding update transaction, while using the same key for both, which in turn allows for a more compact script.
and value '''Why (and why not) commit to the input value?'''
Committing to the input value may provide additional safety that a signature can't be maliciously reused to claim funds that the signer does not intend to spend, so by default it seems sensible to commit to it. However, doing so prevents being able to use a single signature to consolidate a group of UTXOs with the same spending condition into a single UTXO which may be useful for some protocols, such as the proposal for [https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-January/002448.html layered commitments with eltoo].).
Removing this commitment allows dynamic rebinding of a signed transaction to another previous output that requires authorisation by the same key.
The dynamic rebinding is opt-in due to using a separate public key type, and the breadth of transactions the signature can be rebound to can be further restricted by using different keys, committing to the script being spent in the signature, using different amounts between UTXOs, using different nSequence values in the spending transaction, or using the codeseparator opcode to commit to the position in the script.
== Specification ==
This BIP modifies the behaviour of the [[bip-0342.mediawiki|BIP 342]] signature opcodes'''What about key path spends?'''
This proposal only supports ANYPREVOUT signatures via script path spends, and does not support ANYPREVOUT signatures for key path spends.
This is for two reasons: first, not supporting key path spends allows this proposal to be independent of the core changes included in [[bip-0341.mediawiki|BIP 341]] and [[bip-0342.mediawiki|BIP 342]]; second, it allows addresses to opt-in or opt-out of ANYPREVOUT support while remaining indistinguishable prior to being spent.
(CHECKSIG, CHECKSIGVERIFY, and CHECKSIGADD) for public keys that have a length of 33 bytes and a first byte of 0x01 or the public key which is precisely the single byte vector 0x01'''Use of 0x01 public key type'''
Because OP_0 leaves an empty vector on the stack it would not satisfy [[bip-0342.mediawiki|BIP 342]]'s rules for unknown public key types. As such, it is convenient to use one of OP_1..OP_16 or OP_1NEGATE as a way to reference the taproot internal key.
To keep things as simple as possible, we use the first of these, and add the same byte as a prefix to allow ANYPREVOUT signatures for explicitly specified keys.
.
These keys are termed '''BIP 118 public keys'''.
==== Rules for signature opcodes ====
The [[bip-0342.mediawiki|BIP 342]] rules for signature opcodes are modified by removing keys with the first byte 0x01 and length of either 1-byte or 33-bytes from the list of unknown public key types, and adding the following rule prior to the handling of unknown public key types:
* If the public key is the single byte 0x01, or if the public key is 33 bytes and the first byte of the public key is 0x01, it is considered to be a BIP 118 public key:
** If the signature is not the empty vector, the signature is validated according to the [[bip-0341.mediawiki|BIP 341]] signing validation rules with the public key, allowable hash_type values, and transaction digest modified as defined below.
==== Public key ====
To convert the 1-byte BIP 118 public key for use with [[bip-0340.mediawiki|BIP 340]], use the 32-byte taproot internal key, p, as defined in [[bip-0341.mediawiki|BIP 341]].
To convert a 33-byte BIP 118 public key for use with [[bip-0340.mediawiki|BIP 340]], remove the 0x01 prefix and use the remaining 32 bytes.
==== Signature message ====
We define the functions ''Msg118(hash_type)'' and ''Ext118(hash_type)'' which compute the message being signed as a byte array.
The parameter ''hash_type'' is an 8-bit unsigned value, reusing values defined in [[bip-0341.mediawiki|BIP 341]], with the addition that the values 0x41, 0x42, 0x43, 0xc1, 0xc2, and 0xc3 are also valid for BIP 118 public keys.
We define the following constants using bits 6 and 7 of hash_type:
* SIGHASH_ANYPREVOUT = 0x40
* SIGHASH_ANYPREVOUTANYSCRIPT = 0xc0
The following restrictions apply and cause validation failure if violated:
* Using any undefined ''hash_type'' (not ''0x00'', ''0x01'', ''0x02'', ''0x03'', ''0x41'', ''0x42'', ''0x43'', ''0x81'', ''0x82'', ''0x83'', ''0xc1'', ''0xc2'', or ''0xc3'').
* Using SIGHASH_SINGLE without a "corresponding output" (an output with the same index as the input being verified).
If these restrictions are not violated, ''Msg118(hash_type)'' evaluates as follows.
If ''hash_type & 0x40 == 0'', then ''Msg118(hash_type) = SigMsg(hash_type, 1)'', where ''SigMsg'' is as defined in [[bip-0341.mediawiki|BIP 341]].
If ''hash_type & 0x40 != 0'', then ''Msg118(hash_type)'' is the concatenation of the following data, in order (with byte size of each item listed in parentheses). Numerical values in 2, 4, or 8-byte items are encoded in little-endian.
* Control:
** ''hash_type'' (1).
* Transaction data:
** ''nVersion'' (4): the ''nVersion'' of the transaction.
** ''nLockTime'' (4): the ''nLockTime'' of the transaction.
** If ''hash_type & 3'' does not equal SIGHASH_NONE or SIGHASH_SINGLE:
*** ''sha_outputs'' (32): the SHA256 of the serialization of all outputs in CTxOut format.
* Data about this input:
** ''spend_type'' (1): equal to 2 if no annex is present, or 3 otherwise (the original witness stack has two or more witness elements, and the first byte of the last element is ''0x50'')
** If ''hash_type & 0xc0'' is SIGHASH_ANYPREVOUT:
*** ''amount'' (8): value of the previous output spent by this input.
*** ''scriptPubKey'' (35): ''scriptPubKey'' of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
** ''nSequence'' (4): ''nSequence'' of this input.
** If an annex is present (the lowest bit of ''spend_type'' is set):
*** ''sha_annex'' (32): the SHA256 of ''(compact_size(size of annex) || annex)'', where ''annex'' includes the mandatory ''0x50'' prefix.
* Data about this output:
** If ''hash_type & 3'' equals SIGHASH_SINGLE:
*** ''sha_single_output'' (32): the SHA256 of the corresponding output in CTxOut format.
Similarly, ''Ext118(hash_type)'' evaluates to the concatenation of the following data, in order:
* Extension:
** If ''hash_type & 0xc0'' is not SIGHASH_ANYPREVOUTANYSCRIPT:
*** ''tapleaf_hash'' (32): the tapleaf hash as defined in [[bip-0341.mediawiki|BIP 341]]
** ''key_version'' (1): a constant value ''0x01'' representing that this is a signature for a BIP 118 public key.
** ''codesep_pos'' (4): the opcode position of the last executed OP_CODESEPARATOR before the currently executed signature opcode, with the value in little endian (or ''0xffffffff'' if none executed). The first opcode in a script has a position of 0. A multi-byte push opcode is counted as one opcode, regardless of the size of data being pushed.
To verify a signature ''sig'' for a BIP 118 public key ''p'':
* If the ''sig'' is 64 bytes long, return ''Verify(p, hashTapSigHash(0x00 || Msg118(0x00) || Ext118(0x00)), sig)''
* If the ''sig'' is 65 bytes long, return ''sig[64] ≠ 0x00 and Verify(p, hashTapSighash(0x00 || Msg118(sig[64]) || Ext118(sig[64])), sig[0:64])''.
* Otherwise, fail.
''Verify'' is as defined in [[bip-0340.mediawiki|BIP 340]].
The key differences from [[bip-0342.mediawiki|BIP 342]] signature verification are:
* In all cases, key_version is set to the constant value 0x01 instead of 0x00.'''Why change key_version?''' Changing key_version ensures that if the same private key is used to generate both a [[bip-0342.mediawiki|BIP 342]] key and a BIP 118 public key, that a signature for the [[bip-0342.mediawiki|BIP 342]] key is not also valid for the BIP 118 public key (and vice-versa).
* If SIGHASH_ANYPREVOUT is set, the digest is calculated as if SIGHASH_ANYONECANPAY was set, except outpoint is not included in the digest.
* If SIGHASH_ANYPREVOUTANYSCRIPT is set, the digest is calculated as if SIGHASH_ANYONECANPAY was set, except outpoint, amount, scriptPubKey and tapleaf_hash are not included in the digest.
== Security ==
==== Signature replay ====
By design, SIGHASH_ANYPREVOUT and SIGHASH_ANYPREVOUTANYSCRIPT introduce additional potential for signature replay (that is they allow the same signature to be reused on a different transaction) when compared to SIGHASH_ALL and SIGHASH_ANYONECANPAY signatures.
Both SIGHASH_ALL and SIGHASH_ANYONECANPAY signatures prevent signature replay by committing to one or more inputs, so replay of the signature is only possible if the same input can be spent multiple times, which is not possible on the Bitcoin blockchain (due to enforcement of [[bip-0030.mediawiki|BIP 30]]).
With SIGHASH_ANYPREVOUT signature replay is possible for different UTXOs with the same scriptPubKey and the same value, while with SIGHASH_ANYPREVOUTANYSCRIPT signature replay is possible for any UTXOs that reuse the same BIP 118 public key in one of their potential scripts.
As a consequence, implementers MUST ensure that BIP 118 public keys are only reused when signature replay cannot cause loss of funds (eg due to other features of the protocol or other constraints on the transaction), or when such a loss of funds is acceptable.
==== Malleability ====
Use of SIGHASH_ANYPREVOUT or SIGHASH_ANYPREVOUTANYSCRIPT may introduce additional malleability vectors.
In particular, a transaction authenticated using only ANYPREVOUT signatures is malleable to anyone able to provide an alternate input satisfied by the signature -- an input changed in this way would produce a new, valid transaction paying the same recipient, but with a different txid.
Depending on the changes to the inputs, this might conflict with the original transaction (if some inputs remain shared) or might result in a double-payment to the recipient (if they do not).
Further, for a chain of transactions using the same scriptPubKey and value, and only authenticated via ANYPREVOUT signatures (as envisioned in eltoo for failure cases), it may be possible for any third party to malleate the transactions (and their txids) without having access to any of the private keys, particularly by omitting intermediate transactions.
This form of malleation can be dealt with by the child transactions also using ANYPREVOUT signatures -- when a parent transaction is malleated, its children can be adjusted to reference the new txid as the input and the ANYPREVOUT signatures remain valid.
However child transactions that are authorised by a SIGHASH_ALL or SIGHASH_ANYONECANPAY signature will need new signatures if their inputs are malleated in this way.
This risk may be mitigated somewhat by using [[bip-0068.mediawiki|BIP 68]]/[[bip-0112.mediawiki|BIP 112]] relative time locks before spending a UTXO that had been authorised via an ANYPREVOUT signature with SIGHASH_ALL or SIGHASH_ANYONECANPAY: a relative timelock can ensure that the inputs have enough confirmations that they can only be replaced in the event of a large block reorg.
Note that this approach has drawbacks: relative timelocks prevent fee-bumping via child-pays-for-parent, and have the obvious drawback of making the funds temporarily unusable until the timelock expires.
==== Privacy considerations ====
It is expected that ANYPREVOUT signatures will only be rarely used in practice.
Protocol and wallet designers should aim to have their transactions use Taproot key path spends whenever possible, both for efficiency reasons due to the lower transaction weight, but also for privacy reasons to avoid third parties being able to distinguish their transactions from those of other protocols.
Transactions that do use ANYPREVOUT signatures will therefore reveal information about the transaction, potentially including that cooperation was impossible, or what protocol or software was used (due to the details of the script).
In order to maximise privacy, it is therefore recommended that protocol designers only use BIP 118 public keys in scripts that will be spent using at least one ANYPREVOUT signature, and either use key path spends or alternate scripts in the taproot merkle tree for any spends that can be authorised without ANYPREVOUT signatures.
Following this recommendation may require additional script branches, which may mean disregarding this recommendation may result in a better tradeoff between cost and privacy in some circumstances.
== Rationale ==
== Deployment ==
TODO
This may be deployed as a soft-fork either concurrent with, or subsequent to the deployment of [[bip-0340.mediawiki|BIP 340]], [[bip-0341.mediawiki|BIP 341]] and [[bip-0342.mediawiki|BIP 342]].
== Backwards compatibility ==
As a soft fork, older software will continue to operate without modification.
Nodes that have not upgraded to support [[bip-0341.mediawiki|BIP 341]] will see all taproot witness programs as anyone-can-spend scripts, and nodes that have upgraded to support [[bip-0341.mediawiki|BIP 341]] and [[bip-0342.mediawiki|BIP 342]] but not BIP 118 will simply treat any non-empty signature against a BIP 118 public key as valid.
As such, nodes are strongly encourage to upgrade in order to fully validate signatures for the new public key type.
Non-upgraded wallets can receive and send bitcoin from non-upgraded and upgraded wallets using SegWit version 0 programs, traditional pay-to-pubkey-hash, etc.
Depending on the implementation, non-upgraded wallets may be able to send to SegWit version 1 programs if they support sending to [[bip-0350.mediawiki|BIP350]] Bech32m addresses and do not prevent the transaction from being broadcast due to considering the outputs non-standard.
== Revisions ==
Apart from being based on Taproot rather than SegWit v0, the main differences to prior revisions of this BIP are:
* The sighash flag has been renamed from "NOINPUT" to "ANYPREVOUT" to reflect that while any prevout may potentially be used with the signature, some aspects of the input are still committed to, namely the input nSequence value, and (optionally) the spending conditions and amount.
* Previously NOINPUT would have worked for direct public key spends (assuming deployment was fleshed out in a way similar to BIP 141 P2WPKH and P2WSH), however this proposal only applies to signatures via tapscript, and not direct key path spends. This means that addresses must opt-in to the ability to be spent by a SIGHASH_ANYPREVOUT or SIGHASH_ANYPREVOUTANYSCRIPT signature by including an appropriate tapscript path when the address is created.
* NOINPUT signatures do not commit to the output's spending conditions either via scriptPubKey or the redeem/witness script. This behaviour is preserved when SIGHASH_ANYPREVOUTANYSCRIPT is used, but when SIGHASH_ANYPREVOUT is used, the signature now commits to scriptPubKey and the tapscript.
* NOINPUT signatures did commit to the input's amount. This behaviour is preserved when SIGHASH_ANYPREVOUT is used, but not when SIGHASH_ANYPREVOUTANYSCRIPT is used.
* OP_CODESEPARATOR in script will affect both SIGHASH_ANYPREVOUT and SIGHASH_ANYPREVOUTANYSCRIPT signatures, whereas it would not have in the previous draft.
== Acknowledgements ==
The SIGHASH_NOINPUT flag was first proposed by Joseph Poon in [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-February/012460.html February 2016], after being mentioned in the original [http://lightning.network/lightning-network-paper.pdf Lightning paper] by Joseph Poon and Thaddeus Dryja.
This document is the result of discussions with many people and had direct input from Greg Maxwell, Jonas Nick, Pieter Wuille and others.
================================================
FILE: bip-0119/simulation.py
================================================
#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as plt
PHASES = 15
PHASE_LENGTH = 144
SAMPLES = PHASE_LENGTH * PHASES
AVG_TX = 235
COMPRESSED_NODE_SIZE = 4 + 1 + 1 + 4 + 32 + 4 + 4 + 8 + 8 + 34 + 34 + 33 + 32 + 34
print(COMPRESSED_NODE_SIZE)
MAX_BLOCK_SIZE = 1e6
AVG_INTERVAL = 10*60
TXNS_PER_SEC = 0.5*MAX_BLOCK_SIZE/AVG_TX/AVG_INTERVAL
MAX_MEMPOOL = MAX_BLOCK_SIZE * 100
COMPRESSIBLE = 0.05
def get_rate(phase):
if phase > PHASES/3:
return 1.25**(2*PHASES/3 - phase) *TXNS_PER_SEC
else:
return 1.25**(phase)*TXNS_PER_SEC
def normal():
np.random.seed(0)
print("Max Txns Per Sec %f"%TXNS_PER_SEC)
backlog = 0
results_unconfirmed = [0]*SAMPLES
total_time = [0]*SAMPLES
for phase in range(PHASES):
for i in range(PHASE_LENGTH*phase, PHASE_LENGTH*(1+phase)):
block_time = np.random.exponential(AVG_INTERVAL)
total_time[i] = block_time
# Equivalent to the sum of one poisson per block time
# I.E., \sum_1_n Pois(a) = Pois(a*n)
txns = np.random.poisson(get_rate(phase)* block_time)
weight = txns*AVG_TX + backlog
if weight > MAX_BLOCK_SIZE:
backlog = weight - MAX_BLOCK_SIZE
else:
backlog = 0
results_unconfirmed[i] = backlog/AVG_TX
return results_unconfirmed, np.cumsum(total_time)/(60*60*24.0)
def compressed(rate_multiplier = 1):
np.random.seed(0)
print("Max Txns Per Sec %f"%TXNS_PER_SEC)
backlog = 0
secondary_backlog = 0
results = [0]*SAMPLES
results_lo_priority = [0]*SAMPLES
results_confirmed = [0]*SAMPLES
results_unconfirmed = [0]*SAMPLES
results_yet_to_spend = [0]*SAMPLES
total_time = [0]*(SAMPLES)
for phase in range(PHASES):
for i in range(PHASE_LENGTH*phase, PHASE_LENGTH*(1+phase)):
block_time = np.random.exponential(AVG_INTERVAL)
total_time[i] = block_time
txns = np.random.poisson(rate_multiplier*get_rate(phase)*block_time)
postponed = txns * COMPRESSIBLE
weight = (txns-postponed)*AVG_TX + backlog
secondary_backlog += postponed*133 + postponed*34 # Total extra work
if weight > MAX_BLOCK_SIZE:
results_confirmed[i] += MAX_BLOCK_SIZE - AVG_TX
backlog = weight - MAX_BLOCK_SIZE
else:
space = MAX_BLOCK_SIZE - weight
secondary_backlog = max(secondary_backlog-space, 0)
backlog = 0
results_unconfirmed[i] = float(backlog)/AVG_TX
results_yet_to_spend[i] = secondary_backlog/2/AVG_TX
return results_unconfirmed, results_yet_to_spend, np.cumsum(total_time)/(60*60*24.0)
DAYS = np.array(range(SAMPLES))/144
def make_patch_spines_invisible(ax):
ax.set_frame_on(True)
ax.patch.set_visible(False)
for sp in ax.spines.values():
sp.set_visible(False)
if __name__ == "__main__":
normal_txs, blocktimes_n = normal()
compressed_txs, unspendable, blocktimes_c1 = compressed()
compressed_txs2, unspendable2, blocktimes_c2 = compressed(2)
fig, host = plt.subplots()
host.set_title("Transaction Compression Performance with %d%% Adoption During Spike"%(100*COMPRESSIBLE))
fig.subplots_adjust(right=0.75)
par1 = host.twinx()
par2 = host.twinx()
par3 = host.twinx()
par2.spines["right"].set_position(("axes", 1.2))
make_patch_spines_invisible(par2)
par2.spines["right"].set_visible(True)
par3.spines["right"].set_position(("axes", 1.4))
make_patch_spines_invisible(par3)
par3.spines["right"].set_visible(True)
host.set_xlabel("Block Days")
host.set_ylabel("Transactions per Second")
p5, = host.plot(range(PHASES), [get_rate(p) for p in range(PHASES)], "k-", label="Transactions Per Second (1x Rate)")
p6, = host.plot(range(PHASES), [2*get_rate(p) for p in range(PHASES)], "k:", label="Transactions Per Second (2x Rate)")
host.yaxis.label.set_color(p5.get_color())
par2.set_ylabel("Unconfirmed Transactions")
#p1, = par2.plot(DAYS, (-np.array(compressed_txs) + np.array(normal_txs)), "b-.", label = "Mempool Delta")
p1, = par2.plot(blocktimes_n, normal_txs, "g", label="Mempool without Congestion Control")
p2, = par2.plot(blocktimes_c1, compressed_txs,"y", label="Mempool with Congestion Control (1x Rate)")
p3, = par2.plot(blocktimes_c2, compressed_txs2,"m", label="Mempool with Congestion Control (2x Rate)")
p_full_block, = par2.plot([DAYS[0], DAYS[-1]], [MAX_BLOCK_SIZE/AVG_TX]*2, "b.-", label="Maximum Average Transactions Per Block")
par2.yaxis.label.set_color(p2.get_color())
par1.set_ylabel("Confirmed but Pending Transactions")
p4, = par1.plot(blocktimes_c1, unspendable2, "c", label="Congestion Control Pending (2x Rate)")
p4, = par1.plot(blocktimes_c2, unspendable, "r", label="Congestion Control Pending (1x Rate)")
par1.yaxis.label.set_color(p4.get_color())
lines = [p1, p2, p3, p4, p5, p6, p_full_block]
host.legend(lines, [l.get_label() for l in lines])
plt.show()
================================================
FILE: bip-0119/vectors/ctvhash.json
================================================
[
"{\"hex_tx\":string (hex tx), \"spend_index\":[number], \"result\": [string (hex hash)]}",
{
"desc": {
"Inputs": 3,
"Outputs": 1,
"Witness": true,
"Version": -2079506940,
"scriptSigs": true
},
"hex_tx": "043e0d840001034f8f827b00000000000000000000000000000000000000000000000000000000f54c98ade5a10d6c8a3013fd077ed18e1d7eba9119ee318b83220c2521e1d55ff06a494bb210a1c73ef3df958da16481cec61f80281e9ab392ee6701ffc205db6393497681d92282aa2f55ec5f9dba411b5787353b36c1b33afc884249038954c7d6dcc55baf885767d4800c62314f6021cf59d4f88845d960aeebd5fb84cfe393939893a847b13753d9f3ecb8dbc264b24b64020f4897efebfeac68dd6e13b127b132859d792d2b293223fd7b591d03cb9b20735f18c0085542f1a4d769c1c874e9eac2d2e280fa3d9e7b03dc62e64c9fc80f0b09506b19166e84ab7600744cdfa6bf25f5df671725adb23887aa3e8e6d9200000000000000000000000000000000000000000000000000000000119ccb06e028dc54e45a5bb28199c854b8fd1b1797c2d7aefdb5823fc1b316a2a88e9b670ff7f282cb22d26adc79c464a50e3ce287739ec14d011a999dd66553d08d51fc9eba2ab0f8525bc6cf98cc64f09e7d7415ba7dc98701e3b6cd94342d872bea86dcfec4d14ada25febd8d2387ccef203bc6fc202c5b38c09b3525c6e68b1fb9e2284ffa3374777d686ad6c68c6ec25560645b739e8d338a3b6ff314e80698e180b836a315f90a0ed2e30260bea7e540f8a00f4d051e95f27c7cfef998002ba0cba0a725ad33f6d54aff13be272441af523dc5959980ca6c8caaeb518c46d07b0997c33d24827f9af222000000000000000000000000000000000000000000000000000000007263de59fd7c0115337ebfb53cb1dcc1e5ae6f5303ef40c4a9e71e3c819346ad09bf2ab51de119d11f878134d7715b880ec54dd5c7c5cbf2bc3b9db9a980432807aa4de4072064e0b8315010bb61cb85cf2836cd649d86f88170d747ecfc3bfbc4051aeaa453de0f9d90f33932588a03c920d523fbcdea58340733e207817a8a500d642e759a7181a666e8099592548ece7535fb14d11f8a6e4dba55780773387c464502794bbdf1bbaaa79efda2e024002357f2a50ef2a31120c4382be745debf40e0fc0894172a9d51ede424561b88615518c9c9c7b1bc7b8085cd0907e19d6fbcb85e3569c9349d95dca881100d390c321721809e8bbfabcb4c25b29bc4777c4d79c39aa9849c53b318894ad875708d8e6689dd6bc2f2aef433003ab8d0755387f56bf73f1e74980ff2d4eccddd0a00bb9a71b343137b69f7c51cb66d8e33cd70573f65f9157043f5267b60e64370e0cf33ab8d40e6968192cf3da58790dda9824def3b8d56d7385068ac8bfafc76f06e46cccb80852a59439a5f0ed8ffb02aaff01e4556ea01ba56592ae4e4ec33c86d2dbea9c83550cb9357d7b1aa67a1067b4c163e39202438ec52087f4195c1fc90f543fe41c630bf25ec79d6084a954ac70c9558443ded85901746e35226564b22ecde4e23da0905e38dddc4b34186e895fa5b743eef69ecee8513ebd2f821bb89c2f9ee7f0b82bd0d42f40bd9671dc163a5eb53a403831f9df6ca6245cf0ef03708fb889e4362dc5ee3b504a8e01136cfc3d3bbc44eede5e4abd18fca8315d27a746a749f5fec46254cea659c53ea71f99ed1e9744192d1743cdf24d99c59a671006a4474077ad6020db169be53eec1511c5157517253fdc901257a6f391c70dfed3d0a26bf3155ead063468639825752a4f386f43cc94223db499358afa7fb21d27ef72bbd73be1c9eb528962c4697ec9cbffd44ca6d2879dbf84de9dae29261c37a2ce87813ce34a5de387afd740d29727b1cbf0cbdebf4cacec0cc0c73c28d9f120bc31b243629fc850b55cbc704f16d7505c9b83aa079cb644c69cf6ea01b9c92dea2a624315471922626e10c290976a26247c0f733d49225b91e38074075bea6b2cfe14ba60a608c15351701b71c81bca089f2da62c5fb07ebb261682f2be982b2f699aa27df152d8fd260287e9bedd5b848186e38c3fd1895cc1e53d907bb75ab3fda26202fab8c7a8d0fb3d4445fc3b6f90b2a80010cd3c2ae18e55736e460278b9ed477e209939b096a2cb3225535666616c773e07293c100afb5ce982e933fd2d95a607968e1dec26a4b2e5e8e3e2b40cbec9b15c16da81f72d6bd4569e8e223a4351ec112d52cfe0a6e51e8ab660552195b507a648a42ce70e635437d52c8bda21d914d7fc0f2875f08af1f8803fa0a9a48484ae311361d2fa5bda2b3f689559bc2fb1c577f5acbfa7effed855ae0bf908a7e9269dff51070aa8a97e4954505abcdcebfc6ae1c1bc68dd593021777e9ea573fd79334e85c582ea900e1570337f091bdbb555c19b89262aba2b7429e24ca04c177059ba8dd468375f2a12e99937a22cb131ebb508e81ede4b807789c4318b8229b90a01a4443d74e6fc4ae30d04f7ea1c2bdbb98c2a83b316d56a093c790af9ff25ee6be833448dd05e96ed38e7b3fbfc7c2409c99f36d81e40196180e2360ad3a0ef439a0a6bed0b92e93cca398ca4f95906ba6d30b33e81faeb3c405a3247f488dbc86eca14e25ddcc4367f4170044fbc5e329f49a91410185475164afb2bc537500970cf1041b09d590f12613630bba8efacde59e3c8aaecd5bc5626a7bf0b5abf4b507b3659b6df2bad43d7a2ecdc2500b375c155aae9c62a8d8af503a927d859a6dc2ffdca19cbe8872c63b1083cf5b11fb957da72f631694d0dccf21820247943a90b18eb2258af5c6aed6d19bf82542f524c8066501698f5709473824d07f61",
"spend_index": [
0,
1,
3116999548,
4294967295
],
"result": [
"2d28d0672f1d46cb3e86abd7e682d2d3e9961e6c9237157f47d39f0a694bb694",
"12f7ab0a282fb9e29c9fd2ada21f950f492bfd5778a94202398c13ae6e97f0b4",
"0ee9cc212182845d4c32ba6b3ba8859800d5cf423c58fb1444feaf21aa9cf81c",
"da78ece7c0888725532355018961f58ad471f242e29a60adf84c55007fad608f"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 4,
"Witness": true,
"Version": -1368569235,
"scriptSigs": false
},
"hex_tx": "6d4a6dae00010a916a4b8200000000000000000000000000000000000000000000000000000000678ccb660063c1aa74901ac96e00000000000000000000000000000000000000000000000000000000333575f100deed4cd21c61531e000000000000000000000000000000000000000000000000000000002ca78054001064ed3dec34dfc70000000000000000000000000000000000000000000000000000000069eb33a500b63bd6b3a8649f6e00000000000000000000000000000000000000000000000000000000bdef058800d2e45813892f854400000000000000000000000000000000000000000000000000000000dfa70a4b0090fdb4507528cb0a00000000000000000000000000000000000000000000000000000000265a129d009caebc792f12408d00000000000000000000000000000000000000000000000000000000a163d9dd0096eb42406cc5468600000000000000000000000000000000000000000000000000000000980b4ad1008b6e087dfd46e3e60000000000000000000000000000000000000000000000000000000008d612a30061f404f0047d5a85efcd513431c8fdc3e16e04bbda3ed597cba1417cd04394a876b5d008a88e54f7b6aa91ff086ba4ba2fc76e3cb8ff373f737bba9581678944d574c399a6627e2cb10a01bb88baeb4cafb52ca8f14c1c5355497520916ff57f78e173271ed1d731e5ae17e4776481955881d03c183e0737dba812521364159af700d062aa092436e38f6e6994a8b50535a2c1c0513b690c0f1bfa14612aedb1b7b4d90f1b4d4f2909633a36e4a245f6cfba0e64fbf262a96d2721e1d4417b4028b06c200887bba784d6f410880e64c1819432f44256d93e4198b7d62b6cc80fda87347ebba272e3d2267f39efa7268ac3e4f0cd8b077bf9d4831072b9cf1fd6191e6c430422c3225ce247ec07f94fb58d365ff4e59ac353c5cc9ca9be7c01475c6e6509298134e3fcded875ec17bc35c40c6e8b5c6f1ebda9bad1d752b655d9f9238312e5c01f59cf14f45bdfed18c3ae2254635a91405cc42d68f1d7ca68b97ec93d96ed1277baff57951af33a79edd01ac23f47400fa49ea85507bec9a45bf6022e3873d90890eecd1582e17fdf5160ce30eb87baafd169dd4d0f6ea2f9e1b45406620f9c0430a2a513a6011e7cc88557ebc7b2057b4b1dcc55b6edd7a203bb9d8cd9f8019f79b2df2c64410ceefd1a819668d915c1fcc46679dffb772dc3eb55205524f495b6642d311f1bf58024df8400567f61f1debeaeb6b95b612f7e6687e7ae4dc0c3e0df045bd018434ffa4a179bc23c95562daf3e293cdf682381f920d333e61143392021beacb2935789b8d4e86ab2b16d46e0c79c05166ddf0461614204fb01265a5e9cc552812085c68129f7e0663e511f1112588886b30d5b736d3414ea8b7280e5a017473ffa0e6ff88c36902de8672353a8cd464a1b2d67c8d0691d4368b6f5c78a23b8acd08e338a8e73e7f9bfc0f7418f5efcd8bdd924fae94f9f4ef68612144ac53ad0759e0f0d366fb6994d0a8f237236eba419c3afe1176e569bfac7384c03ff056b17702d440a1b0965a753193df5b28f550244e4652bd8f6d9209a3ff027f54c493302dee347e70d3eec95621a223823b5d33f9d59f6fdf66c15ae2ebeb26d26fa265ef3485dc6db2ae40d41da19de962a154baf84962547099ff17ca2e32fd831f65be2c59136394d33d64e75ef4828c7059c0f670769a46a9dfa38bb03f27b15eea1567e1241ac5bfacb5c7737109e1b7dd6f6409b982d2da48a7883ed01601869ae39528755419487c8035b54e66ec9078fa8d655effbd5afbfc067dcab5270ef42a049d32d9af1ef63abde30321a5b56a4e38676ae9a7d02ba11487545ad6829ac5fee5a4c15db77faf50ca1731e85399d4edf189343fec7f0b7549ff6cd94c2df1f048ea84237a5febe51908922d8d5ed87605236e88097fb3e6f5b61735a7a1d899fdff4e4bba1301b0c8008fc550123262c28064e8974ee9ce18f20591c0b5cc9f82481c9e558f44b2b1707ce53ced8cf132686b50bfbe0f3a501f06b37b21c9cd210da0515d73f0d569b610db7fd2e016b6fa063c83c771b81414585f112106d1cbff1c15bbf4f5d01468b9f152a7b04948881699ccfe8b71df6c8841848462f2ba63574b4b82233adb84101a027071d337b73f408f21c333cf80619d033adb11f67c81b4c8364e03072b9cdd06f20fd14e38dc0d5f73ac880ba5f06f0215f67f23c2253dc5d461a438383eee398996d97f1916b0ef6d8ecf027e1aa21827fa0bd8fb04eb0010c98bf673bfacb8a2619b55899f0c86e363e1ed26e43a38ac0941934cd79a0b5521b1338269083b951025b92562b057e738d0c57e6b47cbb120d482bc3b34f1ee93c3de86ea4bf6a01f24f47b7ebac399d4bf3228606dc23695f55a3d99d78e032ee4854e5c3a7d1574c5b56a476ba88a6bbc8263418b5ee790c88da6de6400225763b02f3164c3655ca0c33d5ec1ade6dea61c64a1e40e38d219e870f064c993d806747642572ad2bc5f37ab58edceac35460c7bf50afa9ca8e62c9e8c506635c3301aa9ab70d8c73a955768a56af4e36862d2e908d18057440ea4e9fa7edb1b662a2ccc10b737e59ed3f1f4b8d9445243a685f167ba068153e1d6b865ab827fc01b28cc9b08090dc0f413ad1071760e7740d2251986eccf29c12246dd98171e67b27902a3d02fd58010b63aac9d24630fec45752a1adf2e280c4f7a0697192f128e1ef02f0c546db67f8c45cf55a39a7d103ebdac927574b043a7bb95942267e1a488d60b22f08b32102a7aab4dede478d19cd95a4b5ce911aee03728cbbd9c7666967a86c500ac7c6ff63ff4849e5432bf8de5a695e7ca4d5f1ab2ac09d1cd7c26227194287e0f8f3673cdb852b6d03005c85afcb181fc83a8ec0ed95499be06415c79d69429888a90187e7789f5a860b873abb0f7fef8c47b99e362891451e02eb31a4048ed4aeeebf49603ea7fac87d8134ae718dca06460536a011715ed4b83ae9724aebef0c46bbfdf02ca85ebe1bbdf5f45e58a2e96d514d98ce425726904607e613b16aa3025e1f671f1dd913e60995523035718e7f898bcbb46ee3e90e76b03ad99b61737f1ee2d4c3cf23d5614f767d8a03e4921839f59eabb29ea260684783a2842e6b0d6056429d2b390a697aef776fe8021492db57fcc045e68997524407d6e9b963f8970b5c80cd43a1d0ffc4514da60b26a750639778c902d10e00d8a569c4a8c7008d1388e8b8714c7f827a951dbd9c5a466174f9838651e86cdaa19402c8dc6427d84e73fe41596d6a1d2bba03fd4801e784079ec830a58842a8cb33d32cc56cce22b89ea5dcae7b2e659cdc6c87f6567ebae46e81a5f75ec4495110482b84ce0bdf824dc625c5cf32cc6b28075600d03d48982d75c4755ca3b7fcf9a90f7d8832197e8b96c64158eb3b568bbd48995c7820940e4488f882a8ee842024e91221072dc32917c6da4c03b86bed15fdf2889697ed349649be9b287a1b1e6d5655e7110fb3c98bc417f89eca4c3ca9f3a8891162873298e85ac83ff64adcb9622bbaeddba3bce44855b84c5acd7f72d6be9bc58bd7e9e273385a555019be50dcca5d555170fa041b472af4e9bf7b322178a3e4166b1dd6d81c7cea97788af5615323c128ca9d15dc267dcc41f6db00c8c04c6cfff3f3e8cec109ce77151b206910df0d393671685ea4dd66ca4e20e1b06ae442dc4d4c4c80dd34c3ce214bd4a3e138c82287311366cff1113b9b87f653e00b7757f57dfc011669d691591c3f04c90c9e9757ff568449b89bcce976aeb19b7d0ec42e0c0ff7414910f63f150aaad4de779604069eb6be22287e2dc2161f540608fa3b31728a1220211d253496c399bf61df8691c36728c486e5e867f6cd43262044bdbebababdb8caf50afa7f595ff07b83595de7afeba51fd2a475a419d154e312e5233d5941b45f46fc2dd3df5bc2212cc33c51e2468f5e17d17dfaff014b60024983705b5f9f263055b5ad52fb27b818ec1fbbc1de9d06636eccba8614fd2860250561d19a406b9d3a67ef125cfb6a22c9fb0e61ed3e65a93fefa8edd2fd5801586591b2f2ab61e013400acf71f0e023d17300cc90c1f9259bc8524b2319e77bbba8c4d286a0ffe799c57061f3a36f831e2cd4c5480a5dafa9c209c93d7cb54a56f1b3670ec1eef3de8494c496061c14853566c11e9fa4e77dc3aa029be7a120644ef0394f6cbd581a323b56187769669cb1a5d99bbe08781c95d6eab57a3c6e1d1ca3484b20bf3f67f2b6ef9c6bdba800e3275a469f8e39630366581f2b275b65a2a3643e02142c7a58bc00e60e350f930fe441f443454c5b7da4159195ecc9ea9d90929a74186312877f3b3f8a0eb61037c73f24d7f13fbe2304affcebedc366318b6c1a53f470efdb7cb16c833abf27ba330290ff43209af9eee39081bc576e1715d953ad728297c3c939dab1848763e6df0c72198c8571541b81e4dfea8196bb8f8cd319f80e10e64b61d1541bcd89ca33a6e67517052512906159506f3b012b76d5b4280faa87e5605a175c1b05ab70f91d98eea78f01fdd401e032ea5ebfebe20e81bfd4a6fc2e8f99017f50b310f1310b3b71c70c2537d132a2f6c588db5af8d24ba648ee89fc0553b305f1664f9e480ac4c103665ab51d13f94bcea38d9faebbbd6fa6298a8374448f1e99802499fe7b64d5a0e607ebec52ce1339d073130bc7d68cc0f74c29a8d313ee17d38c467fdb225a1287f9e2c328c8da19a8834809db2ec5438d30df24ba3c3b264858998ba973f016016f117db6982ef3d43d31236ae3bce49a938d43d8cc46e4de548c85cb2bfb33669fd7a9492e62e761861693a7a3aa14cfa3243521f8ca7ae6add2d20be4bef6ce40bb25795b7f53009135a992ebf8563654463e35585fc9c380940f324f9b07f638c54d6d5da77ced9814456adca7fd15665797381580f2aed4bd800942faa64a2a086ea01aca5cc4a139b234ef3837f789d406481f17798521571d5cbf83336d03a4fb054c2556bb423602364006f6f8d59eea0689fd280e29429b7052b4614aaf785e22c70596cdd11403d9a9e9a60f45395c7e4085a515689e37ca942d5a65f872fd3223adf2f7bfd47fce21f280ef44ea71c755dda9f41e730b306b90a1432ead90f9f788177cbdf41db86135171d2b6d8baf8e0a3f019900e19dc9d9668111e3300e1a73aed0a68a25e6d670cba7e1fc6c18e8da346402b732446a381a75c65a0959b1b4fe2d116b801688880a9cc014e0e7b5851610bc49fddca01aea179977b87863ab3ba9004a05a08609278c5bfbfdbe9f6844b439343d46a0cd38b40b4ded6fee8b563a20c25637f7068810e379bd65b704f6e74480d129482f88ce63d9eec54d1f19dd113afd36357ff3d1d989a4992ee5d8c4a25946e8f79b1a80ab76685c568280eed7b6902f66d3e29116ad75c547e8ffe4c5ad03622befb7ead7bf02b5c0f44765d577148fcce0354f60c939aaf4552f352a2981026208ee74c730ea5e03b78756b09aa68e02f60931a2ae5176a0e6eb02726be51b3f286192c11a98617138710d27ce6923bd49e099f18feffc0bed3f1d38474baa4c69bd92561aa4827cfe9796a1f3aad098b4eb8006b02db2ed8fa6dc84eb78a4857cc9f027908d90578eaf1ebda3989c9501c7c098b9ded18ab12fced3473205cc5d1c2b8608bab400423402dd10eacb71e6ce96a0990b34d94a0e035b3fa84b62fc21323a3ff4bbdd6602b694ef45572d4650fd80771eb1bf8621654fc43403fd3a018f67c2e675cf14d60e6276425b877f4c0bb9c057d6004f07431a0e641cbc41b2d77a5304c06ddc39cc995248b366cb79f3c38322b4074ec9bf147d6d1663deb54acf30d9568085f910ac91575901834fb234cb0d8b1579eab248cc5b1172dd8b1872dc8665b07c17f88c37df4f8f67bfe1e4e3c5a0a7259a7a2687319e458de79b8bc377a573b760fdea26b82b1a7ff7e2e89c756d9c7fb29a75367c4c44b8e6444a6ce2f81902a1bf7e2485039d1b2b3810e680e22770953abec970c1ea3eb8244f8b5cf19d23d637b8749c61dd653b34e7e8c7064b5c2d67793c867adf8691543df88c2e96ea08e06fb29a40575ac4b18c8506b08c9608e9e9512e132f093fd12df8910ebced42aae6e768977d7195dc4728b533f35852926671d08b1a68bc6c8abea8b4dd82811bb3d4959363dfa923a5a40c656b0b557afefde201ddfeb04901dd91fa610e4be576555cd592998b4d2e16e64c48acd3ac6db3473ac77625de377c2e1bfb8dcbf8b7b111c13287a84b6b7bf35e2c54b37064fa8c4e03a19beeea55ea95caec8e02a4c73c0344c83664deda81e64b20fb00a602a174031cdd5248db1abbd543ea2240f4e4a4df8c7648cbe45c639ecefbe7c4bb2df223577e63922a7a6bdbd3a6d3908f5cdc412fb455516341d66dca4b4523f82e7f9d3be73ae24b97985e482d6d4e6cb82dcbb362ce064c0dd54a26c42e843625f155f9152f94aa6ba04839323ee78828dbf5e0dfa4d628656c736634f9122c4fad047d0513f7118ce77c959f9eba47b57ccbf2671c6250665f83e915d74ccb7cb6faa028eaecebc21b6bcda7193695592b98abb6ee95e47547da6dca4b9b740d0f4a6a6c95ec7ff2ba481133efd7e2b9b93376f08ec97f40a4045a167695ae1114150cdbff9d3081a08d03f2f0ca0b25435ca28b53266cf94faaf656b4e7fb7db882185c973186743c45064ccda60163e73a8c19aab9ae7d2f9e563ac8fffca64ed9c6277f342a99bdda91efe01c2cb24e6149428b56d322f2f7b31e1c61e581b57afb7acb216627ce137fc8fcd14ec5c8d4be39beeb9dcdcc5087422e0255c29f10870ad9bc8931922a21e5b57e085d3d7f20bed100cdaa22a6af6196892702a6eefcfdd601649dcbca53afb0665b25658b57f988e3fd743ce52ee421f4973ee95becda180c7bf41f7f1b3a0c7a5cfd184478575f7aabb059cbb94a42fbdd5b1b11061b8a442a2f29d1096ea85439d89fc031e3b22d85ed29423632ae4f2b6fa98ac4e4f601d91c487f6c84ca2d660aa157dab73ff31f441e6653e9be98e6c08fd6009a5c7e82f4de916ef3650b7a9456dbb77889763448205f42a7d776c871123b1db50bd73f3d60291b1ef225372e5ef434e256e97b4caf64eef889af73818c30d3b24d5ae5aa15353b4e22de089ea4b560891bc329e12e0aac9e7e2f8fa83971eced1115f4b664f5e80700193c60ed15c07f6267f61e1a07b37ec3072e2282133ced8ddf25e8f865580b9cffa49089014a601bf000adebb5ceb5bcd539f3ad20f9c7ce5b3b1d863d4bd60a5fda1f566c9da7c2196abae8b806d62a01ae6840cfb864487c9f3e58b2c22d21ed292a56fcad7a2c53487fff3faa84ad7d58ffc6b00c60aa50e637d4ea74501aa568b1b2a349eda1d04bff81bb052e1d927bccc3daab9ad18fa77740e936c6575fdf6babdaf7a241114ed4f3d65bfb4fdea7a4f57553963df5a5e066b06e82663e54b58a2e5c8f0ce57e2ba4832139ebfbc70671646332a86e971aa9a9d25dfc89243f41cbdec196b279e1bd669be402c94134a56bece2d3d5e733cbb693ce523ee2ab7207feaee1023c4a11758a2c9a1f901623002b9ffa27b642dc9b6c7ac02c2bda113112e597bef8082c3cf95ea4689d29f1f9e666d75aeadd181f92b6e68119c31bf71310ab8628c5f5cecc32e1f2d760231e1e99660a6ad7b3a8ce6d677ef61161fb9979c3897a21871cb431a7aae519cac807259780068e48917d8f2d2b70b3737311db2333d32ace68822d2bd852cfc81eb5dc356fe2e749fa6635228fd6813997372dfc4cce81c9b847615bf132c3f5d1fcf341128dfd4501c98fa3cbc2537cd4185b53bdf095a83bc17acd63119b6195490014a772c4b1787873696ca6087052284db67c5ec38b9243f7a476acd2f10374724c57c15f193a6cc0ce635d59989ac56172b7bb8efc2d6aa17dca85b2a5690a9f409294b33579ae8ffb506152f3f2f3e7c00955005e4fbfbea1827b6678306cffd56cf3f43ceb0afdeaffc891e5bb7ec6eafe24e2aa5066185820d20cab677bc9b83c5a8f2307d4fbd3ff3a282e457d1c3d6ff041763044318b7721dabd51e43337d37fa3064ac7f564d7ebd23930ad11b38d0d7312a62862f7fc9e0664eaf0f0ab5cea30e55ed52078edb0c722ee7f6d5ec4f3c17503f2a97a498660bb7ea1a0e305fe25492944af4b7d4f7bcef715e714b840b440209650e24ae1302c4a658fa7dea6ca6153ad886444ff54eea7672e9b32a1196e593f0532def46e64f04ba46cacdffb7aa1f27f22a4f30001cbc6c09ac7c4450194df9fa302996d8af546361730744ec2264b884d8b92c8ce254289a2082e182f5199f9e22fc37a23459cf97802ff48448c3c66eda84d4d4583db8946f1d2dca19a5e3177769190174e056a0bef4a3695d4c5a47defcdddf1ba513966b59824d9cc996d123422ffb527eea355cd8be64d0400838229f29f263ed5f31d158b3000e0ea1a41d9d0bb1c83fb36fb3aa3087f3320bda1e78620bc4cd4e7bbadb5a1a79ceed8458b97067be123a9a3545ab4593c9f8a341b0c2cae3c3ce7cf2e451185c45c576203eb157f6f0942a6d18343e0cdf7e99305720026ca36a9f2a4b29246cfc7917bcaf41981b2e6cadf1401c062ef1b4f1f98a9e480a6ce1224cf49181eaeb876726315c2c0cdba03bfc11d091042d47dc2ef5e2fb49c4ab4597ccb65cbf0caaaa6015428f7c223733f2cb7cd7aa8b4c7807341f74e83d796b08a5ba9f2c7e56b51665c452a96f1ba0f7490cdcb248b5e5c85c687b6c5710be23019a8bbbdbb9f451e42b79423657f7669e1e55fcac0ca6ef554d7df76e9ff5429b20dae46ed08b9597daeb049c16b03f095c036b7eae7af530281132a2a3ec12c262ff2f66a261b61cf6400d97bfb413de51aa7bc650840ff0853fef3bbb3fa0aa2481275b7d23e369b3e17263f97d49f7a33caf484ab9629345ddee07c9da56a542ada207d98bd7e7da0f38e9327554ecb0d97fe8eb2d2e6e03047e6a05a5bf9f2ef5fe92a9e086e921f117d2bcc37cd3b3e6e4951f19137d96efd9401a1b86a4c70d612a6e96f2516c5da067c58d0431657cf86213766a7ff003cc932ab129772382f6f6ef8d7191a25ebacbb167a31d229618484276f63069f9f837e910829153d31412bb74be44a246f67cd9054e2725baa93cd362a180da0170b726f7698dcba636acaa61817675444aecedda4bac9cc814cc160ab382768d1a4907c41f632178086bcd42da9f7b59d66aca71fd27ec3badf64355c971cef6f9266d200b054ab5e6c8442d158050a0445562d66d9bade327d990428d3be4098a8a1532113ccb8b973aa3f87c07ac87bd8085dbc19fe2fddfcc626c476a7b39cb83e95f62ff1500af385d97e9abd08e6096e64f1569ba5559f0ca9a7c368938cccd5ebec3fa36843ce3fd4bf8a09310a6fe96dd320ca684ce4839b938fde5b11e7b81aad3d2053c698e8ff1bcc5b90833358eaa7b60b006bdf825a062fe01cd4818cf83c1330906298f7acca65188b51fce45a5a9fd64a94bc180267e1f33c8f052ffe457016bd061572f92c784e245581dfbf378f108880202b1089656514daecc405f5ed23a231f72524c81112662997f371474c3b5dbac649",
"spend_index": [
0,
1,
1311624179,
4294967295
],
"result": [
"e01a5d102bb5f8ba7986e7e4ab0fe8c4922bddd005adf740122684a91afad1a4",
"0980b070c9b5fea0a87b3b4a148876079cb54dc3db9ca560411c1c8cc3a7f5d9",
"3871f92f02152b4846c1f00e3100be52b8ec53cff9f496061dcd3ad3f2f48a2a",
"10b88c130695168a2fc2548e4a6f4fed11388a25f3da39a478ebbce6ac2c8299"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 2,
"Witness": true,
"Version": -1051347441,
"scriptSigs": true
},
"hex_tx": "0fb655c1000101e3bfa656000000000000000000000000000000000000000000000000000000005296f6a3fdad01023648cde2159aabc319afec69ddaa111fde9d94585b4610fb3586e295e25fe73989f10e0991620403eb13fc9861f45021df9966228eb44d474d174823ff8ee86a2ecc631b1267fdb545612f78b4b1d300863e675d47dda8c600d68015b7688d4446625ce245ffc43445d0e95ccfb3275948ef8c21eb59887ab32de1e540d20b62182d442f5c82e41e74b1faaaf84075d88f883fc2e5ae237f3e6ba115b0b2d803fba0d28472c1d0db5e4128b2bce7fa1c1bcaa8823b66151940bc37b9e81cfb2b31f1928a6d1d8716925e91f02de1bfc8b54de0f606b950747063444149f406b003e3e954f89769626083128540ceefd85546537fa7d6541b605cac7c76feb9eba6db727892bccc686f5003758c1c36e7e5f56a49e3736dd9e4e85d12d242315fb52cbcfa19fdb6f794e99bc9a4c7504b76e4288bbce908e1147e1ffa2b25147229b464e03c9a196e5e660fcf43c0a824497e5c246cdd3c79585c43069e54206c06c60a00123f4a3f4927166f290354c512ef7e42b5930c8af1e224a052a0ea1005ea96f19e368509611b183415810e1f399dc3afda846235ceba7224fb53bc8434a2ee37e4d494dbd0742ca294cc04910281d342e9ff46eb40c8747ca18aeaff3d1c00fec1600b4642a520fefaec35d3df74aa13c1d9e37e6405e748512e67399ffa9f7fba8d3244e2e1d6a9efb716a78e4cd947a577a193282d407ba748f3311e7f8880852074a47bbc74994e75fac4aba473c99b97e7ea245e8c56dca37ba1bd4d64522f9eb474cc29018d35da3a1a8abb02032bf0577c681703c4e88ac2c5a57ae0f678dc5834639833fbe1f0e1b9fa817582c30fb07b51641cc4d75e3be4989c25f4b339e3194ff91a0e08916c0410a407fad131b0d15958ed8439f6dcd806554121260a62c36b32c82e0a153e93983ea7152eac373761dba154518e7da0a6d90cb60e306a110886b01353f1dc76ec082130f8176ed80444d9bba60cdff3ccdf31b370e837d94055ba6cc5d5bb8fe396c6d1bbe92c6a19cbd371db892203e7f17e91aa33f093e886601473319154b8fb4db0b0e68e7872e7002fdbab5d6f93dcb61500e4447e4c819fdb590bc7803f8068a008e3f9f1e250a6730a76881fed07d6895690f0444f49019b6e11939cc836fd5b8e4a01f1007c029250412d8e7fd8ac89476849b2c020aac27da1ff8618166303eec688936e28f0a31adb1263dcb48d0d060172ab1d0f0e15102d2815dca08a19d9c2d872224623dabed1880912485e54d3331ec9052a778786498ee0a57271b243e3c854701b2284cfc5d9e5997107cb389df6e58691180bc4ecd0ebfa266a2379d23c561c7fc3b29c393820be0534237fecf93fd33e5cd775e3e17a5db3b35e1d3dff99ccc3263796227526b62c1836704cd13bb50aced16eb449e5511dab9544d1ef4eddd839ac1f73de9bb6a5ca714fd0362301489ffada6154f9aa55fa3bae31eae4f7a9fc02d9aa6dc431cac4f657a47d75defe00ed7ace6e2aa0bfbf06a6f95ab872fc7fc084668b35991e18eecc9a5eb8eede635a619ff7bb40cd1e9f36da0c1fbb9ba88667b8a33d28ef266c270a8e258a933903e8658f71b4c104b34a90a685465490b82483a231d1f5193b58a356b8aa509783964c6aec4f480e6d37a82882449e9f0cad78df21cc73ab71f8253bf236fb67e3807e1f7511da8d4ecf17df6794595d2ce4981e6e7639cbd7dbbab6b18a4ccfff9f404449d82f8c9dd5ea718deb2c5cf373788d8dfd02d375b6d52c8c12d6bfbb5b2ee6a7fe45d705a28df3a0097e90bc4b19ed940530d3244da84a86a9c241bbb2e2048ce0510fdff6c9474f0ac33423b93fe6c07d9c24712761f57ed7c19cd311b1af416544443a6f7f61385ed927d13921bc9ea8a44cc065e6b17db35451b439e1954a040305b2b355160426868746819ccdab1023e30f326926c850ff52a06e8c7852dafa114863f65b25ab7495",
"spend_index": [
0,
1,
2574543262,
4294967295
],
"result": [
"f995d871d35aeeef5d42fbe5c6e8428616d2888db157697579c17add7d2408a1",
"029adfd50489e1921d57b997e609451fc71b9eebd5ab79a068d96beb221bf3eb",
"e1a58a099f934e0ec776d858c811fe485ebace34a67d0ca3ca23f5b00021a262",
"73591132765c175ff83226808b2efd2f13be8e3acf422ef43f728bee7a112444"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 3,
"Witness": true,
"Version": 814707723,
"scriptSigs": false
},
"hex_tx": "0b748f300001053c73ddd9000000000000000000000000000000000000000000000000000000006d37f59d00ee34fd4b498f005700000000000000000000000000000000000000000000000000000000f66f9bc300059000915d417d6c000000000000000000000000000000000000000000000000000000005fda9bba002da98aa5f81966170000000000000000000000000000000000000000000000000000000049bf1a56004d5d2468ac523d8f00000000000000000000000000000000000000000000000000000000276b4b5500fe26001d03fbecd947d802ea49c8a61d48f577a041311daa647870c8166b0accbf1b2d5e050ffddaa2b08d3e1b2f5392bfcdda9e4a1c19c2b1d9f6185d8d3112d09a983c02db4ce36d9eddbe2daabdccd2dab45985eb37b6349bc81c871bb26ab409211a4513ac4666324e7f44c608fdf5bf073fb64499471f81e6f7950c50f952ec14506ab7985656e5a78446b10a59439d98522177037401faf445734aafce951ba24f0cc68bc0b59a75614d7717265797a683485ac416b4f0be3f9230747f5b6c63ca3e3b8650a68e2fe9346b8fd17c9f29d8c6c4012bb9ab0f970578c8e10acd035ab33642af34daac3882805910b8312bb512d9126d4b465a8260f27ab99c2cdc0936c43fbd2bdbdeb2c35308ab9ead119b767ef01afb943dd9e2b5e053ea99d639fa3b897afeb812d315a80396bc60d59b61fa3e6f461dd718b76c057fc998d3344da47b9da5d024dc4557f05d2a270a9dfc48f297b15c0c37ce68da274afda61593aeec9143b85c060e90ff86650e4fa4e9fee59d4a0c3a3d18351eca4e7cb94fe3f3b156e07217638cdcfb6bf8d512f86bb38bd610832cc7c75c4a94e9a90153ecfdc8b85429d2968cdb48c8296777133ff16197f773b3536a0a1a2d598e6776257685c969d43044173724d8cbeece0e7053234712880a031d12e84ceea423a95efbecc0a5abaabd5a5647fbc6b606116e10532fd7a31d8738d37cfc201b726bf6030f25c3961125dc510417601ffa52cbddddf2c185f4cc17bc7b0d510247b575562306e64cb4e5359d7d70d09e3cd89dac10d82fff19c2255a3ca6a992fbac4b414f23fa1971e838de2e393b2c20c444c238b78e0678cca3901cf29417ab0aeeca9626fcb7be5e777da3648ed088ff4d4154b701f38dbf127fee38897a5ee7d7d357a672031a3085600ae3ad2384696bbdedaaec8a86e008f064c6ad5950eae848772bfb597cdb9b9af7baefff97e52965fd8cb2c8e3561617582942eeb827bce577ffae69ac948a6409c69691c61e0cc55cc11320df3ac90ad2917913e701d69402016a4d88b84915eb546ccf34a37a8b33135dd10306ab10e73bb2ab3fef965423557ab11dcf6c8135660b07a90881b876e06047827fa3e1ae98798604a0dc1d11d9e715102edb2ccaaae863d10ea8c2147b8ca3e8b3f10f082140222d914e15599706465da455f6d5f5b9f14829b4a2611476b5d5ddeaa32037e69098658ccf4790671e2bc206020e9e06c13bc00ce2d4ba17cc6689bcfdd4018fc919d232d5f5021c3d689a4625593fc68aeaacdec4e408bade148365996b6da85c4e9fa11220dfe94615e2ff5356b97874059aafbcac2b0dc90792c3ec08ef4a2bd135ed059c52a42b1d1c168558cd4a758a54752b433d624ab4e7971e51cd39a18aa1229acce968579641aba00662976e6732994b8c3f1683bacfbd510b345391cd438f171898612236705e51c6d603f4c95f5739f80d50abf2133c168af58450f26cdd571ec8d0c6ce4dadb2cef510cb424e75e984f9176e448683c08b3e11419f34f8eb11e1ce4914ae35188fccfece3372e502951df6715ebc5ddad5c13dbf70835c1141cdf2ecf81ed0ecd8d5cf5ca8c57203440f2beaf3f91ef4bd5ad27f53de363c5116de666c5ae832cf9216cc8817091355e22e9dc7ce4f652783b2b523032b7b346c25621b65f4a505b220fde444c57a9a80088bddb5726362ba8a8207834b566c2f9bf9272883aaa62b4553d82010d4081f3bc8a2f7c4878ad4adf0c8c11adc04c41c39ba49dd764bdcb7531b23837ede7d615ce76dd8b68323df8835479ee40688172c881b81cec1074456b53ddd50ba6d96b113ea8a04d5f0466f8ca98b6246d8c84c54d8e9362a6b93481fc2b2c5109c7a6649078c8b38ebffb1adeb396aea039c0b6354d17d5077bcfa3b1103de56a85d7f7fe6d244e4689e03b33515e1674724291c138027e4f0eb953286f4f9e5d790351b538ad17a6a2b0dd3758d06d84413c0bb851daec68775eaf4281010ad67dcfb377b834b3adaf308368fc9b105c16e62e76a629b8af41c7de29a54a974115541e037d5f0f94029dd551d72a3b43e5c39c111a8ce30ab87a0e2e21770e924be91b8e9644c8bb37568bef66a355530e2ccc596bc553ed10fb9973c1c83b6d6f088baf33312637a3d7b47aba022d6e74eecb728f18c22e94fd022e73e7f3e573c8306926459669e80b64eb755ff25df4d2ce78a44c6072729834ef9fdac017c197d8b0e8f91205b0f689ecbe2ea97aa26b6d60d3f72923185f561d7ecc627b96ad0744f69d0cdcac6c30bbf45e9d208f69c6ab1ebc3d83e39da96863525050a37d1d2002733a6fc1581e8e9d16f4a64f2455d7541646d5026ee34cbae5f559d822a99086c75408e376e8d932f87a773b7177f54675a77fc34b935aba64a6fc836b7be488764f4644e68c09cdad418b438a15f02a6cc148bb5e716af5cbacacd4a2be4a5c34e7c0a9f534c19442bb1c4c19fc18567685ec0a6cc79f997061ba073169873b538814d6204b0f0677e9904575bd8d4dafd93410e89065d32ba5fb2a912605368bda85f0e507b68b504baf5003b6308b0bcb094d822ebe2369f0a1caef770051c5a658ed4bc909405c7d30fcf6fe5f52a560e3189e308ea401beb3ab31c1c9a274f4daaef6fa6ddffe0d0accb622d782ccc2d8a581db691c011ec745f8a1c1c4bcb2f52efe1c2856e9a77295e8ef14b935820641d952aa895b1c6bc46a821a85d024b39e734838d007c62ede95bb4c14c6e35d1abf959dae66148b358575f52d9f79fcd81a3d6a4bc7bc62f2499d85ff5833bb2a61a12e28b2b70e8433105ac084998ef7982179ed17df120050b9408a074b8c88beb21ca3ea9359a0bd842c8124e1b3e12bb2f6f68f3887f76ea02824bee5f60ef7d6a438f538ecf4cbbd71c0bc5a41acb03c8c46e6b4ecdd47d16a00e4dcebbbb36e88c82e94c5046081dfdf34fa334eff1d2582e72e39da5a3a0966fce036748b2fa55adf9c96e7b995cc10e3ef11b34a9f6f4eb2556553e6572d11013ef39c033c40232aecba0e36b34daa35f6d9df38b01fd6101cba60d0c4fea9019e3333c4dea24bba24bd906ec319da74809533cebce37ded637c6a21c5fb63096809715971f23ca63b613fe45722cff3c8536d2d2ac71a16476d78dd29bfc013157f0c74da2d05a4bae9bf8145b2c2e5d5b98a1ce1bce0da674490d607e67cfac4fa2832088d237482e3184722b67747658e6c2c94c65e3217bb4e5e9d6c02d74dd45829aca17d9aafa2987b05ac2d6aceb51c824f3d9164a38166d85ed09069399a5d76169bab088258ff89a49451999eed3a2de860e81c6a69e2fb6c77921a018cd29ff1f368f5c5ecf1f831b175fd2f40548adff6425596a10e4d857f3eecf29e00c0e401ed85400d0f22cca0cdc3f8bd566409a5f50ca75adca2de1659698608fe19f5d7ce08ce7d8dd5df9d46146364b4487288290a6d88f52a9c8f525512a6fadde91329d86198bd49642a6f75523e0d0fa10ba996429652c173b04c94f182d6f24d0bde2db590da98c9370d25a6f08978e5183cee41201fd2201d9c1cc04c01b43d94b86a20f89e498560be4361aa120763798da9a303337116095fd5e8d368f0f492c79f120d532020a9f5b8066ab8f7f97f02f0165ab1eb352aa651fff9d70afbf497fb82d2bfa7b95c8b7913d9c63756892e3d8a4defd7c63e366e5e051de0657777d06b6d047a065d34129e6c61406bf004884bfe21d27e840fdce1446a47b0bc55bc6565aaa599262e66102b42e7d410ced19a14e9032c0b52cb73bea41cd6ce76b7430eb2f7442f9fd2236b2c37d9f6a01e522c28b5ccd27d7a0b728cf99f86c06460d67c9521cc5cb95e4116fec8b4fa42dab258c3bd4ade03cc6690e5ae0622be12ce57fbe86411c8c42e77ed684bb719655ff5b47b6b111868e1768b36a31fc09f43017e413f9439969f492fa4ed622e8a6751fb94c3f9908e91981",
"spend_index": [
0,
1,
2609405748,
4294967295
],
"result": [
"5f3bc9fd7fc449341f79d74af750943ba58ed43366d610bf9c85832e15b8f4f0",
"564800f51e04ca3288dd040816b60cc9fe4647833a750a98afc943ea22807d8e",
"408c08e764904e02780f3e79cc5e12c06cf7acd222e71bc22ba05735d98f2d4a",
"aded80f68468d06eda4dca4c1b0685c8cd5563e81b900cf29c82f28d3ad77bee"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 1,
"Witness": true,
"Version": 21403141,
"scriptSigs": true
},
"hex_tx": "0596460100010601d21b5000000000000000000000000000000000000000000000000000000000cc926fb500674bbca5336071b70000000000000000000000000000000000000000000000000000000087fe629e00cae822a64fe86aca000000000000000000000000000000000000000000000000000000003ab379d5db80aa6ac750bff88788ab62704b6d28b5d41262af3c738792a963e95fb02fd0169a194a7accdec7ead5fd40d86f6d043f58d81217ed028c8af11ce797fd503aae366f79cfdc5e77f8c77fbdf3b59629e5262f6a88d8abac1ec5a9e3be9c9742e18083573bc5a90f812a63dcdede3e3d444a964533b6ec75ccde595c389e7c8de759530a578b7af5c6bd6de3c88444ff202514f5e22599ef86bf96b2331e7db56f85eb538358598fed5cc77eadee5055f22969d408d32515a674702788e830a3eea9a7c4d35ed430d475263052ab5f774fc0e6425bb466b123ed43254eeaff351b74ed8c000000000000000000000000000000000000000000000000000000002360f547fdb401292a6b1ce12bea1b921383a0da232c9999f28d1a6cb8c3e48a3c8bb493daffa7359575055c7c327d3fd5d620847a9bcf92ca4dad7632727c8f62623029daecba1f94cf734c843c1d52003510c56b9a01d3bc8a56b9371ec83b3f1b89b3e7f9a8d87182d13a9b5b829c29805a4f09859cf5f67bb8eb9c6c620569b2d2e91dc103de7d69ded829cf2c193892dfbab165aab1643e80b9d48d64e971e40d39cc9442a3c498f77953c6ee5e361b47a849fff0648fd9b608533951bdab1568e0e8f1c2590c4019623034afa5ab96d93bb9aec122bcc329e756205e63fab1349f1765c680660910d7303029091fc2fc3539e7a6996db24734297c97e766073d89d27c67e5a2064fc312760099dd2c60674d4332b620573dda5bd72b444eda33174c18c05f721b860f4eb2819a9384d57df40a598f2aad3909041295d59f0a8d30aad1a8c100f779607f4aae77feeaae5d8f597d8f270e115b66883ea05e9c9d3b273ea0f013bab65059bab42f6b2e154b54666f20bac42bd482481e1a084c06c700726efca97927fe005727c2ee470bd97bea94a717f18dd56d52a5fc26c98f06e32b1173d3b1dca7406ee3dd554e8e3280fec79939986e71c8bfcdff78bb9c000000000000000000000000000000000000000000000000000000007fc3fbfffd01016f8315760178a4ae021929732cbfe8fb92ca4e495562d3d38d7e747e070fe5918c42937d71be004c8f3987fb5507a23cc15a92fd5c864eae227e41798af6c61f6e3314b931a10aae0d4f6da2d4c519417ee5302f3f844a32ac914429c25cf553d8fda38bf1b3a107ab3891b66195999701021e07c0dbf0ecb04df0389ba8ee241da0fcc470886d086fa47861c165dbbdc5a46dbaa5c731d8838bee0e00d9d041d8c073ec35d0bb684cdc2890caf837356d45133eb62c103d33450a531d3da116d8265017597b58e61d9e81f64015c97c6689315f1b3bcae6543ef8b14995497b4565c4afb9e9adfd7ee1555306da7d854ea094fffc926fa6d9db0913c9d3030138af91cf26b6dfd6330000000000000000000000000000000000000000000000000000000000fc550a00d67beead01b3eb058f1e5d1b6bc89326504bd91cdeb1d12524c41f4bad8737a0742c673bac363e3c1159cdebcb11b8a7825f24012ba87c660db47a6736d0b92a8515f8ad66a5c926da385e17d0bdfd26b546f9b86e4229a673269c0500ab7aa65f316c2abd00e4d3b5e68303a7c3e233c286d47e81664a421e556a6531998c232ec00e093ed1f3773a4287377c203026efbb1a04a54212b8234ca8556f0b5e6a6111e161326c9c626eb78e9042b5d197abc092ef7574a11bbedee547d0f576805e7dc8ca1b1330bde8ac2f427b239c8a81c902a0bdba04fd39014abab272ab3ea33bb5946fe9a18786ca2ab5d0bdb07a3a9f38130c8b3be1dd13a7c4881b1720791cbdebf2116ba09412cc9d4b4ef081c702c88cc3cb84e22fd7b48d21ffdb250fcf9a27a51b0a4e5ea4d5c0c2b3aba3dc55d37db1f0f88c54ee1dddcb7e38962cce4b4db92bd036079d1fc62ebf6ed94482ff5fa1c567a5c938c130dbc58ffbdcbdea5bae09c0600717af56042976d15d8a38fe5ffc144cf4b8391c4950e3199ab2a5f2c5fed16d8d137be7ce5c0f3aca1ea8cdba22aa4bfb24a08f47d1059b7836364b52d0d4c4c3e0220087a76b7a6eb5680f407f3018d5b0fe017732f5373be87f713b4cbfc5cfdc4bf4fcea60d08ba50c0f71a4f1c01acb685131b12cd5a745ccd09a4ee694bf6ae2e16d5c456bab6c476cca8f3e9e6b2302a578a7acc6a5daec6ffa7153c622b08df87f79a0a25457650a3d6099a243b7b754d1bffdde01a755b0cfa2547b687e47612cd8808970be6da73699a66936a65dc05ec720e21d757ec8e5c578893f42cdf84c91c6bb89eecac05c29aa67f78b2320f20c52bbba11d18a70e6e32187766780d0c1455805de1c921be4bb952da6f67e9016c0de75e96880f22aa24930c27f61f2cfb42f0fda45dea3f8dd77510d2422172db478415c069541d055e210c16614de7c40001b2be4456b77eaccccd6689457793a29c6a3fc8430f447661088fdf3da0a931a68cd4d9a9264006c218fc11fe41c19312479fec30795b9bf1606b2d8278cebf6243fb15834c2f47460ae1137580fd39f52c6740d9e7a9b0b72c91673333101d1ec4deed2dea4cade9779c9caf41f044ccc3db08c270a5ad8fbf16413d3b657595b8148a3ddcdecd142efb3ad3be784026e9ff3ba15bb3e9902d19dd1db39e8cbc9a9e49d679122c3784bade4640cc7ba9a396c61890311dc587129d6e65331a5a041688f8bf377c7534e2b04a93b42c5315d43696dbf7d26fb1c4f16e31a0411aa90f3cdf93badd0a30d92b3aca8ab0c0b2d1b07e3c99f85396c5f2377646180e8880b22a3ccea23acdc1819f6f6f4637e4f16eec41fe53dc7d8391ee9b60f88853e06b6268b4e3376bc564d9400c0f3e9b30d1a268391dd6c69a6ab5110b4545284aca27b56cd2cb7ba24f37b9022fd7d018a529a69011930c421fa1c8298e8a2ea0f853819c1de239c0e04d8fbb55fe0a36fcff19927e1c8ee08b0051aa9e4241b52c35505527c7cb49b5ba85f6742235a0efb6699b59c18ee90b88d014aa7439cb6da9dfe7b8069658df473d86f77de8e3abe9702c7cb57755b2a07029a67346e4f0155e33793e9ea17e230c7f6679bd870d936ff4813220662753b7567549a65d259d3b0d4f76f8a2dfc9dce0589bc8976818fd7b7bbc1b138c4fd913b1c05346505052b691c2781b89eaf7014d86146a928e2deb36e162f1b5111a9140e030a3e3e02fab012320cffc361155e3d54780bc31d9886e742a9eaecfee7226d9090a61cd9887ac47c2b5ead34f254e8956a77250eb620da3d7b35511591e42cf2e9208fcd075eba22472d7552d16d4f6f3d95dd98d22fa5df590ab33129f8404f1cbb37da8a154f3823354ae0831d545ac5807e64113c93052f2ea6e8b42d6cb23a8164d7f5ea186a03ce09d2b27fba5c1ab1306443d899c09192faa6d3583f411f62eef8a9f20f05d16d9166526502a002bea82178876bec3f29b4d6b14ab55c554a82006fdf29fdc41b52f8f5290e0677ade64afddfe9c91e0a70c18cb77df26a15d1fb9b00a2728fe1ac5b64963e8b1a7cf4f41a2b0e359f81d9dabd1c03d78c963d6e9b30796a1233ed4f78979818bff3209d348502db99e877c2837c19f56ac5c30c9d9fe3b111536015603d7af43acd4a5a09789ffe18ddf91c5cbd5bf934ca7774d046e87cd5fe5180d683d2b0fce914ad495295cefa281c10c1fa286130add4909e664c9cd82b318cb8f88576f7d1c1e968ba054257fc04251fdb19d179d425f261f259ca49a700b648c52fd2b82dfcc746074ca87f899382a76fc980e5d0d53ef1382d77b308fd56fcb64a91585c240b7203d31de0dd534421e5f6705ac224679582751664dacb38161331e8e7b03080a6fe6327d2bb80d867f8efd92f35b8391903551078fd8facde46693bc4d05dc7dd08353a3d14c4eecdda0c509f8a225a8bee815916c9e6b782c4cb2a0f9d724c593e849869c8fffc84ce768b19bf5fdaa9a88ca4e9ab3e2aa7c1a8b41063460e5c649172c80a65352c8b50cb3b8da5c092d3d29786ef536b9004a045fda1edef145f7f81cf947f8a582c1b09f8cd4ac04a531912c8ba673af7f4479844797041b2677d312dfff9922bf974d2843e907977185be663522df8da46ca5b860f49820ea46388044a366a90727886af05e4419a9471ed6fff9dd5e6baa2f5c40f9db17ab70d207d359d573eb435195cd1e69bc63e6fa5b3110d57b47e8e1a472fd76b40756bd2093d49215eee347f2e2fd98d017ff1fc8b3d5df71344f8dae329b49bc9fa1769378b2697f6f0aea609848f5f40446ab77ceaae87d37088cf5b4ce90b58896a91d9bde4a2703e0edde875bc768836eae0e26097a3ec206a2b0a44e874424ab70ae596318e2e3e1ff9d0ac5f749c6854909e8a7cb58359377f6981000a31ee769d18fe9ebff7f291ff0d525c264abf29b3d52611fa85f9600173ced565fd2ce8651a9745f967b883c234335d3222484ab5f4592427863242805337424517b1b391193e462419c78f7e457eec1ba9f6571e9b939b2fae357f3bc73ce8f80a205e10d48b7bc11e1bc77cc10b5c0473773a0c023a4967e63e41159059b18e51d972f878a9f3dcc2aaa355aa94c0358631bac7ac90e279dd8577b025bb396c260bbff4c5e3bfb3b512b34f6c6283bdddd1fec44b0a60fe3368cef33841d604fdda017a6d1cc3191ca5b81377b679801e62f4d0890cbb8223802df810a9d1354438049b3d7a0e9c8ab61a4656d6dc2629a9fb4e25fa54a9139d6646a6a147f9577dc1a7f32f8da8d56fc06b4379aa064380cc8802ef69aae0a2e962ebb8308fdc13468aa5935cb388f9d8efd3998dfd05423540194c4e53c7a0066161e8c285e79a4649f0e66c3646607a915e1c88f59e81b8affce0fc807adeb916889f48b94e5ca31cec3b2528ea318e7b0d424d6c5ecaba319d388641235cfa3514010fd4c0c54e7172ce0505526a885de8f353532af79159562979839a5a90f08ccda684a8867be69036f0d6598a4c992f3a43c3ad1fc1d7c09fbca86e3782a49c3df7e05bb5a17d50632b577903fc5c9c3ccfdb2c7f9c94bbbdad2513eac76696b29ae2e53abb1bc2f4b6f8fdcaf239380a51c7ca7958c6b31b7422551e9fda7e6eef57bcb35e331fc1e5a375b29b481b4f400f880f9c786a11f002d97972cc1c5a626bf86b8303b6603eb343b69c1fe3f063e9e5c6b7f1ff2fb393535dae2409100ec0903a76922c978ef7420c6145c5f4782691ead4734deb53acc9eba6de9e9cee2294c9767ec2f9a17cb8f32b3ea0bae12faf5ea9c1041528fe5d81d620aba24b199b6eec08f630e216c830f53c3264ed031d66c8f8a560d5594fc7dba25a01f8614036ca1c29b5453b4b7ebb1d524d561fae087d71e71d4028f2a6f60a55385b47d7e6d16c50a59b877c5f95bd473a02134697df794991bf42b51504c269345f0621009d4ecb25c61260b9af0576ed74ba0acfb87ca7d0d2afa0c3f4755eb93494f22b76611518fcc01c69302a816d90e0b443f89623e4b97917c78966c2e5285a71945e332609d793615693a9d8f4a351ebf2eb036bf2a7946ba702d55efb77dd61584faafa55f842066b11d250bc53905dae083fd1de527f9180171f486a6044a96eecdda76a42e975f7e7689285b9e5af32b9049beb95341541e915345a38909b8c5c9927c932af502e0726d84864c3f2a8866728fb5b04bd3f73cfcef203134b06f08301158bc85b49fbc4d915712e0f031da2533825548c87f3a0d213e204effa84bf31567a358d01826246e224a3e67d374307fe3eb66990c4052678f415c938f20a502779808ac8d37c7137dc2563e3bc05470a16b573abf62a8a58464bc83688e5466fac402bde107e940feece935197f0c2b8b3c0f9314be42a3c1165cd9fdd3074b76aa0ec8455bc366e4b1bea4de34c2b278d854299428d1e59f76c169c747387c04f2f6defa126cd32abd2a83edcec1198fdc301671e12f96e0fb407c506fea811286696d25f6363fdbd40481070b4998ae9e05fbf5399eeeb086d5453e487278d20934d5bb48a3c549082e4026e81832925c92aa7f50f94ac0df136ea6102ddc25209769ded90c67eea3a4622141167b9836689f11aee4c81471d00e379c025f9c0cdd61c3ecc293e54fc78486d8b5f053c88534dcd1dad1f33eba8bb3f242d84c4ed4676c4a595aaa1ff6fb5d3d9d49c1cb4a606d628c8a6d6fba32614b3c75c59476cd8a854e07a5a73e30cbad512302291f090bc97e739f5993c4ce65cc16966f6832c18513900b6de7059e205b333de39dba7548ce5ceef1244e43701ebf5a1ef73e134d5efdca291a95cba7d4718a03e49ec1b48ff1b2529dc17616e788e1b4a5bb94c4fcbc3b0d63d4814dce04806f2a2fa33e29ae146d03516cb9d567b8f0e52739ef42685e4559f54aa914f1d685e0ccffe8d971d84f3e3dc78b55ef3825fe1d4f93b5dde4d7483f272d08d5e69c090172f75b1b570cd1d2f15419de9580433df9358395ef41b42a87814c8b5597afd92dfba262ad1784c4a56b43b3960db6bc391f576285093a9a59e681b46ebc8f7bfa4c668592a8759c81dd5400dc5dfd4c54c292c7b1e715367be922e592cc7a851d7ecfd0401ac846196be62de8be7ab31884d3a40ed6fb97d2dc08e3fab6cc056b35516929a09dbc81ed0adaa8694e46a6973566974524149d085532d5ee08e77963f2bbfcd59d4dd97d7b20c099bbc71c3cf9a2d9381114a3bc402e558cd9f20b68b89fec071ddda09fc29a9f61bb7b339b26c146e3071406092b1204d570a4f2f046a1ccfa9ad2780356fddf70f549e3aec3190c764d771dc69c1c0edd6a01cafb695f248655a2929e2c153bf92bbb97c75ed8a677bec3a487bd8fec11586ad1659eed9a99aac10705d979a57a3abf42d17db324a6ac56d52f33edcd523d906587792dd3f4537db5b11ff1190b218d15db8827f2c04961ec9190e72a8f9e8838db13bb4b74a264d7f597dd596d169875cdf219c6360ac9d436713e0b38a361659eaa57941ba50449e765e00bce31185741feacb5f258c0cc8f574502beb1220b39f0341bc22fcaf8c1f4603fa96d310f8bb1720d08fe5f88d08c021fad3f6c4b8a65c04cb34bdb23d8ed3ab86d48f2cfa9355d334562adcbf470bc2dbc7baa9d7a9ba48ea72433d08c2ed9aae3a4e8ff3ccf19e9a09799497653481bf686ec1aba8add6f67b2f8f59a2ad1753133baebf551f489aa9deec98a2dd9fffb57d0e4fb145344d95b459287b9a21101a9a8abd022962468a7c5c79a9b1b391502d1e5be56330f6199fe691be0ef34f3446fa1cee5af1bfdd10cdaede2fb367d36922bbdd925462f0f532f25d295d2380e947e252650a861ad08f0d395f2255964ab2c089daf5bdbe7ba1bfa42d03524f9b4ffdce01ac8d4e394e74da1ea643ac7294d4482a24f9e5def87c8bc44b2d8ea7039580e6b88f1840f77ff4dad00c862bfe937ac8c5f2ebe7325c13338b286bbf066f2dc113a1f8d34948c29119814e09a57f6e2b22e6d3fc68faab24444ac83fa627cb5e251940735dff350debde2ae483f363e3483c5569cae870cd8969c3bd942c4c00a29142a8c97e427064779e080cce75a46f19dc4a0bd89dcab0fd7fe9bf211cbc0a945b1e8fe80a26f9486bdaf92682a027577f76915183184f5491c5497955c0de539a4374bf4aedb27afe226ac37114f5aa4c2793bf60baf4eb44a04e4f4bde01a2d5260a62ad7a99c9bc3b1e15b3c422dfd1b1292efb1a4729b6d030d67892882272a1ab255c83acedbb3bc2ce789a5cdb74586787a4deb1d726b5c3fbc45ca712e84e71dfe84e321566ff45504659aee25d65ebe46b8961036329267d08ff62b7188f88eb633699bc0b8cf8ed36f1977df3e46f8d965a65964d0e27f35cab715210207da86781ec5a78a06d290b66fce6bdb95fed09e5b18ce6dc38d50bf1baac4c7136bc9421dfea53ba199782b50dc93d0fa94b04dd9b19f7c26b3f1ca5176930334ae449b1ee7498ed54ecbb57162da15b4a4464d4aec222062ec8a025ae87fcee521e54a7980e76f79a53bea72f94d0d05dbaf56fdb26360412eac08d782ec2e004d3b4825ba736e4314b15dfeefa6a688c6a2fbad552420f9e34260c353de6bd8cdbe20f25d9b925be17416ca6f40a120a9b51335f8253c85a996eb814381059942df7f2fd2b2ad6a3dc72701d26dcc70b9b9272c98ff35b506f362137826ff1c01cb6e94fc45be8d4566e564280a4d459de12e7a4bb7e40c01162d9e0bf26005ab49620f3e9ec6edb2971892b01892fd6198a3f281fbd32eb2fa6286ee81ca124b5723a5a87669763fcd76e635150248cb644d6ba9cb39a764164980efc751ff4f0025206aa0c1f065d2f3d6f2507ba39e28e5fe4cb2619e397792954514fd7d774ecb89c3e93813fcbc5abd4a451c7a29063fcc42e2264cbc24b3ba4b1a7e89475cb57f618fb0850a346b62a8e2537146b67df20fee9189fbab7854bca3afca89847295875db93e7922f12bdcb1d179a1a160e0acad1111a6a8d297d03b3864c0d97e35c7d35eb7d429fb1abeb7a5967a99f2faa60a3333507de04cf9d061363e0602b149652018726ec6db2c25705491df598580ff52eb9f728b8a0c6c5602b7bd76a94af25d32ccc066ccaa6c414a74d475f323303c2d208a7aeb7555afd42c14686590bd12a9396",
"spend_index": [
0,
1,
2796535865,
4294967295
],
"result": [
"b20bf0f7bf874016ad63ca4df0d99831c1ce767b3ac3b0f50f2d11771895003c",
"802dacd41f97a3865ae0825950723ac06924c7caa13598f67c9232efa8843a04",
"5e67f8c61e39c1ba23abfea2d0f280ce65cf2302cf385b0828226b8fc36e6d20",
"87b4a556c0b5dc3ea7d0853ac2357422344833b3a5cb16e4d347a0f6b74ffdfb"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 2,
"Witness": true,
"Version": 1925178759,
"scriptSigs": false
},
"hex_tx": "87e5bf720001032856388700000000000000000000000000000000000000000000000000000000cab6031d0095a13d21ad1caa5900000000000000000000000000000000000000000000000000000000727f13190053d917c59770137d00000000000000000000000000000000000000000000000000000000f537c10a005138206e027518707259bb2b34c86902e1031e3e2e4546542ea8862d73bee5c7534fedd0f90755ad7738a760f8bd3519dd0d71adf1bfbff642028e875c015485e8d7676338930d51dcfebe9e0fa355b0a45f4d86e4bc409cf5e8be215f99afff42dfd27229b55d5be188ea90f202eedd5ee9ef2c2a35b5f89945457d667ecc08fc841f34f79b25743cd13e83eae08a3ca9dbca956741ae05a1944fe1bda496eccbb7d95a4a089f04a5fac5dd3ae06694ba3189a3fe31feec2cb97598fb180b7a4e73c2c926e2f72af22bc46d74b37c5a97867486ec036d4078dee0b36a56c86bad746e8a509c812709e292528925ccec70058ed188b7b327ad59676f0ee7ae0a1b6784635865e097a6c05af564ad7fdb308dcaeadb293849c899c7237b0321c35098f37214ae4628e8aab2c1760d9a3b87712f69c4363705a1e7bdfe1209a58a24b774f38c940b5b235c031decd9b96cb8d795529a86c579d5b448691b6e9347b2eda029bd0dc7d0305dee4253ba8f964d2f9642274d86ff3694c73bdb27cd40125e3e57c2eaa86ef0b3df137a4723c36386fe15924654d155feedf70a2f56c0f25fa1841601c804fdce01c01e108a0ed78ef7e93645c39383c3472d5698f9ecef72defdbd00ac5def148ee21055d8e87262adbb72e3b9f5ba174c61a3c03cd75bd197b0b3174fd274494f30ce300ae8ac4fd3a6133f89096ba19fbe237d6ee3a0f5019ce6a652c60b0de903d53de6a8d058dd0a74a96f301f7580bceeb58e20cb2e4f4d66b109205edfd81cd1f5374c8f7a2bfdbe71224f950495f22e685c24d5ec231d4deba4d2af7d350b4eb0f7216cd692553c62e212c5f42805478138b4c49fd35847337472cdfb0a95ed19014da13dfc715eee6c91e6af4c6d13d090bbec13071ef2e99b634b1b96c6e3fc0c2e4d3d2828abb021f6721a2b7630d08d627b4f8d1584171be8e0b920ec1456cde295a7f12fe89a97b2511aa4e54b1c44748b184d4de656b06612b619b2099ae1892729f6e11a6803fccbfdf636e26a7f13d9321bd56dd733c1944f3b47a698725695c7166299c965b7e564ebc02ed3eca057e2643a105bb4007831ddc860b99342fdc938735c8e166a7d41ae9d30db4eeeaeb1bb38a09a451e1258927df33493deba07fa0e326fc2af03d733a365fd4bb6662cdf3bf7acef9369b340357d911b028e8a89a904901c9bafce874ce0974f042ccaef53a0b22e66a97990fec4a010df02820ae11beea66947fde80120122771f5b022287fc3b0cde2f62bf2780722a35c7b9fffabb4483f25a4d9c9d6f1e486e5da2857d825a6f06a91a4b020376ada786fd91fb14ad0b15b8ac2034b04c2e61f1b5259a80d491762d1745e13649d12c6bd6a21c7673fa21cf4a55ccda0ecb7a6d7cf57bc0b2879bda4c2adf62bd7b787915f5a0418f59618957685ab5ddc2618362ce51ec0eaca7650ba1d7f25be051304b3b6cba5a2b11f82c8cbc9612533d5611f0d0e1bcf64a60bb200950f62bbc5949c10b6a0b8957a1bfe2891d1eb413762b0ac9a2700df912689edc3a2a94535119fe0346ef2ff0da3fd404449395463d3eef18dc29eb6eb539c0a667ebd364eccb8a9666d932c990d13fb663398ab8e964598c3cbd298e954a3f5ccb640c932ba0105cb4553895f7b4cd58ef0252a363b28f4315cd3b93967e3c061508367cf814db05f24c15b0587f5adba5b3895a83a47c2944d47e52a1c9a39b84a954af50a3cd49c455d914c9ab25195c5355c24045b5b79a134d244f6ebfdf3b5c2267704513b51fd085bf1cb40106dd34c217200303fb2537cdbbda8fd8c7db1d4ad5aa8eee58696bfb6a5e58a979f6e95bfa86f8db432f1500dda08aba408f7210517eb5c805aefee3b1096bdeb29b30a1b10613bbc2b7c17a91d03b963af7d4863e3a5391ef9aa447ab435c69a4a1f77f502a2faaffd8701363bca086a732aa3b76a68b9632d71eb8c4d3688f4081e5f40ef72d2207963a2ce18bcf121ea94c80fb07579462a43024ca3a7e2c5e3d53b66beb4817fecf398e142846b16d786ccb034cb2d455b88ead1bc0123d0a97cce3128bc8ec1fbdddb0a41b063395b139ffc93023ae8bf25afa05be76527264e364e7f67f2367191ce8066f2242eebd90225c73fec97f6fe3a37011769d7f9eef3d7de5b62d3a4b0f6df4c528a326f5c998444bc1fa5b92e3ea258fc98f0b32e45ca4d3dbc29c796e3708da6ca0fd78345b3b5ebcf3e7658eb263b185f4048f22835c71b3976c226c420d558618daa4b43051e45852eff7f81f0192b70e88307dc99e30bd57483f26f655402269cbdaa9d5c0e0b2e4f09d5a20b6161bc1b3176e19578d0c47079bb789ca26e218ebe235626cfef665a317e02b271c47dce6199248daf06373434fc0db7c9d9f763da2b66c330d113f75dbac87d44e1a1b3a4af8fc15fa5138a0aeb023b1b357cc54da141b0f72edbfd4f53d7ead2ea105e17cd3fa348f28ad0e8d9629e66da1bc1cc557c93cc6240026a713160f8c961c7d90737180e7437c7b18155559fa9ae4b342acd42573d90228a2853c856da1d6241e033cd5a4af667cdc3678b76d67a55b8dffea7a398a0c3abfb9aff7ba8dd69fce4b40872156ef691b2391f88a07811b54b4f176023fe7b3f565b1afbe25e02a7c720b0e35983b82749358bbef2760390dc028fb92faec6ebab2a72b4298f560af575ca56d714bcdd678374b31b477c71817edc83ab772ce48ae2df2bd4df788eb46c12890bfbf11b160b085f64461528a79d0e8085ef5af43cd0072e7339dbb833d51d4c30d43c336ec5b7065e3ac88bfc04ebb76cb0196157223303758dbcff789e9716716ef8b434dc827aa1e3865f4874f4219f9b4f9d69bd38f1d89e177b835f3589ad22859873d25927bb53c2f105219a486508e7a8c941bfc372b51e8d037076f916965be6cb7ab9814185c5d6c38b8b955309d467d8b49d97372d802654b9a4c2b47ca5c980c75bdaf3487154b0fc585e548c22a03fca488d2b9d2f71b482099edbf9f91ff962ebd7f8adaffbdf68d45df9a9d9a25b2423131be2627c4b0915cdfdea0143b4c9942e37c67fa4f1d684dd8258362f0889faa91efc843c05b8bdfa6a0f30ebe12055ff1e88a4531a35b0d8e24ec5c5a1d49678b7017dbd08018197645a17872c50f39fa027f17aad11b3a5383768e4e9ab472f16fec17fa6093f2c4f7e7495141e4acd4b046dfafb6f725fae55f683b6f94092c589b0757789d8dcb2b00b8cd2b96c9a77b333f9118d9b1f0bde08e6a6667d81d76bd622cf0b225b3da4e36a67d0aac083f6604e89c992031091039a4d508b504b9caf437876cffa89efe3544bcfff3e723090476c013f65e3267f49a4194ef85fa0a5fa5c229dfede0c70af901edea230f8e5c65da6071bf55f7604aeb7c812fdd71912e1047e0a06af0627e2a8cc48b575e8c17bb4a7d59f4e349e4dcc6fd3498ebc98a003908ee066602ac6ccdd2327b7ee8d67074acfab3b845f9e7edd4e9866819de8021226c321f3a489a4bcf7da93b2817c6aaad6d7f03743ea3f65831ecdfbd13396aac82cf68ba3ac3a01c9a0980063d895029d573c298b2ae61703357535a672048b946a8fb33c3e0a6a3cca25cfe80a288f4c83c8afa026a35e9e0b4936879fd9a054bead2d7a443bc62029c2b76a05126e27fb04edfcb07acd36dad78cdaf13480b440ff69fcf792929aa8e9114b426c58e279dd80b47a3b53c1a075849bdc8f4251ac25624f2c9d69188be10e32b702fd7201dd1a38c74f28d7ed192299ccc97de5fee37d86cf677b4a93cdd4d57b2345901a0cbb76a3fef8981c3856064099d2f754186892fcc30b9ebee3208b8a6207bae8cb9d8d894cf3301640e9442689d2e8ac45a761d000a3d1f4259726e6b4494f8d4cba43f4ce68dc9cfd01aad9c2ef23b61138223a99f687562fa17e2a33025f17dcfe9e8d7608eedaba9562b82096e5e08461c263a5d579a7f104a445122d718c2e9a1e72d7157a37c1067f2ea00a5f80e6badfc25b82ce089deabd156ace425b4ab8eabd96e60da6565ac2fd225b95f2b25350ee6b06a2b1c0b88db0eaa2a33d6ac7dc594f3a2aca32c000bc539ae9cfaee05d6dcd38f7aef23180e9d6716387c0784864399eb9cbdaae5c0805f36875e290179c5e7b9b7dd054390c0449989e9c4d30bdfdc31d24c60127beb883b171e9b4dfdfc5faa0503d7b9d78284f7763b490afe2b41a2d8d115287107240758b0c5cad97c93f656bbe14a0a3ca92be59ee858eb48c9d0ab4350cbfe1bcb077253958fd9401811f8f4b6068477201aebfedd962ec4a3af8505bc567e9025f89296cf404f7511ec08588c7140c0200fc66abf09fffefc9e21e18cf64c405e68aef2923c014ec6cf65aaff5092f91a11f6fe67ae8e5defc323128882e412562455c1afd385d618f93e72e3787ef9f4a11a258ca57162004d7c6ce3c86fbdb8559566ff33293d904d1151554dca7ca46b53e7a59bc9338beffbcf504104b15e18d4c307fb1ae3fca5b1777809974351d7f4672ef191193b66e56e490106377ca181df08039f6312060fad9cda564be2b61dcb8d24b34592dd74940d1dbf5a01686d05d545a1fdff3f1fc6a7f086bebb6b289c54256f4fff10b51fff6395c768fc23836aa47a1113393e18c6fe07efa218b8dac25cb170c2d40fca0d908520a314935730f554e233518f7b9eb90a8f6149a02f9b028815b144cb6c8f81ff77c3d9c546ba12e6e605a4eecf8e8807f66c8ede1caf68f3afcd021102bdee3515b483e62bdd007e4446e78f4b9ce50b2bd0e8d2eb35e90031df6945adec76996f46f2bb20a0fdb982a9356e67739bfdc785f88c04784e830dd2c0d731b844f1fcf",
"spend_index": [
0,
1,
2531309487,
4294967295
],
"result": [
"6aa5030e6eb67581aa7c7b2708db784358e09d8c9b0ffc64310ad8ce17e9a642",
"c6b316553f883ed41ae93c6d5e78560e625f38c6785cbcadbaf742787d2592ef",
"b7df572832f590a304798ad0fa135e99042164719e03afbc3dce925f3d6527b6",
"fae5e2dc16eba4a334d843e889ffd168bea0f1984071b275d2b002e6fce8be7e"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 1,
"Witness": true,
"Version": 388868779,
"scriptSigs": true
},
"hex_tx": "abaa2d1700010519f5c040000000000000000000000000000000000000000000000000000000006ea557d8b117df5e3bc8e37495a9d11545c33b2c595415f8b2a04c107082cea0b6880f1bc1c56ef6b5173e2411b8b009b6cd645542795ba41692ef896e5b3cdfda28174479ca46a39a9a7a2b6deead05881f812d4490c7638d7622ea64973a516f30968b5bde9e00c5e185f5c7b74f5144d18a8785a77f41d5b0369910521e3cfd1060889a73cdaea0553bdd73b9a74a4723c879d798500c1ab8b4f3348be682f420cdac352ca865bd3cff954121fa02ecfaf1893683eddd1e29a32b7d1a00000000000000000000000000000000000000000000000000000000d8d22db820b6f2070dcb6ed7fde96cd0daf36baf689815cf7434fe76cd17b40d55caa040f6fde5a2bf5c21379200000000000000000000000000000000000000000000000000000000f283d7d3fdd7012e9a3be8258305b795f179d2eaa2b257f33a61ed25ef99b46e720d64af6ad1e163e78d722ca24f4d1fcef74ea1b43aff2a2490021ebc5f4207a832e8129afd787494df1ed827969ab9b1a8ed85e425abf8312b32a6c37a5e2570a33cb36a422053d6ce242296e136e163ec84331e6b005f5ccc2cbf8302d67e5669f66166b390fc5f14464031e142b99c387aee115bd785cd9a254eac28d2e08c602d45f24c49e15d86798eecf8492a5e01c8f38262b2a78949406a6271ce95b4d403dad1b63e4a92a9ae8070ccc7911e3f6e7755e03f524aa5b4e62f6e8b726d712b775bbf6dd11580512df826ace61c2cec6b71105055f48befe2c7aca4a7fa1e7910892e279281bf073bd16b3d8c728c3b8654823c76ca4750e195bd1155e9972b02ea16a06fc65d8637fc37d589a22279dd0534d5564af0d10ec8143bcf6d20dcc769ce0e85dd2eba3ff9292464e703e4188c188fd5d30bf07a0a9f45bbbf8f7134380668b13f45c4a4dc50ecf6a338c745cb21ac3f8e7554f058c0cf57553c54ed698bed87c659ede75346332b9f75358133804df22ad1cbf2a3ee4a20f9baab0e3ec1e179528ffcc3f50812d6a8d5f0e3123e913682e42eb1d6d62ff7fe438024d8fd03a8cc8e25721a03139957c9a987eeba99260ad4369c6027b1f9acf037f81547000000000000000000000000000000000000000000000000000000008281c66768798eee90d89d4bff1de684f992a43812d0f27b9093151e22b188d3cae8c141b08c3d8f386da82dd2b16a8bdb5dde5c9e77ea90d753bb3eccb7dd82dc1eb29a62ace3a46c4cad25e3c2356f722f5de3933e952dac1fd33d50ac33dd7b4a488fa3be375af9832b25a46696913bf550b3890000000000000000000000000000000000000000000000000000000031c3c9f0adfa37aceb6b344e0a96379c576bab04ffd61edb0e05fafde6b6a063aaf7320c1a3f2eadedb450efd98e32615c1b7ec0ca2ffb5281d05cce41cf81b52ae0f4025e624d64ef7a811aec917d6ed31d8769a8ac482128780b2be995dbc308935e970fcc8c0c9d15d08503ff9f8d1cafde70dc21e8a056e056d366a9451df9124a2987eb5e438bab5a12a05b87731467e36423fe1c7d9b045f5d77468567b6a604f9ce35b2d01ad020139e1bcfc99fcc26fbcd3f01e4c968239235b20ac84f59e357bdfdeb4b732437828a6b24e066b5984db7a9d67cbc6f7f2c68124c0e3df45f2bd76f8d1ea27d38c583dfda2f2805d11e914807ab4ce855e29189dc29c762a467acfa2a736f2b648f9be1d08fb6a71c56c4dc549c0426e9d32b1ef4db61c0b8cf0dddc4a93a72691a737d85a73ea106aac065304286b9c09443bd053de8bb39078ec9b8fea69b39b8e2aef850828c643b6e5d510cf0ef8429e5488003b0afd2ecdc2dd1afd4335849879acc3c0de1669c9e2f6fdaebebbaaf83fa711e9fe34f834a90043b0456c0e1e45c305ad273ed86c10c522eb8a3f4c8d0c51d236a307ab7ada9872c6826d7f67883777581c94fd8610114b863acecb440d638332d5ff8b59cd7d4d9065d143e2f3aa26687a13e36319b3eee0df12fe9cf3101c2124ce5641be61fabb9351727a09a5b609e4df14fe2c38162ec1afd1dba431891599ca340697144c8c8dcbf53a45f9a9a947498e3e3e3c5a5a13a568587275c0f3f2255be3267675fb73c5c00572c53c4ecd49f2df83c47fc36ac9373b54808e25c2ce64b3dd1949476aaec7f6a25671d322b3a9b7d29d2dbb965c18825de47afc6916852cb09b88d8258e89116fff7230e0448600b2f65fb6fe28a72cccf44da378ad4a7dca0152f2973bb9fdc82ac01988d5509c42aa640940a8a67a5f18166b9ed42c08391ac6a5fe6e0505512f8f103bbbb6721a527d9b17c9b80dcd7858c20cbf3ad1255614a6d062c4716875d682f415f2e443e1732d432ca7bda8958fe7c881853176924b313cdaaf20bcdef7601ac4d35216aa0b2e511d611a07ff675dd2921064be23f6d401515e739d88e8db72120e0f96a0b05c4367309749d01a165fa4366812c78f90c015f39612ef3adaf24cc67e464a0033de296b6d8d8e7b7f50e99d5446e533dc5d59de124e9ed4fa42a1f69842cf28bad4e7e1d966b11c64100d9d2e2df66357d478db99d35aea74f633d415d97e9a451f97355d51970355826add27ddc71676cc700029fb1af45dd03ebb01533b3e59888fc144249722045a444db4b752bed28c49bac7f4f266e12d6889daffd0398eec625695644c9106d2f493a18d2a67f3bba004431b42159459a7efbb34313e5a46dfa65ad062051dcb737c52788d4198734c9c55b7f4339924815bd1c9ece0984b092529543f67dcd8eaf092e4f4f879e527d0554820030692616a8d773d114b902f1f0bbe1bf0eadc45985fcd5301fd155794014ad3b971756856d80f5b10e756092b133aacb680a6cb9e710",
"spend_index": [
0,
1,
2898176934,
4294967295
],
"result": [
"881e1c24059c25a2f9d1a00857b12ead0f18b45567ac8d897ca6e850312cbb57",
"c60857fd242e2c0bdc0e2713799212c734c324db3f60fb0421fc8bebc0f85f00",
"f5fcc4667fe355e529975a89847ca44f444c560ea86a17ffa27261821bad405c",
"294e2970a8980538352f58c1756958ec21b7f5d1aa0f649dce8a90844c4a71f9"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 3,
"Witness": true,
"Version": -690026209,
"scriptSigs": false
},
"hex_tx": "1f09dfd6000106f4d2bf110000000000000000000000000000000000000000000000000000000059ff91d000d80f276e34f125ff0000000000000000000000000000000000000000000000000000000079474ac1006f953bd096e48aeb0000000000000000000000000000000000000000000000000000000017751cf70094245fda2fa003ae00000000000000000000000000000000000000000000000000000000738ccb5200d2e1794cd5eff28a000000000000000000000000000000000000000000000000000000009babf79f0002fa68d546faeecb00000000000000000000000000000000000000000000000000000000309a198600b4bececf030cc7a4427f98762ec86324677caf5e88a73f1d065463b9840abd4c40e262d892c03b8165a07abd15fbc1709cbc97dfe1192bf523d0b1f2a88c5d3d7610588296c6b5f6f8fb0acf213e38d35d5a34e5eea826cf4f82b3dde023f49d42aa306158b41ea7cb698535a52ddb25ee4dafd3a669cc7416d593a34161842e7204fd2575bffcf7d1eac9632236e781f1eb98d66d089ccda65a355248180f88304a086ab3a4350e18b837ae2b1dcf924c19524755d6bc168be991a5b917e0a7a49eddeb73eef59f1a1f833774c4e1f55fbbd942bd23dc1236090f1d064dc8da8df713f7813d467fff506e667cb98535cb0d4a6fdd7a1c83e3cd66550eebac702519f6fb205a60e977a03c90bcb13c5f74467db98814ad9bb7ab2048eaba8f0d568951f2302c1a39233a4a57dbdf4df82d5aba2a9d1c3835f07fe6836bf52da50205a6bbb14e9e81aafd784a87b522ccb385cddb7b9fbae48df6807c6ecec5cd65f47948abe0d51d1c64d1259b592008ba28fe7507fa9261b357ea21987e63b1e4eea4e0ad9c170718d5f128d0fb5ef6a6346a06836657d18d1da5189b1cf8ca816f620d04756843a96f877d875d4dc881bb6098d0e9667905ee31ec964887fae8685dc96458c6ebee1882943fbbf856bd37cd3d30eb7168839d768312153e9f55d7c017c7a5e367a95d0d4a74fb927587faedae6052b635356436120a6e45dd67dd10c9512ef091d3813577e1d5ef1adb031f70559d70405616706f3d3ddbc4450c867437513581b825c7fe4066fd672b4c7ee2e39041f473aff0ee6b9ff342a16c5870336d3ab8c2e11c9867ba47f16d33665fe060b8c6606d7ab7ef5db50d18d4ebe46e6c858ff3ba081d867a3fadad20357c3bd6772204fd7901a51c74c194dfe328d02423cf6a663f69fec9551d59e5ffb32c3645df20062cdfadd3e73f768d49eba33c97d20797ccd80a64510d72224d50cf3511748842e7944c3214a4803c81793f1716e2b997c3bb6ce6eb43636a49d9b520870cb6a63cdad143d841a3e072d61e52889e71ed7a775e5409d1f119ab84a5519976a52d81b392e32cafb10e75ee97138fc9478dee3e27fadf32494ddd7c589fb9074434e13ea90dd3d4aea619897522b7041504992621e76144a813e3ae7bbe28fdbbc5bc2e706a2af7a5b4bba1dd851d6050f97ec6f24f60c05085f366d07d1f66215f05f053606948f87edf84097b0141c834bd736898ecbc4eb1c90e4b2521a75e42a245fc45f13a0405e3efdc3a357f87a3fc27fbe463291a3c83122a302923aeb8f9ed6b17deca8d833a9463d1b9593d5687972c7988ccafac4d816e85ebd61cb2fd34e42e43d36e3ccbfbe11015c39bf4813ca26fbb28d8ff3920add8564836017eb2569ec6564693d8c067a441892beb3444f4bd54ff00c58b6056bba0f38923e844cfe0008cc5fd889fbdb461f738ed15b687c6d2f8f0a4cbb1609b532c645929f77c1d0575ddc49035e3eb15896ba5225831b15e7d8b5fe1eebc6021a8a8d2cb0e6be7b7b5dc2025d85587ffa4d0b77b07e3e7ee38a99f88d0e5a4baf94af8ae908023e35f8234c548b842d4ad8aea5f4646f5f166576b55eff9821b873b8d367db99ac446c7ee40b81f4c7632d514425dcce6af9c78c7b7dfa89346f8508b72ec7d9f05b5ecfe110f8e7130ba7e0beb25a57b619ad20e7013a3d394d2f65caa8325b19877fd52012c5455dccfad0089dd69642626c889cb328c5f567ec4ab433686ffabd87426ce440df053c2dd69b7d1d5b162f6690bbda276454494780bf2fe7691f90eaafee1cfb52e14db9ae3b0980cd44b21c056c8f4b0cd5b9886bdafc59820a735d5478c48a2fcac7bbfb3515011f5c6ed16228315a8fdc90fef8d8d41f9c27eb2e991f5ae1f6b83a8f1070954bd47341fa301d19534c8a11f572bf7c899d581d8457732482ecd72c857c22f5ddd56488de0b43ea4e8bdc1bb32d5677c1fa352d1d02cf1ed853fe37adcb20c8593ee9cdacdc151f8fd0d82322d48787f66935bc980e03495142e1fcb3fc00b3e3985fc335a5c0ad81c397d9f892d0a485e64c74fb93411c3c5f35f6b87ebaf67f54541687590579c0722f2e98cb075a7508fbddec43f1c0473121ff5e4521bb61327d898ef69f5ef42a9157ba1c8d93e145c35c2dac263b74ab8bdb7bee6d4ec23ae8d1ebd5b3b36140456ddcc8881497022a55696bc6db40be3a0c9f57ab97d8141fdf7fe90dcf0df8f5901c4ff25930f73b3a87d55b06b80fd748b01729997f5fca4e1cb8c9be6725451e2d31beb587740441ecd6b64fb757b3ee18d8c822bd4fd81012d7b13446c4dc4b14f76ff2f7b9f336f9d9a7ba464f455b4f615e206347e40dee0b2a99b1f47f819628c8c6b4ab3b8698c1fb3f437a7d5085d61a54e7c1d549c3aa7669adae4fd761ffd0b0e84928ddeb49d7297dd699f7b8a18c58b651f55f5e62c6a29806d8e44b1b328f67dd090a3d0e2964e7968b2fcbbf5d62a51ef6226034bb0cef7f5d57a0a20fd018959d78cd23ca851a6ffe8e911c4b27be42a29cc71f75f99a60c82b4506f1480c4bc85d24eec9605ab4a9fffe104d6df5350a897fc71039fd5a6df6f1b19d0081572caa0ded13b4c7c5028124c3c428e804388c59fdd38148cd17d8fdf8df4c2a4f1734e0286e6bff59b712cd0a5193b822f77043cad8dc3a8f40f4b5249cb8f9e9821dc7073386507a007ac24969ee7090c96192231aa4a7daf525ba3dfab3d11934f736d10e8b7fa5d8adb800a5986ca8ff9adfa7fc2818b32d020e84edb4fad653a3a495a8d875d51d070efa96f961c1f64d23449f4e520a33cded54a518c2f3a691198660d32d3a2d0cfcfe16b7bd4be7a88d9fd5201f60356e1076a25de008376d86b96b0adead85603296be4b4df6b0a61be6c71e9d777d22842ae13ec6f0630254fa68b61c9acf53c6ba8b6ee7d2504e6ce5d4d3dc92f18e647fda4bb72001a4134659d7c16253eb5c50bea0b848bdce5a7bcad890ec279265c74a3b95ef03e77313e12328ed4030f2e44d85c02d76e2b481b04ca4f03ab8f2abea06327ab0e121e49a5f07b105b99c5cfa47e5c54d5ae70c495964dd276b1af264ba04b95f2df45f799c71031554fcff39c741180b9c2f7432c22b779591080ef524dc72de01855d60db3766800b8a99e8267108dfecd8178928d704988049cbe78cdb2dde1516185bc69e46638ba436311f57f7489381e92040657c314ee86a63a93887c81c362a6f7b7d7637d2c88d70b6ed2ab80a97fa548f7443ac64a4241cdfc4b19e50b1261da72a21a7c2a7229acfe8b6796b728aefdf1f866edf007b6fd0e6db52ed1d2e66ac8af20ce41adceb40115faf56eb264b4ad8be82407cd8b580709cfb58a027b92777f7efec9c2fa66ac505399eb17e7d48f0a6659a5b99ebc2dd36e0b920456114b957a3a194951509a668dd42915edca3fbf59bef1e592495a51332fd4e895b3762c24ffadb594f5b4bcb196d7a7717e403911d599afcc1bc26ce664d905ad01290a9570da5c778a709e88fb4c307c407a9e61f4c53a69bc8b68668da5b5d0c32bcfef38e8b0af68e8b98c19c9f339fc454676be0656f1e5154019bf5e7047b7771fa6fe43d39d79643df3dc877f05cc3fda0001bbab3f2f1f6c9fa3295beea8b21c35bd32842e6e8533250547000134f38ed4f8ebf51f296ec746b90dc7fd301869f4d33d1ae655766fe07b548cacb36872396017a420623cfd8c147df07a8fc5161ea0f8f721fec60ba030d35d7fd99becddf43cf3cf064b167d740227cc4ec7a1b5860a174b8a23f6f9d3c754cfe46f069bc69f44a91bc4b3e1d9544f5571449152cf9b5c92bea1b234e7cc870ed476b9b39c002e432b501d18b09f43d120c1c531a5354f5b5d394472d3c2913712012390fda2e78eb4cf26495a17f02c18db6315cb984977c493350fd892a6f551a848c6bf4e002e5c92f9",
"spend_index": [
0,
1,
3965014848,
4294967295
],
"result": [
"f28f0129882d7fbc863ee68a080b6385c32ba80c9807d2c3faa0499c9a8fc3aa",
"2bfe4ee98648516da59d4ddaa7f3852467839f09c6119663aacb7c8415031274",
"98f7eadda8776f807ee6d2988b94d26dc6b28bdf3bd8d4f15f4874e3d74c7ade",
"0de00fe6be6ed7fe240fe437cabecd03a3a6b14cf66b0b4cdc3863e9d81b2436"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 10,
"Witness": true,
"Version": -330535473,
"scriptSigs": true
},
"hex_tx": "cf6d4cec0001097627afcb00000000000000000000000000000000000000000000000000000000dd3b4ff0fd8601acc66aadfdbbd1a947a172eff604b62e8c3e8090a0e616ebb1e6ef6d3125f59da24b00eb8680498041eab005eac7cac1d0f8180db579f55ca565c48a2f01b682441db916655c4bf3e941d79d9e028b37034954fd18f5e4eda9c407bc7d92f30e630bd12a59f244b247ba3eb5f415101c1ff3ccb933fa49726f692c7ffaee11dbcbf4173d5fdaeb6859094670f15d249a1d0b521fd3aade0bdf895b3380f950a83f2cffaa114ef0a2bd51670b0b9bc455e3fcfc1f838e784af5cdcee25b367c711b3a00e362757b467b124c6693aa473270d84f7a36dd49e3c285b2fc3e688d4b9fa4edb2d46871117bf6c57d7b510934f2ef03a224419fa78a30ff82e9da00396ceb4584fdec173e22412eb221ff8b9ab3184de295fa5a49a5b3eaab279adde8ffb6702f0cc72e702463fa566e2d27644727dcb1fd796271c494e35b916a62b96a9af7bdfa5f9713f8ccd0523568efffd2a4086b992473b63ad567769c4c76724eaea2044f45cf3ea94fd0e90e7f5e85521601c1442140f84307b86bbef737bf5f3331ea638619a7685ff484179a000000000000000000000000000000000000000000000000000000000873ea8a00b07efc1db4359fef00000000000000000000000000000000000000000000000000000000ebe60da8a8e2db5d53c50b23150975f807b126660c5a1e52ba0916681c0586b6de121953ac1bec5cec423ee5495fac135a1a16ad24f42f62d37b1baa274c078d166c0cb96da40c94ada121292b2ecdcbe61d2cd8bb38f68d86c6ba389d3b2624c56d29211829e2fb435a605cea04b58aacb5525640e7dd9710a78880e6d147745b74a4dd7e6fd333ad05aa65672e9ccc3776c30df7111fd23af7a4dcd4e525785427c2d3b48b95403085e065292536781915c66b2200000000000000000000000000000000000000000000000000000000a1b109d494bf80046c183e6fddfd30f45e9c56116a82655b51ef881e2a6993ef310820cfea7ad3ca3d4b03a0437e586dbf0285ade22228c9bfd0b4a6e09e88a1165801fcaa3bace6d47806d617019005645541af87f84f768ba51374c46b84c118e9b138ae51d3aad4b9bd2b554c438b246e3b4b25e831e1718fc82960e116278b2bac8294aa3adbff8cf6d012777671c8852a2efa06dd2de4829b4fabddca2d8c000000000000000000000000000000000000000000000000000000007a4ae42000ccc9335f2bc7ad3200000000000000000000000000000000000000000000000000000000f67aecc1fd1301f2dff220ee90be9a059583b33badbe3678cc01cbc436ad3fb515e3b052171fa463e036f1c6e31eef7d777c182a501211acc92f6ed87bc7f1f049ea062cef28c443709f5c3db6dd35b0a6d9e19bc7e2d5e4dfa5ba5653ac6b3acffcad4c83e0c02cb5cbe31def8cbc1c47c833862edb7fc5236510d537ebd2ca239a2646026400a6a66b6b9f2666f1f431591873b4cf8bada2897dc589655b38402c358d6df8ee17a0375f78a5372b52c7d06705240628ee488149f1972f8fdd8fc58a15fd1929199eb032915cd464f6b29b51bda2696f3149fa46defc89f148383b21887b299d713f0bf1cac85126eaa2ae61d4cac70644564768b6c42ed3762d7b9f1f286e3e9bf41e5fb0d14d99e0bf0b18cf8b6869975d32eb90f137c28db4240000000000000000000000000000000000000000000000000000000027556429ea5e83f8e8fdab01afd8f10ee8fa20fcb75eb2fa1c813f915bcc68d2e167ffc2ecd7cddc2de40a3ded68e6c617ec37efed4cbe046488f1f80ef7891c6de643f80f74b2fa33e686c0a7989225076796a2a281c2ed87919f43608678235c10d7da626f4e4868b7699eb15f4c8e82f9563cb93f3682b1074ab2e1ffb357cb7b10f8d90baaf786acd8c7694e07f54765ecc537e1b8f5d69f089a944c16d019932d1c151b3892b18f8508d3defe64c9d570e48fb2ab39fcd5f8ee8f10dc1698da04d3529e92f4f50a459be8831db847f6db2bdfbd930224f369a764c1d7b9fd3bad5286520def02649194a80555dfb0ae56b5027eee0000000000000000000000000000000000000000000000000000000057b75a7500126ed03c1729c2dc000000000000000000000000000000000000000000000000000000001790f11893056b98dd75c8abeeb70077e143802fac1050777c07b01165d762cebe0642f8eb8e80ac983d09ecfec1c1194e58edb173a72bd76b42d5f94473c1e3ed2cd0bd6b8fb18ded173e2098834a4906a4c4495db06d27606ac5632882dfe2474424bafd0d9b2a869f881ddae605129ccd745648ee5864a987eadd2d172a4ddb550c47d5d077dee35b30f8a0391927f4d6180de7ca447db20c4e7f0ae9d6df64dc741700c8d2bdacf6fb47879544b5577409d0872419d429ce9e101f900ac52bdfdf80f5c4a479232936e8135a78f61ed539d1235899b982b550e3ae1cec8e23f68e99ec2e8f3daab0c872b1e3e5eaaa153b653e833ef145549f2edcda348908b69d50e19b2486fa33c4b8bcaad350242b52083f0c065925c81dfe718dae232504c0a23a3d38d71ac9b909985c612779f67db6b4b53846c925ddb151b72ce4574fbb516f5d82710118a7d8898b9ccf8f7c955e05310b2d92dca1f9793f7c8ff51e7612d37651bd8ccbfb143030c6874e13c96fcf49c8ebdab66f39ac73b51fd99a996653e9d0042aad8089141704787077869cedce34aedd537e2824a081d616e8f2cf4cc9d367fee8297313d1cb986015f1ec7b66b3b7660ac2e530edc1b1434f08a444984e2dcffa20fcca5b92f7c06b094efdf00e77605e73430079d770b4eddb5a826213de714844edb92336bd07c040ad40c09144415d3e36aa7365888d98f4751771cc5adc3e51de8f595e72389c5d0a16e75a932f217642c2f3373a799643f6bc7aa9ffd533d422806d8d9d88dfae56d8c719ec936456080aed951e9535984d3df654c815d7691c3c00131fc40a8c31f1a0df09a5785a2fbbdb33938a77d0a55a97f237a0b97b92842816a4e3c508619195fd0fd5b5f4b698980e06efaf728ab6c9390b523d5299c3c82c9319f8a09e8da63776a1be938946e00258514b8ea81de4c8adfea509f96554ddba9bbe9ab4d1053a72c32e37ddaa3441b826b3d23fd2c7a1a0a2640ae0a63b4e42d64128bcb441eba69ed308b34ca675e6f11efbda407d06056852f51a393a20e2eedb4775d3b311e893e6fe2995c8e600bd7df3306ed84f4ad943a6c633bb04fdb1ea059a00b1066ac8ce2105c4a05ece4edcb02101d5e2c59dd3d834cafa28554c9f2073d5e345f979dc5cb5e2c17021a654af09d50083d4989ca24609e6f84f44f056a3f2ce6af7674b7614c116aea78fa761b67067c60f612e9da7e671c1ca045eb45211da68052f2c95b020d30f19d1b59223f193f0c3f2e415fcffc7babae3bb34d66b0a281a86e2369f1e86f428d20f7edf2ebbc2c72372df6955c06c8e1e4aa52913c35dd934e82b031a9c081b6567091d82aeba56092478a9a87edc367d0dc3901db866df374605ecfd925885df426d66891df6c36ec8c3c946f69ba08811c4437f200861e0d26a8bc8608812faaf86d520840e0eaca173bf78b2a3e457de9dbab31e50dec191f8c55f8e3cb71369114dcd306b5593da5ea7527756e15ceef076aca4d0268fddaecdc7903a13e53755ae2e069f5d3b17424ce58c52e9fa155a0c5cb88201cc9263237730c9148cd826f3b7e0ccc3346b58a3bcd5528f9990b9bbb2279d45b4f33ebcf8784c5b17461aeb16be121f9a1f23786744c15d5cb1101dc0984f6b3df7db65c8d2543816117f91d8f3aeb5d47f9d060ce097d00fe6487232e33a021e6fc8759bad93e2a4d2370cad829dfbfdf53052776414e69e142ca6ca23848d4bdac7d7d73ebee9ab375bf4042869db5ff36537cb8c559ddfccd127d82a5051b45293374ca749234b4bf2ffd3a33d13a0c0e18f19400943cde7aaecb18def3cb269b7e000fe32c4119cf18e2d6963d9e8989b315d9423f0ab169516eb0e4d63a2e5b872ca14b7fbc39a8b9b4735e30fea05b17c145f99a52e1d5fbb4aaeb862cebeafa33cfce235cf8157fefebf00b7f0220456a909523da21f0e331eafaf24c9819267409754ebbd927bc933efbdc728d142c802fcf847df3780db979875378c83385d7c4e881976ccf2dd9eeda3338296fb28cb8213d716b6a440823dc689a42d8ad8ced64b4287c1fc4042e9459f77a4ff1c44a5b353557eda5ef422ec32b1106f1588a2cfcb936e55616525570930c0f9e308ecd4159bae020cdbe2c53d5520fc62242211971dd5a43788189db3110ab48c5f98a7aa51f5ad6cf8c842f67e1fcf8583b71f31af56387625784a50a38a1b248a3aa57f4cae0c0c8d2c0c93e0ee4c72926e96f4b6141b055aba8895671fe981f6c96f102f0a67390cfb0d303e83da47c87de11e7102d6eb52bd710f59b258dff8d79a7ec187ba70ca8d1af7a3a127350ccdddec6d42d6bb8bba9b5ac65049277edc126c02f928be0637353be04c1f8154b4cf6985092e9d511f205e43be2bbf0141460f389e65d7a2fdcb3b335bcfdc72142b8f4d695ff83be7a50f8c66830a93072db4cc4006313509d6db394cac45f131ddd3e8e1b810f7a86e90ed25156dc653445d5e698517754e4b9dff7954f09461401c20090bfdd08698a067e959eaa8270589ba8243b999f1788de6465d6a85a542aa8b24f950fdbc8e972503074f3ec82798d6bda5a61ee0e3d512d0cf06fd7a8c9cfba818df97bf2fdfdd0c13616e2d04fde64f0d599921baa5113bef041cad95f4b6211548b9ad834dbdf91e258bea7a64484b7cf3a38358cf30b75e5f19fd17aa2b08cf200f249357f2e8874b39edd0800f67d68387e8b39926785a40a74f8133ea42e8577b0acc1171136e56c7be0bd147be8c236c3541cef4b32a5073485b5844adf7ad41472a1712009bd295d4da656af34b59f31099b22964e9014e6971752f74e652b795b1875a9e2ee0f7ab3f4276d4a3e1b183fbaad482ecf6103ac874248862cde6960fb8a11f7e69454e74ab8de6a1f11cde5e65326067fc3011ed9da1232df5e0fab0d5a542b696b20ef364500ad79f6b554a77dacd738355554bbb9f39a9ab1c2e7aae26b1109350db947f6194a0515578869a4294f3e57fca14e3e1446ee2b120cd0c3d2e58a8df857fac16de57c17ef040f19e1e1b5064d10b0ada94940e8f607a15636b58e9b3e1c102e8975ec0d9df8c0ecfdb53f96956e21d78dbd507eaecde047ad065b3f24a7b91e64b9f175d5aa5ab3d5a6dbd192610982e377872af8a1302fd9701b6fe5fcd0fd80ba1dbfba614381ad6fe46851470ca688db52a9bec295848dc823d3ae6669809bf642f1e9718bed5d338f358ea556bc39f3fb3f2c13e175f883d30a77b6b3070b4dcf2a90b3c7748c594c820ead607a4028bda4e75fb9aa1000097492bcdf5d895908a90f7b86168ada4ea94668a5ffd72728d81a11badd5f2db96c06fa042d7cbdbabeaa83d1a95cd0d29b8c39918afc939a7f90f924d36d0ee823d31fd7541f82071a20115b8dae1918b5ac923f3205e97e35f01419d152c8ed004d48d638f602248d1c2b36acde460386173ed9aa7b6eb6a123f5ad362a10b82433724699302041add3997ace66d9df208880bef12ff706782f3b0308327a8fa29fd373c141b84b4c35290ac4397170186cd95882b717fca60b68b8c678d31f59b0002c9b57932fde5dce6e97b9967753bc0fe7534b4c0ee79ebd44003bb9a332c9854b4f1e041a30693111d74ecd62a3dcd311a1e972fcdda7e8591ea626aff739e0b681e813dbcf5891dd1e2a72feda409f71c1e151297618a3ed8cfc51f615e2807de037aef841c6bfc46a1b91a933ffe85a59e44912334d8ea6f4c569b6be0641de5edfbad3a64b355f3b92f060e2c340f74f2de00f6bfc08c1a92fc51a1bc999a6cdb867e7f04fb848607e6d95dc5a02353ba856321b413b6d1eac3e808f19fa52552eb6d481d54e3d14edca29c506591ea82347cdb9956abb01db8c033dd38d23ae7b9bf48fd38488682868bb47dbf34fbd9de7457bd15b61caa0fc55d88e49f5c542df58b01fd92016cf5afcf22685e402d27347a809b3230ccfaa73b2388911034537f18fda34c8b42f931e00ccb6867af0891cb34c3d4dc894ce66781f35f7fcdad63e9d62a6c0db6a6ed37c96c09e7319bd128842a559d70d51bb7b277d0ba2636bde0a9542151511054a59e844b275d25e3cb3fa49d78e5251d8ba9bd8041cf7f726f0be3c54aec311a7c34a94e29a3c8c7b87b0b4ef6807c423a8cf70825ab3f098084239fc44ce457d3c67ccde24861e46d22754819371106cd1a9ccdf84d6641e96f3ac400209bb61302d479f055e42c384f7a6be8468e04ecd1a785fa1dd2eb250a9d7a47af39cac8e685b40a46564bfb5454190bb6d5ab6e9cf6e1317b7dd4288618f1635994a47091956cb7e1894bc3a3cd7addcd8e524ed8dbd1deb9f6c78e1f3bc1988fb7cedcfe3e25554a4ece943bd54279dc5647ca3448b57c1ec729b5f620ac557a48042e3ef811947b210377b6e0cf5d55db80458886c627d3a078e954f0797d48d58ec07515f617f8514a2ce87a5fa25826227889bb27e854011c4dcd2affe59c03971c33b95006d27dca609070ccfd630b04fd2301bba78e360591b8e6e27c9ae167697212c1166160664b20b0799708d1b93c02af323f46852e72158e205587367c103a861ba5c9ffc4eee63cb43def8c3e38cd70ea759a5e67c7ead31a412b2cd5e50e49621228acb4b88cf46ceda11df8b90ca79f5fe2a373f884a8d742be4c0cf0e125499a252ceb6279cffa84c4c184a7097f548fe094a5268aa8bfb7b625dc41e9d2dc2f0b7bdb27712e6e7cebeb2a5e1686f512c807a14bedd253610bd520a38b38837752c3acf9f39e5e1671b099f2170bdc38dec2aa556b701be61b7945b783b44c3c355a87b5ae3dd9ef1f07e077335a7acc7dbf0f03f9dd664c881db172fc237e8c603ca6b5650be236dd3371f866abefde781dcfcd87ed58178ecbfda0ebb37ee015b01e7635152222f23fbe961401a1b6a2fd6501aacd7037576a0d88fb19a9a0265a19ed9c5e1d4e4e722f393b5c1a0c326ea7e3c41e0b4070c59ad1bac3086b83ee661b16ace313348493e09c6d36d6e056b74c37492893b0b0783dca75292596644b0351d95fd870c89cdd6f7c6df57f82f149e321517664354974be9fbe8a7f4a6752eb8f68ba846b6956b8acac038e69cab8a65a015911c1a216bf00d41b75505942c76b4ab03863237054bd0d57ea90ef2f3d1525f2487101677af9093831e0d1bb239cd73ebf835c37bcb19cc39e20b6fc93fc03f2ed1621b41fb36af3fbf071fab21124fe86f1be673548220ce0691f322dbf27125867f7d424e878a427c15898800d18976214059fe37638192cb3deaab52a2514027cab2c0e9ec2a08b92f00418a2640d8ff7d9681d68aef4051a58b2539b4641a0464316651231b5549595372cb0323e81e180368a1506e0cc9ccb901091f27c8aacb3c05a9eac8bc767db41b68431ce1e357238b40a62a68fc9652cc13a56688cfdda0198b1900d19f27d8604cdaa8e0197e9fb9faa949557d9bdca35e97412acd25d13c23a6ab4d5d2e98e1381e499d0f429d8eb53abf92fb94bf7a057c1d4c55c10370098b20ba6b2197078d3919c2e1c638f6ce98ea9b9e7bf55e5ff5e36cb6148eab6575e11f0ef0ea9014fed6db4c47f9e67f203a3c404d3b24d4ff7f08468734b58ee663016bbe7bc2bb97ccc5f664fae40051b68b459998ff4541dadda2d18051dae13ab498e8f807ba2448b2683c653a7876f5c17ce65c91e0062ff6c316c8ac0b22f48d884b1d8d89f43be0fcb394c01139fdc5d6784fa05d7a382d053aa1bfd0ab451de16d3f3c01e1a555047a7629ec4529879a6002385e48157b1f315d4718c7f557067ff4912b1a1b6846833211377caead54180ebd1feb05e00845fca50ed10c50d18637c4997eb205c11f9352d74322ffbb0ab34d00d664e7e2d5eba513c93ecfc9a17adff0093a0c7aa1555ee5b4a6fedbeea988b7e109a2ebeaa5726600f3d3679f0786ca9752490dd94081eb9172a8a4d6f54928e4137e02976565e4f57c4c137e117c8b19d1d7f9482630d676227f9403d1a1fdd525f3a3a4bb41271bf0bc8400061ec7ea3a9be19c8da28298a460f44d2139976606324b743e7cb21ac25cb9cf4fac8d9ad8240a96b8a04e542fc6b188c2954e96fddba1a03422eb8c1c9ead858eaffe47354441d14be919146472aeb160236054a9b1874f7bdcbc2f5f3c9142de5d2ce0af9a90226f481a3147c787179ec1c8e45c283bfdfab4ade49817c04d28233bd2b657fbd63d35acbf9233d91c316dbbc3fec2a86417d5002b96479aa7be6a93c02f088f1f2ac9e10b21bf117f69a342dbe7b1d81e70900cdaaeb1e98998b793cfd08a6e68d9cb7d94b777d6465df704bd95e88569a50a036f593368ad3110840ea30e9da9fcae0be665aea09ff5f996e8dd009f3137808240b533183148c042b1b975ab143177759be8401edf4df446311be64aa933a974f80563a768e3fa7b9ca25dcfd9236b21e623634fda73ad79ee0d9daff1e0da58e844296df730b368bb1953d9567fdbcefa743bf5af9a840760224f22b174c34bfa8fd7566d362d7cb41ab19ec6db5514a647d35059402cdcdc2aec31cf4cfa82f494ddb2c82bd26a0059b7e8e0749f9e56165189fee8516e2c45e74c2c234d1098bde49cadd80abfb69ffeb46e7760c3f3d8294c45cb2939d435457e39aad3335f1277e640d4e594c70e4aa1419cf9dbf1ad818e900d9620ad79116a52740e9b3c150509f797e59008279a28e92ee9068009a70d93c108d19969fc8493fe461fc636f0a6294e671a6bd7792d4a3f31304fd2e015b6a8ac5f9b350ba66c110d09793f5586d8c14fc3988ad744b0a7d7a11378d26b03b14a5125685cf754c3046a4f8bd5801fc397f8865a2f075898c2d8d7b5261a17b1f2612ab315cf04d3e70ae45611eb90f54d30fd4e5df77d6a23bbe173c01d832d248de4e435181c1303b6deaf7cb7edb84ba1fc5d8e12bf204827559ddf22c63d4d345344725aa1c9d1f58c4e39efbc2c21f7fbff8d25b15f1e415e72b2ead357c79bb27ffd99a0803945285b58dba10c428162ec0a6fa8d39f77bafcf212a2fe3a4e117f87d670d6a1c9665aab94dc91bdc6d5450a7997dd968bd3783e8d290392aa9c64a66ba1fcbdd9031b8bcb80b2c815aeb8706fcf05e6aafa49142e8fe584e7ea14621318fe341d5523c4f5eb96453a7d0d390e2eb7879cbca73316443f1fe3c75ce92108b230794e30f42388e0b35a41fa064dc655ecc5fd0f1becddc109345e0f8e923fa1b57763dcf79c89047e326ada66ed63a94d4e24bb8a8f0040561e80740f608656e75c15d06facf6e348bfb3a16c618a8dbdbe09e46209e4921d2f17d6adffbe04601f387744dbce24bbdd4fc997e750fad11c16fec7aec3d8f22d4e2249bd0d2a1ccf0eda0dba7e3f1e1504d76ff4d661aee8b7b1062f9872f2616427385a49fc06168284900fa1c00b21e76d6d14571d8ef85bec6f417893c4fb135a38cf1d6d57f22d61486afd92af96b68bec690230b995aa18977a11cce699fad3ac29a0b1794e73a8066d71cf7fd7218ee9cc9f9e3727517523ea5a1e07c295600408ea190bc4bb45da9d50bcc55c4512f3990ab9ee975485207ec54885f28eec2566e28af790cbdc375cbd105de246305ff0ed36277f928d9e421add9d1b8b897729fc0c2adcfe592d16aed21d99659b67fd17540f3b28e3b83cfea71a8a4d5acbf25b369a8f709d51ee1af3978907879b478b54cf37533bb43c77283ec4572baeabcba5a27fac46764786dc1d2b87d9d9e6904e6f82074dfcd1e0ca8a12762506172a90c2372c816252b1f9e5e6a2d7230b02d940083da713a33b179b0225f928e34e57100c77cb8b0d1f0fb4aa3ae19110e25c8c5d714c90202323b4fa950036fdbb6f35ebca5cce4a546e2864a37537fcd5523d8dbf8e3d35ffae12391f71fef2f5833d20e6fb7e313d4c782d7112221a875231cd54b163c6fe8f191aaf2cc7af4aa2d4c9d233ef9115c23f56e6ad7599bd827fb2d879326eddc235505f90a18cd3b6ef684fd3989f7340a56535b56fdd4013ff579f6cc1d568b4d52de4164d7ada29b0cef596e02b3186988580cd936e2d18242022c825e195b81c25958b2de0880d897572d864fa17feaa1545ec0c125fa472d2b118d1591f480a8bf82a653734188427d03cb86143d18ce6305e0476a2d8748aba80c48d9b9b0cd9242ab58c53d702dfc447c6b17346d9035479ef70a10f8f5e0089a9d4bd687c8a74f0bb71499f0637d44913f461b18f7560c2888ecfde3899b47920c428f81c788ddcd0fe2b029dc2e31565c92c21c2ff254a7fe9969ebf66a97981dcd2f91694278f298520e8ad070a45d845b34148f9140d72246ef0f9a88ac4ae501d6a713ac6a600f1585823b2bf389b3fb63788ae8fae1ad486c530cdf32714c8d24cffb019bbcbe055c95fdeb2488e35552dd66ad14d0dfd7f2aef2c0e4893f0508b6b3d23f828bb4592bbe99ce12f23cc00a025064f361c7272eb2ea5c38a8036c34f22b6cca443aef1bdcfc829906dba7acdbbe3b2b7ed996f1bb33c845239052fe8c8a13527dbe53f47b9f6c330629c33a217952bea341195b91d6dc54e5af843c735defce0371b7c51692c5c23d180336a9f4fa025a3280707d1b0517a2cc46fe91f87ff18ce80529d24bce9cc8360933772a4f58a7a50c0206874ee44484ed37002ddb8aec3a9c1ada3171fd410132493ba7b1afef487bebf0919aea3f563936532938a239649d0e6b804de475a150678ec2894970b8cdb0816a4b2e159e4ef0badfc7f7f3a632cbd040f5da4b541b0f2cb29cc481ed7275cf5f4b779c85a9f4bde812bfd00359c4432612824d7b6712196764d3f563de3849dec3c8db0c5c2a4a233a1191b0eb4d3b60ecf51d3d4640aab4ac83a25ae7a3785530d7c6b81d1e61fab8edb47f6afd9ec80e6d76a5fcbbc17e01cbc000f2f36eb2e3f74f2bdf06980f0c64e27fe73b42416de02c60bb81ee40a7bce033f75c7b7a7cedb35869075bfefd60eaba4e5447d69e4800dab388989cc027e4380c7ea2fd50d7fb4039a495ee1d40e94ff76402972b0c57a8f848e7ef42943998da34e682b1037a5d4f5ceec82c3226c1d0538cce2b9bb73cfb78ab7f8499d7540a63f9b07e0df3a253fd55d5f4306e1f81ba697abcc76cd95603fd3401319dbde87be7fe0f760cc92c08f155ae0a068f04193c1e7f98846a2e256f087c8ba5a9c8189908d10bd30606e5f685e92a8eee8eafd622f1e146d93044eef53395b1d3368a87b4a6b27b11f21cdfaf75cdeeda684f0ec7bb91e04472b19bec99174e6f996435293631ed0770dc9cec222f089811da05e4948dec445eeb508596caec3f3ce738083a2041cb976ff6b5100286587994ccbe31edb0fba5acd1b2a69d4eb96062a2f4a4b668d5f3b5a71a7586ea8296facee1b5b4a1d9f592f0f161f1588a05057e35467bc2628e18fcd927e152ed89d84b33e9ef68bf9270f4f593ae646ae660806c27d00beb048e5dcab3e999dcc5dd314069089a26a5dfe5416c588970433b10771b114f27d6e1b7cb57a00cb67f2ea96540bc68067b9038e4ecb1e5052e2b5903b6a88506960526c71684640ac3d64a0df67e9154d4161dd90eff4a55e95aab70809566b1d9e9905e80d96414ff7413b72a0eb202ea5c1879eb7642919ac939cbaa254847f4d281109acb220fd2e88a52dc76f6b6fa5cf3efd719a47b5195c1be675f38da77bde91340994588259591aa20554c83ca7e37e54c38bba16ded6b31172c160a49e2a6a26ba7b5ff677259b0e96b68c6bde24c1abdcda73a1b816175d6c95e818862fa95fed7dd29f84bb08e97a4649fbfd3764f37344c7ea8bc2a2567feb3cac0751ee3e6a1453fcf97705db7461a5494d244c8d52d295026371910fff45969fd430156f589ac8bb42be8ae75382bc6077b40a5fdc5eb527be66a2acadc29af6694f94d2abfc7bd6105d1ba4134eaa69a98e27b4969c5d6606d1aa4829d7994f6fc3d2f036bdd39bcf1c6089f2748b4420cde9529369d760a86ddeb26163b5e6ce06bf33fa7b82e18a80086d0ef8b54fb352628609b60906bafb2ce0a6be053ffcbda67a546733d99b441c61f21f81291021890e62c89b10e005e58dba73a05b7a78df4978513fe601d89a9ee643f01fb89bafec91e5ad17bcfe72acc3b7bd859cd147d0a8e33ec7ffb00e27c64a4d274feb9a4ba79c17f7543b6a216f1e1b5ca009af538aeaa019ba81a1fbe311afcff9f4f9f182cab2dd18eb7deb27fa08caa9b0b23e4a7d8ca66bfb422eb8846269c6dcc57ec8e6ad32a273f2befa0e91b635d1c66e9b1e00aaf33a16122d4ad0fa1514980f6ec1ec0b7858d389d6c67a15789eac530bf01826d18e0ab706b453da60fe055c9ba5c1df31f3b9e857f3b29613ad75a67c9cc34086b6d7cd58034534940e91026a8cf93d47ce82163feaff45674768f7e755b8743baf4019612c1958328fe9bc0915cc64138668b302b5d118c865ab48ae12a58be525c9d49a4612c376118d7f27e215df8dbd4ee6181182904d6e92330b61aae1ef10045ad689a",
"spend_index": [
0,
1,
2540305684,
4294967295
],
"result": [
"1bdf87717a32269847b30dca87757d9125ae7a4a7ba54bdb5094bcd3ae8c1942",
"8fa39fbc122b1e2d03f52b209358ccba778a27d2466ab4b7ded97e042c2d718e",
"a985ae74fc1d0b42b8f04c1d1a49e2af5cb2dce04e1a9dd1063110874de5f091",
"60c6438d4af02c56e3767618189fd4996076ad5951120197639c72d34f5e7684"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 4,
"Witness": true,
"Version": 715592854,
"scriptSigs": false
},
"hex_tx": "9614a72a00010244487a8400000000000000000000000000000000000000000000000000000000cd90855900c27120ff4dc0679500000000000000000000000000000000000000000000000000000000addd625c0073cb3bbb047a8578e8670b050dc8e81238df3cbc31c53a872208d5e486c4c6f0c8e42c6bb480593f9fa346500640a95a38ee4ec7038b016778eb46a445eba8fc434859693bd099612e91d72d0a8da21ece89d9a0956491083f2daac8945aac13618c531f63acf3f423ace99b996e936bb91f6f532ce34aef686ed4561a101829d37a318f399e8927b3ddd93835f1b2f4509ad45c07aa2618d0bd4918d77f9d84da4df681ecbb96419fc27ea8dafd1f2657f039d6bce777bb7027679fa6897fd8a3d0410d7a71ac5e914b8dbae0246db86c6a03d9b3d0eb8dce9c3f3e7831c8bcd08cbe5e3fd00991116e8f98776590e257dca41919059ae37ac66e3d84d9cd38cb8f0e9b4f76dd01d3d18f0b8a8515163edd7f2ddb6a8dd67dec94f2cbe24c430fba044f7f938f9a3c6c8ff3f80692ab19cef56cdfaa5ad05637b3125d23177ca41495fd82c673ef78c0930fe7d349f513a4a21a3f2f0d9379a9df0e87bf7e9f1e1d0f04f18a735da44baaff3f46e798fbfc107393be22a7fa6f4115fb22d861ab986391c9fd2a9afa441c8db8a0fdb5bc6192cf2c0ba30e3a3f0ce9aa8df89b9afba0d8671363690a93f4927ff73ac81fc0c754a05e6cc5aefd1e9a6bf163d5359460e4ef58ce9168a65576d42e71b677b44da0c72c5eb6ca33a0e363200bda6935fa89e898b9fbe26308cb5227409afe818c3c17403834fca308fb4375db0bed101aab9344203a01629f7deabbf91d91dc6be20e23bf9c09a8a9996935f76ff3322675f7b8cca0bdb46801f8a9dac35718b91ba7338b78cb25f696dd0b61316f8141c94b5a4c78e2ecad292de849c8b9fed939bf509536d01245079fa9516e18189b213343a8f671ed293f2f68bbad654baeb1847215aabe8b0148dfb58905c8d8a0ebb5d60cf68a86e9e3c0c10f4b793d0cf0b2d572fc6b6e07b5561da1c08f42dd827119ed706efc184c781d5938c810c479960213111190b658e78cb2488bc6daf83c3d344ea9aa34d2aadc0729b133869a1ea92de26275993ca80eec33227fa56c19b0fefc7813c0abb06611fd75038d890b41337ff607cccfe5211006eb8e8a218270ae41b46891b46489e58aad8ce43fc7e0b1d99aefbb618c678e74a547d85f461db91b3c3a9dd35627cc247099d7bcb26c0604ca8a6a893dae31171c026e8287f96938fc03fd240130046afdac26ea6e14b194ec5d55c92aca669ad09a3140e600351a34bc8cb92e8267e4f416ac60181f1c3f718d225cc9034d2bddd624823fd5a320772f7201009c0f2f9c545284a9acc22edb78e932e61d4aa09ce09ddd582cbefad60ea3e9e20953549c6ae564df1b6ad4cd2c367f4783dcf7da99d47c895dcaf7a6b77f2b3452f03ac054108c38f9e4cd4c6acd9751029fef96c1592c04016a0a58a9f5d9c2490a1ba9286ef3273c61bda674eab31d6a974e7e7ba02dc3ca62e524e4a89a96f08fa5708461a36c7674588de9dee7c1540a2c287bd5a566cd20b5ff6ff7e3581a5cb326479260c2297d5f8247d0222be1f7c09a58cbc1437e0f91ea3a180b1948ccb0f1de29ad2874f56aaaaab4906166b741494dcda49b16171ba4ff99fb84c41dfdbebaddc69ac0f231f31080af8f04887e59734ec191eac3f1c1a25916b354b9a75ac31d0a63e58c5910f47510821dae0f70e1c1c2dbdb67a14ae08d6efc6a5711c0c6c86355b4ef4048bae9c9f6c3cd5a79d4517ef7ab8c48cee838c6f360628d49d52b9cceb8cd7f0f557f899df6cea8b66cae6856c4fff1e49c50ff9fddad83b3b681c674959cb4959141a3877ff02903aa497ef25cbc936b36c8b3786ac05d71a391b03c8636f82c0d5931b612b75ccc140ec056a3f6028d439db9fd0301ace9b8223e7ca7e00ca9ea447d88a8d6500f302c40e4b13b803d1708271d78adac2b162a30a26f4f0df593f3ea03995efecabd345989970d2defb0a21092a6697d32057e0efd8de0d8599cde438524067b6aaca75e1afdbb1ac04511ced0bbfd4d93847175232ff965bcffc5a07f31457ca97c042c28b7334b7c4033c7a84d0edc792e7cce129c38cdfa0eb9cddafc42a4efbfb16d5f85f2cf3b1244aebf1d89bdf9c018563ab75ed1af53d6260297890daf6c6b7a64190aba1e4ad79819cd241bf5abd87cc989cebb359b41fcf0ce3edf10e2f314aba31565635fc329a8864acaa63be50e7eb76fac299ffed9984dda7b4e55687871d964cc3d311eea262decd1e98e01beca3d7733f03a90e6b04ed560536dc3cb9291b0217597b031510bbc65e5bb3f0eeb12bf7760d7630d75cf8a39dbc7134be2bdb44f2b204576a03d91ee5904a4e548e39345deb04a13859fdf1f3c09b978a4dc2d58e9f461949d16c601b9b8103a5a0b0683dc95d42257e74d28a73de246a7a5cee4103022be8f08141a775672065b73a8403d809d82d9da4d89f67b38e5ab1f692b251b72c5cc19db96ec651183aa5d55fd763119b74a1cebd2c2e698ff797655c176c382c9b3c3c235ced06b696a6e",
"spend_index": [
0,
1,
1848110724,
4294967295
],
"result": [
"12bf734b91f86f14dd3cc42faee9f9f95327d56c5976989d46144b56d6bbfbee",
"68621c4da6ba0611a1100bbf14a0881e2486b668bb51f137a6a7deacd85461f6",
"b9103641610e7fc11a6a2d6c7bf378bdf4a992fb00933a409c03a8f6fe2c39bf",
"6077b14cf061a280c1622f21605f815ad2c68c82d00adf4be7076ae4231f9979"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 4,
"Witness": true,
"Version": -594424904,
"scriptSigs": true
},
"hex_tx": "b8cb91dc000103733a19e4000000000000000000000000000000000000000000000000000000007a4632f6fdcd0148c8d6c4a16389b5a5ca57d5dd3c1ef98adcfc4621f779a4efd7264b5507c6dcb3c74e752fefdd47b7d1caa92a5ca64724df3fecc1d2785e4a76ed3557532e4571eded0a2385f0a72d5f37f0b1f1a5520b7def869940e1e37bdd5b1b4f710a777fdbb1524335da1cc62ab9df1c3eb313d3d1b56b54e833fa4d89b4cb54066e0c9ea64a8fdcbad8758550500256f383d973adfa2a1b39452bd218f16f18f52248b31b23af5b573f40e41e8d2333f9d5cf2a7af2bca541ee8cf3ca940f7d578b33fd13e8b885dac1d10479dcb9907bf667ac32361148ba268668da91b04a10974fee0a7119262062cbeb3f0de101336b71268c9b20c034f57da61a64d21afd3e8cd9193fe4b16b245c4b46b5e90a77b17416d5227383e19dfa72fe06ea6cb09ce283c07330374bce788e33aef9f19d9185f52e5132cff5220b58838deb8a7c7185d6a2218de5995656cbd1ee2de93c035b339f9d8bf548262a01a157d6bca8809cdfa3c97cacf843486a99a7f280257f2f32846504458faccedc511e144f123ccc9adc1e9f3b34390096c20ca467cae4b30baac6796184a9c933184dc6793d9b2b80aba55d56a8ea786aa081b6b867e7b236207cb01e773bdb2c764549fc955cfaf98d1935bfbdbfaf9bb1c34e3738812bf5f2ac4fa3000000000000000000000000000000000000000000000000000000009404b6f800f4e4f52c163d1e4200000000000000000000000000000000000000000000000000000000aa49db60fd2c011902bd5a2d7327eb901214d39999b3b939b182ed7d9fda9ac45661cea326c1f9b5753da512a87f5170970d375af04284fb973f11b32219935f25d30bde60f32ba7a796e9d699327135b718426be60e23ba076dc7fcf93215cd0703d8ac8c4370f87d09fe19c508a2cbad345b405325d6cc1bff5a9e922f683c888edec5e329b970713c1a5a31c9f2788e6de872da38893e99f5a3fab0f45d565ca28ac675a2ade933651cf73358319977995ad840abe4deb94bc99e11541543e908481f72b05f04f9dba08378d22ac97333b431ac90502ba7bb954f5809f85b5fc48efe3268c60d964caf9f7ba726c89fd3654fdbe1abd99ebc0f4f702e30b01056377a114fdb25be013e214d6964a5517b3c173b4e92ce28fd17094450993f53a9d66952e06bdcda1ad36ed9c92cde68183e06c22cd804f3b509f1c7c4ca07c8379fc44ba9d006767866231e4cddd1027fe527f14d60674a861a21f28ceb777d5c9ccf49954860b054bb1327b2681f6fbd057b3ded7b468f911a440428c5d9b290fab62f9b59273e01d7f898e7a7c00b689a4d0be67d59abd17d8e7082c6e66bdca13850fe754b60854eefc36981e45a1a3b6d690006fefcf9fd2521c6737bbfe4ddb8757a804b38110f6863430d3572f434eab01b5f60a692b9da0ff212e63655b41232403d6e4b85367b634c68f5e07b975ab3280c3113a03fa2e8d50c0fe015b1380e8887157cd539e16dc10a5e4dc82209755d5f1408169e4e8bcfaf4b6e3db0a25c4cea61f10ffa82d92d439599e3e594d2511ef4f753a0ecfc2f3e34661d295c73e6507753ba7c7f7dd3d7013bd26e53c71a5441fb85620eebc34b0142ebe4d7bf4aaefa69b3a1efe51e4eb1a72d3b4f58a59b769c5c8882e2774cba2011fbc7326d0dc542b260d5273454c137a2f73f5feebbec4e59a13d97c34edb44d3a4027e8781327af40cd4d36ac83057f0a4b65e89e4c0dda809335341dfab0287f40996bfd5cdcee0a23491d766836c1f9cc9ee5799a9dedc12ce1634a98e2339c8f6346e806db1df93013c11e1c2a3429cbb6a07d0198937853b0003926a6929371c0bda000bafc3b409d23f13dc2b335e3152639c182a65a8f5c5139f5951f958cf4954269c984302ca5ba5f74c939695fdf8351bb55406aad1a0b8a68ee6579e2c68955eb94f6d883487497966f89eb3c5feae5cbff08bf340af79d58d8c3cc5ca3e13ea626961cef01c55a8faac81440b1b74684a57fa715238b1d8c94c63236766fc25fd9f271c383b05a11e7489b87633a4324b85846b4487ba9dc62d79492b8d9805a2678cbdc225e7a3f050d435c846ffb53ae3f839021229acd939c8f82e3dbe86e13c6b2baf38d9d79aef51db0d0acd1324967c7fdb5be42bb84f267e8adf0147c3b31ecb979aa31328b3799a076d8400d246d5db9e31ece5bbd4eede1dbe477f420023f3f930a0f4998b543f035b2608e618f862aaa7395256a617de91104b19e2ecc4ac3dda6f263aa4cb008f7240fcc88c590382ccd2d8c1c6194c850d2591e1745e2d53d9d8fb183e28d2a33cf81966af225f0a1219cfd6e1da9a398099dff30571c37887d8d0f773ba1593c39f9d2862f0fa2e02fd710140009c89fc7322fed7a5f14728db863b9ef494fcf42de39dcd6e46508b0f2e000ba263b93570ee6f028537bca50d87c7e22ab6b8de23b350317cc9bcb94841cf18e7eb68b8fdbefb2025401bf2127c417e996a83ca6b74e2f4d20ea1730737197a6b78d1a057f8d67d67ee0feed3d0f30d6d1cfe9d948b7f0a86c6a9abe525fe4b56ee091ad0645ec29afe83581ba0fdc09d1b0b37d41909f6c60aa506e658590205ed2f454007f46c2c4b45d799016df71b664595da3df4cf08f6de7405563b3035809d80cdd027214a850f7757f029d2d650f349437e71f55b2387ebfd5d3e0d3e250380f6f576b624f2f11a964233c1fa3cc197119aed41f7e00f2128d29d77f90c799f024fc0fbd3874b349c7c3f3f8f5eaa86ddc39e4cb5cd84bec069e78b8a4f121746a5a133894a41385a88f2df9a1707f91c2e3d711bce65a32ab79a120b133a0ec8a6760f511f04016162d646664bd2c6455c79b7dd0738c9171f8d8c108c5ed2ab434079664e2adc222abcffa4cd5adb4a5ca7319ab0992c74bd8ed244dc153b58157549fe6efcfd11dadf190982171b13048d0d85fb77fc79d1b4eb8e9fe31690c6a452c3872089c4b472ffbba59565aa2bcf086161d8aae852c9311ce35476e2d35a99a475fa7f2b4a2a2409c9432bd055d848c2f5cbe4df9408a807a039f8fe0bf927d4d1db654950fdd81f42b4e96d1f7b8f1b228825fa4649d0f506b97b269b0a3c1608076adc62ec5e5ab3ec4954032858605a882b64b5fd43ea52ebb07882bca68fdaa40395a0748655c90d35e62b80ec1f8b12bc92d758fd18010f10e77980b531fe6b9e2ac2c2a1055925d8ee9cd24b0b97d8bf6a7c8345aa410819a86115ba04b717d0a92939bd79c564564700160d098fe4001f9187ca250d880b0880dc7bb7c6ea057f638c3496308c3f62de08988e7be3822bf75d4f757d70a0ebca25fad075d8d131f3ffa979ae3787980143b9663aeeb7c8824f00d6c8fdc809224d2e12fe206949e51d85550e200484c64c0da3fd1d1674b03b5687350793ee567ef211acdec4690a0346460144a4b745b34e7bcc87cb470b4c5e61fcd57033a0a2d3e15e974651edbc2e36be909f083a15fe9b198b3081731d4d853e386ff1902f3941b2de824db6b3e85346743f7e4150b3f69a841886c9d789b15f9f238320f77748068c4b5ff760a6e69a834d98b5a1ea24533e9c10a5af5b7d6d61600699fe39795816bebb6626bfe434ebcf1d33c6fb899ca446b9cbb8fcc29a38b7a5a997425d7ac0b3efffeb344cc8ada7614592df78025c2964cd1fd90e9444ca3e8e40c10590fb0e531aca63bab19e9bce562bffff0a06c22e9d992cfce03745ad4a2bdb53dac2dd87d64edc352327a6785a213cfd9bd2035fdfb9e3c680cfcd45213d2513c7e9dee7863eb2ca087cc9bd4ea9c08639290f32ff31682e07820d044384081e750a750e4cb1f8590cf4736a05731072e430952198800f3e586ba605761acc305f192dffebfc548b18cb91c21751123732547d8c784fa5a8cc952f9e941436617cddefadabbc1b12e90723193e8fe213b21a49933a72206487e43c8f991ac1b556429bf99eba3d130bd13aab01e9ac6281b548ff6824de4a731c81bc5cb328982e7a36f239fddb1dd4007cffbd56dc2892c1d6ad42a6f9cf2ad895ef837ca7273e6d56a48f36faf6a42a1bac12a68d5f22cf54",
"spend_index": [
0,
1,
3958408894,
4294967295
],
"result": [
"17f1939a60adea501d1df741db5aada01c24a58719bf9d2b07d55a27c7bb1318",
"7154f2bbdddd70c4ff507b69d410bc417d7fcb31999a263c91d8bc791196aaa8",
"55b6cc0bf1f740b527d2504d528b14d2f984d341884c92973dfdf2b9eaa1bbc0",
"29078a5f9da6ba1a90c08ac1432132da1a4f3e980113ec58aaba74c3073e4e2d"
]
},
{
"desc": {
"Inputs": 8,
"Outputs": 1,
"Witness": true,
"Version": 337442454,
"scriptSigs": false
},
"hex_tx": "96f61c140001087e9a414b00000000000000000000000000000000000000000000000000000000bbb460020066e56a7726d9c16100000000000000000000000000000000000000000000000000000000a0da8851004bf105cbc37b51450000000000000000000000000000000000000000000000000000000036ffc13d0086d145c39025520900000000000000000000000000000000000000000000000000000000b042386b00f41b6f718073966400000000000000000000000000000000000000000000000000000000a13d214d003936d83037240b7f00000000000000000000000000000000000000000000000000000000c1f53e5d0032f83feea6e61ba50000000000000000000000000000000000000000000000000000000098a6c744006b7b9bea56d181dc0000000000000000000000000000000000000000000000000000000068c7606c00d0ff126e0139c1cfaf06e77e6fc81d2323ad8d445ab4ff24813f6b9b014bfcd828d4f1e90cf35b8277fdb43c1f6c7f8d6c9008bce81f0c36a9b4f2cc394d17f6618e672ecd63b31012109a297fc6d1bcc3802ad8bfb7347e7042f513b97fd3c0f0ac2127367c9a895424e046b5db194fc21c25a8ce132b3f53d82621d0511450386845a0da04eb360f133e6047ddf50e32146783d2acfe5c12aa80e892e4f203b1ca89392db85d18c64a80014b67bacb29e73400476de764834c9a1d4304ad44ce0632014349032b0fa65bf526e2d7c66081964c6ef2049516f52f3e2154e69ad2999431baa121d75db2488e41d7bd5b0cf20849efedcbdcac5d8b4ba43c773aea376d4b40f9cf71473900226ffeb66689667b7ddc6bee7c0e9de94af8af85b9d177317165f8f929145eaed786376b37e98b5aa847bdd95f416722dbe25e08c0a5828fd2b7173f904be99eb2024834a43e38e14843005b9d6917f8761dcf87e57db9a7bc7dd13f8217125c408b27f72a56da0550d1a1c5fa76d7e9e41287d37e1bd84c3b750972b5be044b6001333012155a0143dc25abe04775ad7531ebb5c763d5a279675ca655c52a80cca830019b878151c86af32111546c7e5973da75ed378a75d5b760282f2504359157d8bd69311d0765c723635c80b6659c438650ca6202b421d2922e629d0b3a6bdaddc6208a4ae49bf9229752a8846291d754a28428aae53ce63a9c62bb8ada059faad2647b27e7f5200464361b03a3eee2db8609432fc9f77275ab7bb9ca2fd361c7f0f91771f3c52828ec4fcc12455b9deee62106cf59f415c9d18b39ce909e8687085338c2f81c6c057a190597249c39b63795ce575ad760d756302fc8cfe391d19f9ed10da1e64b016993d25b14fd5f01ae8c13e28f211da8444cf468eb3d85b22f47d953a2869cf4cd9db6c12b78025b7e66cb7f5b1b36a925edf3b550e0682d0e57d6f44bb21a7532b76c6dcaa9e02ff60a38d2e795d934b9fe08c9ba900e46abd8abea41c95e9ed7861272fb2031adbff68a64c20f300422f770f2e70a148faa04cff451e396c6f6b9ce6c4a496396c63f25ba627085f0959edc0a13eebcc1c3e4707f659e6c3e0915e6273ccc89cafad3807640f8e0b1c186582c9f5c287b4659aeaf4bdd8af0bee10ad39ba72d188173f8ade7f34606387e12944fc000c6351b1d05bd64c0dd7994cee575c93943a7282934536836210b9faf05a0aa266fdc4a2dec83e2858c544d054a5ebb05b0416e8e3e7dfb47c675e8262d02c2a45a4713cb1edf91b52d37283a307d7dfe4aedabf59a6222a485480c5d8d6d12be9376dfd25e0a51fb3b7156f50231a672ce1e27ca8c57a3dbf4c9ff16fe005accaea603b3d5cdc90abb616b39a8e8111c22663ac0fe15d554cb77b8c58360b3a0e49ec7503b32ee9beffaee1f075d97c22074fbe28810372ebf67d0a8f8de51e3e683ba281f3324ec536dd2222642fb338c6734e4a21c7f9106da99e2a54f681860cef364df39cb5fd217ab558e7a30c005ccf1cbf94909efd698dd2153a303e7fc8b4ee46dca657e3dd5fc6d90828b04cd67a99ee5cee2f1eb68068d97cac7aac69008bc41d61499fa95da1831735ce3a5fdc5edcda61235784e04771d277bae6f06548a609c164b885ea74f76d259d1c7edb1d7d0cdfd493155025ce691d6ee0729eb73cb86658b004ec6e9bbea2a95b899f7afaa8e29c8b9ea9d98b744a487942ac5e604069450b9986c1e1d4cf4e392c7afaa67ef0004fd57016fc90754fbeacafa6072ce2af42758f4e60a67c31214f0790599086cb75e0f1cbf5dee78af75591ab769be419ffe68789d540bb81249f039f3ab1a57dccd3c288064993db495db279c9f926181a39c35017359214c70ec64fd60f1114ff188e181e7e741b873217b06d791a6065f8e1be48f37e617443e18d497cb725b9fcdd96621e467b8a0a86b324fa01210263a3250799ae2e12232f8d782ac03229b1977a2fa994dd0d19d38cb52b03cb48c1bf4e06da1da5a64de11683b526cbcb2da296bc81da6a11a5277d709fcda6c7a55b6841a421f51681bd60741d9cc1bdd8258ab809e38b2b29bba58cbb50887eccb0953bb6b8f55a2be09ffca0c4b7bcdcc6e9c72e3e38da0692bc189eb922a1dce4ff58aecefba92e64a65dfc2247b79e8e1cae4b8e0fe8a149fa20427d6b986ffcda76198b1c196e29d40a8e1e4bcd492a5b7572e73eb157a451ea1a8838fd48dd491573bc374582ffd5a0101e268d28a667d973d2d37458f15f17389f3e54a5297d947180eb472eb491f098097b927dd6abbfd6f76381f82c9b3f56366efcec7ac3deb41db2db24a8e922e2050aa8f62b1698b1bd3e879af52cbb5f202b846a12bd05ec8331669628f30b5694e81814220093062e3cbaa8031c2214d732c069d42f816b2be2f8472fc7d3c8b7c614f18bbcb20348ef0a8401a087876bcdde9393c529be6fe08d4a874d656ddb7ea3bdaf9ce56f665c0ed2f29aada7956e4d1adf52197fd149353e029779afce1f25f292685e0d4063f412b16b9ba8041f356ab194b975d8cc352d0fd7ee5eeaac01af1f8dd831302cea2bcfe5d81005e9b73d24f78d475b19b1eb90502813be650a643aa45ea8a101527a2972b142b8366f4b1ecc3993efaa5f274a9719cc0ff12ae48d7899626368c3939ef9a7872fa70113ccce16050bbdc1c2fb93d19643f6206641e9a776587c0841112b9b96dc8c4374a97cfae1936b031ead072db908e8814f75e874d8ecb4a413911b0526cefc5342a667d559ac61fe91f864dd0e4e281b505d5b31a3279dc4a928ec8ac983952d5dc2cb6d0ab415d7e020e50c9d9125b443ea20f30f9304067eb920a6017f2f9e71a4f07b4a1aee6c1e4d31ede35d897e2171a009efe4cc90ae37d737799cdeb0b73d2ae9ba877866d6c28b5b8ce0f22f4e92849e62862bac8be7fc2d41aa401d642cc7ed9a7042c73fd2598affacb48d1b7daad5dc6e061d390eb0cccdd5ae1ecc3a456a4e8bda8df96659037c2db23c3091516b9a625247ae9bcdac0abd7a987823d702b2a8a3777976e59ac32243ec83abb866bc627f4d0443575f7624b280286acf94e5a1e9c694820052b0f669556c54cb6422055d116f4fcea86fcdb4a7ab7534ce594a5623e7486bbb003c843520bf3a3f38c7ac8e0b43ccc9d93ac7cbbef8933b0db6f14ce144525f33fb9908c5eb1359c95bca252ba90528fa5074d639bd0b9a4370faf11d6d4201c0b4d6c0d9114f413a8f7fd0e259dd275460d030995e54fda775e4d086b04a503fdb8016af3746bf16cff65cbead0c2f4530ee5fccfc69e88e64f465d8ab44509bd5000579d91be86675a6b2791fe4512238fcdd5424e3ba12590d1a0698f3ab5fa3b3840ee3395487a230b884abf9ee8d801b6e77b2b4a4258016c31ca090dcc9a57a6f47d93b1fe31f6a37b2d28eb0b2a58f79250ce617cfdcf3a6416ecc39702de7372489e6900a2adb97c3a4a8eab7e173afa9b59931bf6857796f942ea25cf831f321c04afb9ac09bf1c15e732533c667dc53da916c447749ad90c805c7e2be056c89d4cc6b84a1986e532af2c08d86d7c25f9f8ff6ac8f3169850693c798532c6feffd10be80a495e406f8451f9d03929da93c70ca9f6c874a2288326fce6587b5ec8eec8bae34b6a930a515941546e34e8a758adb74a8e818eb843d7b30d8d3e9ec5a569b285246449a5089994c69f44bc1997a507ecc2160e5461642b2d9605300aa63f0b38e194ab60e546371fb06469331a78aa516b811ce6aee14ea202309134498b1f9fc082e6ce77441b602d41ad34910346daf10c8349230503a54d937d758a5661100ba17bc2275f1c66c78fd2c16dc8d7157f7d196b25a9a2c580ce6e92ad7ac950469c0a1cbc4b7bd7d9f8f0f5d1077ffdaac3fdbe019ca5d7f0036020a6708ab4fe4ce27bcc795b198eb6be3adceb37d825804579a88f432f183905554dbc390b85309746d4ceb274de0e805b7406c41c6ec18e9ac3e9eeb2b3c9c0b99b91dd63545c4c3d7943f81fd7408c4de733046d11fb2baf0c5730dc6e1b8a865ff1b99b23d63ba23455d699f14a209b092e1c02fc52254b129009be00d0598b6e1a91907515661ec67b9b9769379d74b536c19cf8a6990531f68608bc355f45c93335ffdf3744fda9a83d71d5f2258f226b1ab0c3340883b7a4ea4bf70462deb63fe251ba197ab63e0ece6eb3ee3aba4926de25730c3838a4a44cf0bd31e2847adddfdb6495df84daf50e2e17f7e46fd0238a001a4d7b9eb7d6b7632369a61c6f14a82639b479566ae06eb610333bf7b8b1ef323efb800ff4de1812ef1befa3b69d164f9dcda7b042c85c3023c0a65d7a5ba828a09d4b201a8a79aeb5bd2103a4ac4653f24b71e722e33e86c480bdd3c9756267389186680ac4fb5019c4c26ee8f03733f27720bfc5e21e61270a7a12d4c0027c4467a8a998e94295a20f5597aa1fcf92d913b41617ef535092e35d7cf821d4a110bd1105a899b2da6360b78a02cdb281d358652d3a26d6b04b1b498bb8e12c175d01a2fd9801df9dde52c5e44d1eefa91321418c5321ae7afe08810f3a2c7b311f63f4468879f3b9cab3c53ce609e24e94fc0b753e8bf80d90a1e8c5db717da41626f806c453b99ac2856f923c420567cbbaeed31967955c03e9782e26012d85e2fb58c556cefbb782b0052ad5e2a7faad748e9b167bff703460220fe8139ac904202a9ea095f6b713007f0c2e51a7f4062d3a6481757440807ea705d31b0f582bbcbb21bcc92c68902d51c4d8b2c750e115e4725ce6583b9353089aa25706edb0d02ca5ce458b9ada4aaf5d9eb67de043631b5a334277134f17eee9ca692ac519645b98414d35fc63a40ef2498f4e972511d2ad23e928432cdf1c17ff2191f49968b9c2fbb2a19464289223a2a1333b3b462f972affda45de0669248ed796e6bb65bd547b31830d3ff7680ebfb8a03f3514e73170b233975ca725466c00091cfc48d6d561bb4c894c0c393ea0882f517ba5e227776e9f47a78042394386698118971ea58cb3f4af225d898a9d355e5ebb30988d4fea2fbea217e2f628133f816b0422f67fe05f9fffb64db1e0d95ad7765334755c0e7ae90c6a36b7c5ef0001fdbd01c1cd410e6e8d3f9ee6911b7b10a3fddc7a69757211100d1cd938e19c38ab13bbef52195be90ed215828c948e06b11254b06d0c6332558762f4979b30cb16b5d44286c55d44d7563d9c839aad43e794896c39ae5f6c59d1da00695a25556d61f9a257b9c3b6517b08270e567d5983b67284dc702a166a508bdf5051c34ed68d271d94d1c4cab7d17fdae3fba090c99c306445b6350200547448e301728cb015b3e0ef0c5c73c07d54efd942290ee08f7cd24ffd68b657a490bbfa623f3fe91d8ec8cebedda8827cc4246c450f9f313bd44bbc9d08a60e29e8a6448cccf1c8d78b93cb03fda2c837f7f9aecac8583ef11918b057fd1e6f28a2be0fc65748e7ccb424db21beff9cf3de47b0df24b85fb82bc39820c3ab56af99e42f62cfce6ded2476bebfe42b1559551a6954f89b7d66a7772cf0189ebd69287cc0f4f7a6d3d6366109e2509b743ad3c7d30e1b31b4b4c2fa582c6d04f2e09d880be665017504ff768e201612aa5eb10a967f30267108ca11768a25095443c0c6c557306ee60e463d96d38c46adfe2213feb5fc37aa8564dbb6e81ff381b105d37b1fa50a5862873e010305709d23342e418fc8fb031b59862f9581176e80963bb6ff4fe903fda3012a65baa205b7d619cc03238a5f7b8f9731ddde6870823bd7aaf8bfef5be8245aa6853c9f132e83f5e8492e3efdd9a807dbf1e82e609bb6648721ba15bd3d6bf566b7fee38583029b32d1b955b08631add6fbc93d023830ef70d12722f7c8c98fb9b5bba967e32fcf3c157d40b9507c6fb066b9224d13e74037bcad873f92f6017418b64079106900d37814696e0cb0f7ab8cc2d294383cc7ab2a7402b2d7ea5549ac71f7f34c4c762b549ef6f8baa07f33fc146dbd707a295badda26add005e6398379adf6f9b39b1e9aa0f9c82bda37fb55abd53431c3a063935f52ddb91d52c94b0b0c1c4c6fa2d31f2f5e04ac549dfe8c720edbcea0bb9d9f97e1006b078064626e24d692c5370e67be6af073e873a0761f27ab126f32451b00a320ef456ea42a8f474797ab91ff0d0cb2f5a89180916f366e6fc59496323321c85c4fa3c3e0608af8ba1e9ac0e137292888976c8448c4bcb1637788def1788eeb80c3de15dda09d2aad4c8ed4e1cb71e4dcab6ece74b3aacc5f07d01b6e0ee79a39d38a925fddea413d1d1a57e5d014c5cb5c9dc000b083c9fb5ed3a653edff1affcd7219b57b7241ce01e88a3a7e0f0065f7db7ffb1ec66a671f61e0b41c03eab8409a96f8d83c8322078e69ea867a80daa82bb084f48aaa2703b7211032721a5c4f1fcd3b508e8a6ab8ada0776d296f68d80c03e3c958c9ee4c21f2a89ab2d67b82f1be09b9fb06acc787a9d50529ba821181d27991ee4b322e129565f864ac521048677d2d068a8cc33e6da6fde37920d1250e9242f82c0e22cbf6ed18008f541fc14b2191f6d933bd82cabc1f8b4cd225ca5ed054ebe65107bd3e6f5fd74839b4bc4732126a9283dab4c2bc24325cc63933f583676d090d56a9a1addd38032256e5727d692992225a56b23f6edefab70a7cc0e4c998f63f1ddc0e68dd057e59ad4683808d",
"spend_index": [
0,
1,
160980537,
4294967295
],
"result": [
"c2edb65a3843910c8acaee8ac8b960a5ddd4bcfd62b58f50c7a4cc5b8d82ca3e",
"663c865131db07c41a98fdadc60bf6144caa9f1996b737c97ec87f32ddaa3bbf",
"8d9f467cbb9282aca24a8b49bba8efeed62cc664d53c519804b3ccfe6eefdfc4",
"4e6c8c853edbc3ee372ed7f2040712ea193a7e189e99e0713a48cec8117e4984"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 2,
"Witness": true,
"Version": -208179031,
"scriptSigs": true
},
"hex_tx": "a97097f3000105fa25780b000000000000000000000000000000000000000000000000000000000f7d92c900ee8828a0e9b2183400000000000000000000000000000000000000000000000000000000b046100bfdbe019441f12872f8bfa445d17f90616607523132c5d6fca1a335dc016a94ae83d7dd70de2cd8cbe030ba58488e5631360cac3cba5bcaa10a68bd87bf6d5ce18e635089d64c2aca7f6f2c9064365f40f5873c66631fa54fd05f4720ba3e2057292e8bc14744af9fa6bebe0f027ca27486841a6bc46339e7df5a2b1ebb3d6afd616f430eb383ad807aa5ac6caedf6222ab3f1627c3f8b32c030cd06f70566635a069016144734ef25708f185ce935a993e2775a7f2a30f2bb73175251d8997c977db9b5d9a84c921624a06e7a180c09d2d84f37c750bda8a20036507d60617252ad16e6191b660c576f6170bb28e3d663e40e6281741f831b71003480fc74d8e437bd83332706b81e060ead39e8146696582e086cb51c83131cce25c5de2f74730e60f184791fface969ce21fc9ac64eb9b166ec4285ec090c371148e355c933c99f79c65f41c70413883a4f2546f0f303b844fa094b30241ea26ebc3c9352e559db36c4daf13ab29d87611f834bd49eed37ab81e9ebfb64d383eb0c6ff2adc6f2bbbeefdc8adee724564b3719b9d543bf230f53697df5df96bfcb1a929e9be4985f195f07c00b4b97ccea403489243649088abb34a5b8dd9ac82bdbdb29a10d5134be33e6f83183f700000000000000000000000000000000000000000000000000000000fd3a8efcf80bdac12a52dc284e40b9db3d74be831b67e9ad572141ee9bb1801fd8738efed388e93660dee7790fb483981f8e1664c6d91a0ff75e68b36bba3ec063062e9fc5bf41841aff600f3c192c43e83194abcfa1f0527c9c7b7b715fed2872fbe84c9b5cf0addcb030debaafe86ac33699dc03dedd6f24c3c87f54e5106f99a5772fd6f7cf13fdcb25d4e8023ba4867e72666e58c4f526e2f2c3b24d3518948aeae1bd5f331487821ae32b4607e8b1f1d8d9e33e21b3a46ae09f6a32a79971c9e778587b656f8df55fd78651bf7913bedec1eb98d3921e5f7d6265a0128ac243d98bab396dd78a2635a9734351946ae5d013e6bf7f912be9e0bec689b93abdc22c0bc80000000000000000000000000000000000000000000000000000000010c9f8b707c0fa690adf9c10a15af0bfaa0194c0000000000000000000000000000000000000000000000000000000001653f913171e35851593fd7b8dc3f177d435f7d76d5d0351d3311c27ba9c677e020bd5df2e915a8531c8bba0e037b307c1799a180b382af53518861ffff74c5ca7363611387d3f548248e27d22b5ce473acc247f62cb590ea5dc8c7b7d3ed9647d508513efafc78168d7dff4be1ba706f5f445b7d4e32c0fe7026fd6b5d262604dd134849853955b0f11ebaf618eaba7e2ab56d29bf735b9f3bce5cd4bef65a26baecf830285f3e848db874eafcdc632ee0a28b03d0be14b3e4cbc0b2f7a509d7e89b70a1a183885d81e9b7f3e11c981210149217bc31f4938c31373a7e097d09e4c5cfebe6a3bba73cb675f61af1d07bbc44c35ef2f9262ac4bc8cf0250611ae4c4b1698a3fcf91002298cc5e82faaebce41aa6b5bff6745a0070062b6ca7de680b29d0607d7732cbbc0be090705cd7e467c3f577c7c5fff162e2f502d0b1393d83eea2fafd588f6700574d357d8da7e453a580a117d7a97459137806f9b0c2b842202f576493b8fe9d2085a10f57cacf3dd2f8215681c588b16363073ff26b39635b76abba71890d882516d18f20bc1fc0d19386b20fc24d2903efe5270a8ff31528df06e4d25486003e896a2f8c4bc38929724b9de57e8e9d83af6331310b76639d01fd38011a14b17778860107c4d7bbe9991c9d426ac13f2c16ecf90a54510121a1ca91542b1c345fd3c44109af0917181448ba824ee9a913c50b2ed815f30f1c022edd2b7253306b4540b70e55e6664ff3adacb859968b45821ae0d41645ab293338d9cffb38d65ca8bb1e23fbf98d458e9752f63f47a508683f4234bd45af58ce649163dd1443fce086ba28bca37906a097d9ba07443c4e48879414b11dd69964935cbe657b6c6e974b6083738c9c270985afd8838ac864cb642f24e55dfa10ba468f6bbefea10e02819f0a6d6c3d8a83243e9739fb4685edaad91abb9b2a88b31a42c95bbc806c9009dac3fa3ee83100f805108701c5beb28fa197926b6b5389b0e730d73ca847fb7352df11807b0d8772ecf6888771ed2e5bc48953c3ac8c5ed7690e200b882db04d608f326b7adf3a26edc802d8e6b078ba35b30003fdd80133d4f54c723911263a74670ad11ccdf73fc90cdd3c9f0ad6a1de7b06066633942fc2e1e4193079b0fa68c18fd7622be69eef1d9ec73ee22bd19a03e58201c59c0dd3b2a60261233cbb0ca6bcb6668f05bae58c3e50aa8001e0431e9136d604aa18184a6770d17f6e61ce4586d3aee02e4f9077ede416bb4cbdd0885086074aa350cd7929e946665c857d3aa5dd215939fb4f13ffeafd36f570daf4453e5e6e01636f488a54c489b60e451e736482ba94d627370911422b84fd54654ffbd604ecaec74edfcbaac05bc4f0278a67fdeb3e0e1cfe532ca472baa851620e62c06cb1276643453388f2f288a2764d1032ac7b9a524b9e1b5bd796da47f511dfe7950ec0d87720dcbccdb4007b0efec6e043029dee10c5963640b01d70adb0420e8403c3db99932a019377e0c8d91fdfe6e64d18866b5f882f8c1f0032d19e596596d84cef24068f9ebeacdea045f31ccf73119c81330ee89fcad9a54cbcd463c55ff7cb45ddca3238262f62259982323c1fc4e961b5ae80eb56c0beb48cf4f5461dbe6677c2806568f2977837092aa6deb79d26ba969165f3a3dc134f99339f44f300bfd537d9f4077bd9b60642c47a97f80fd2aade8350c39634759c79bfe117ce1152dedb35e6d0d1a217811dee07ecddee538d08b8d273e5cbfd970189b6e24f770efed56c9c80c4074c78cef8b15c29eba5a06f86df85480e45baf934ac975857b3ddace566dd4b4cfebbb6259ff18a4447b6043289df210eab4824b076a5dfa73c1bcd19e5fbe6b5af679c77508c3aa107c24fd4c9e977385ed90616e2f9b627965c9a9e503ff1451771423543a9cac393cb9d5a8ff2818b164cc43450b19f80d7a7cd92e0ddda053961e699cc57f99ce9a77ab0dbd3b7b0282f16c75af2fd99ee7440e4f304b3dccbf9a0d65eb46c4916fd0f3acf459c95528c8d7ef34d70b0b35fd8f51f0f9883bcceeb38eabf17ecfc5cceb6a96a871110f2c2db111a95295fe1d681bfd942a86bb82debce1aa9b2e484d7c324ad48929ca77f09fd13fff6ed44c3c48861ff87189575e38d47470e627420f48ecbb49b50aefea244c11231c23f5fd796c7bcef7309028f24805aef538edd0d5da266f830650412a96ebf8d6d88140f16433cd9f14a6f7c937366c81ed19e7face8b71b839b5530fa2ffbd0cefb4190fb1e48172c28fa050d066963c76b45607d0c1084c337c1a0836189873a5de399fb48ecb99aaa98f8b670b5949ea5fdd8019536d3cc39af27e65fb086b7181a3500832eff8f48d32822fc817acbf30a955d3452262f420a49066eda432819b4da4de9c1f81912b13c04b6929d4805059c4d023164ba3cb1a2dbbb4d69ed5066768b68124303d3f214721952e65f3f04c5c9e139839564f5039855c81b16f9cea1a1537798ab1d6807d207c15f4671f12e056e07cbe6d0cb134008614c8f2781993ecf80184bc2530d642d99d380559b41b6eb435d0d2c44a03b3226ff9dcf29ac957e9d8ca907b0a6eecf8c23751b6cfed7d28ef413ac63396e1e28edffd97e1d81c66d9d5ebb4630e1e8e103278c63b8b38a5e75d12d53c35c2e117d1d94c1f95521387cc01107aed86b5d4b9fd2712a0923faf3c6dec60dbed31bff0df448712f705b875bc3a460e82b276feb64b9bf620e037ac8b2398c439bc252486607b41e28467141cf083361a65443ae895bcfb46e69fe8dbebf901f8faa379652caf76c5f191acf358e093f707e1db4ba52c1de9914e75a03e9942bd7b78b582562ba37c39341ae6816a27862dfb476eaad862e142066127db08460ac92b0c322a281a18aa854698451b1ec896fdd537b2d335065e333a36305ae8ada624192459b375471b753ce214fdba256189bde018aa50b4cbb9d1fe3a73e6ee659679f0fcaaf697ac5ad9591b7a1c904fd99017f67fb0f0574169142356cae3dfe973ee4d3d2ce73955cf1217d6068d564aa0347999256e26be6524fdc78f0bff86c96978f71426b13dd7872c3ac7bcb03bb7d246763f5e1cb9ec08ee56e6ad6fa9d7e66685f2569336084b18d9eba14dae3ed3d39b9963c72de173ee6c03120444ef84a5c956c42c022f410d8ab46f7ccba2a7dd71cc829f0e891edb84541752add870837ea5cb2eb8f7117f2237d8709d83ca6e725da307436930639123772cb150c50945bbd2d7996267d2646950654126abc294311a16d4ff5628c117620d3a4bd4aaa0f59435fa240f0aab0dc2f49022b79a3030f6fd5c65a93ce262231c84ee20d08d6fa166f613f805af2e5789107bd7c3d7cabd8a09a824e9a68829fd57481613fda02cc23d7c0081d73fa7c981b98ad06af6e382f23a51148eacaf768c977c5b174613eef34e3b3c8582815c8ed70631f4267a585a8696f9ced6bbe7d92b1ec17892be40a8d4aafcd1c4ae7f507e4ea9d10200c27f7a9e4ef2d35254f87b64470b37d1c022a7805dffb2c76964bada340e59e38971d43d0b0c99b82f724b0fbfca72bf8c5211988c0231d9852c5f4458a0878c0ac6b46d86e8812941eb6da4802cbaf8ec39a33c951129259a6302757e85c0a27af6ea7d07d056adee32a1cea48f3b69fe760bbf7a10bcef05a440401782e1c63df7aa2ec20982ab3b50955f25d5d155dc9ea7ce3376fb1c7f3e3d7e62ca04a15f1652b255161c5cd5b1d503f7008a3092dbf623dd9ced7ca3012845a92706b0a65168478f7d1ba6261820b48c678ffdf5eabdf17395c69c8163b3a2f56ead84cc91a7eb517621db39ea42a3edad998e35a834d8e9ffd3901594ba8158ae19f276b3236d33d81d02b17616276a5f3fbf57c419b9900003be3894b99f5d3cabd4a9226406bc5a8e1e82fb0843d1dddcf95f397c969bfb6ac625251062864b5a3cfc6cd18a031ab61caef73b82a7340f788a1af5e2950b67869d73ddb4b6fa69f1ee21e937a9fec7b06f5cfedf41189e448dbf2a3f7ed7724092890a34544630238bec759e6cf7ed512cb492a2ad9ef68b2079e928bf0c5b335c07e96048d028ec537614f034844cb018139b57bb1995d86f43b63e51d090a4fb259cbd0c0966a5c4fb56f1f96b9e03db771ddaac205faa89d6df5866254ee8bcb9667bc339fe4494a2f1ef5148bd51853ca7fd1f2d639c87563552fc05c4793e5fd3edf37337406c0d466c35294a98fe53caeced772cc910e3000ba42f69f76a20d0e3ef987702f4781d214e2142767164533ec437f31992846f90af1f92339dd44c445f43ba87bc400ca43567c9c1bd1231734aba642e1e2e45c10adbfb970eb4ad64e3c7d9d3b1a3a92f628391496959ed9e0ff99bfda2bf19e9087dcdd4c049de6d5a11578b940df9a216e070a82f8954ed42a45a8f6893116d74f15142b45da7322d0d0575aeae811ff1f05f9283e2a1eee43457e714383f25031005f7dfc1fcb4a4b6ead58a0096e9a0f68352cfe43afee9d695cdea3c6fbf4646e2c69059d28ca858d8bcfd76755cebe7f3b616067c6a9bb5c5404922a025d00565c97cca4c5cbfa9d950466cbba17c7f12fac99248211434a9884afebf72e4156a54d33e2eca6c46a8eb5eab25391ba031bcc04abf76ef65f299a10936dc20b570fd50b6a734b9714cb8bf77db282cbad866a8891857614fe48fa738302de7ca23aaccbb3108480f425f92f317d3a538f732d4e30f8247be738fd49577303156c77882d7b85941affc159095c62c515365ff603fd3985c4fd1598e645d6a56096522a3786c24c8b0f561fce66df51d7e6be34f7fed635319c3d899e66b18a82d05f9064e7e66a82b1694fb7503562aa553d097d5f4a6e78676f010285c88f27b5a0b3e9ecec27479b55328efddeee4a7ebb7d401c9a7a7a2815657c6cc880b6fd7801f36b79fcd809320b14baf520e23c3065e7b081b4fd9d55c0e7e492aad3a8d6abaf2e279c5c89d7d158671dd6138244863c75036684cb8e7fdaf3155d90a694d395ec3d2770f35ebca5880d3183980b691c498414c40d4cd1e084e3c36ce1c392f92b297ab63e1d9ccd84ddc6c45ce6cfaf39df8a834609ed1c88e2dee15020070662022886bcfd4593c8300cee69c0b414df1a542cc8efd80aa0f6a4b868abdc0f6fcbd35ef79e10ff2d5fd072ca8d082821a8329c8daf651237426206bdd82287524d6de21f6549bc62738fbd1a2bd66b9489ff3a769461ec53761112d6f1fc16102a4a66e126cd354320de2558a54dfdaeba713d135d23ae2100bc22b74680f69275ba8dd04200e27ef2ffbefa0509855785c6a37223df654b9720addb65be143cffcd4d0796991a4a683d566325b70f05caa668f730808af646c811aff91621cface8ea17f2da5dd1fff5387e65169ed16586bf20c9e8d82cfa27c0a5b88a7f9ec982721b51e810e19a27d42b2b211684c31751cee0e69dcfaf8a",
"spend_index": [
0,
1,
2519856964,
4294967295
],
"result": [
"ff2086489bd8239a77392745c1d4709be47f9f3a622cc0185e70767ce8c7d386",
"7389250c5334183c2ba13e0dd8fc2fa16640d07802418d63b3edcdb42e43d6b2",
"dae332e69edc29fe196749f4a8139cdb401e89bb7be4322da29806e788ce8608",
"83a6690614a97c4e9bee5a61b6a6e8fdfbc956ba33c7f3411320c7f3b20840d6"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 4,
"Witness": true,
"Version": -1769011343,
"scriptSigs": false
},
"hex_tx": "71078f96000104fd70808b00000000000000000000000000000000000000000000000000000000350b590700f0a00891899e8f4500000000000000000000000000000000000000000000000000000000f2cef4c800a8bd1f6472219e52000000000000000000000000000000000000000000000000000000006dde36cb00e70ec0c43d375bcb00000000000000000000000000000000000000000000000000000000558b89b600a67d6ee704a265e2745ebb9524c88857f1ca22e99d95d20f3e2a996abf3ae45c711e2b198c4ce1fe79ed484a459260dcb6dc5f0bf6b71ccf9fd93e17b414c03906b9f38ca3db4d7719e5ecb3253896f5e2df8ad5e4ddaf823edf806d0c417a00c01f820cfa7bd1586052b0940292736f41c6c44e10645f7c380de93fe9d925eca44e23383478eb00ac80b180996ebea3b6c4f4edb599fd2894ee978d94f3de95c34ce7827a375d4d5beda4aaeb3bea83a13aecbf9a98161a6ffbd5698a48ed0aeb56eeab370b3822d8cc5c6f5fa08dc3fceb92453ac3cbe7ce3224e4a81dc848574310c3a8fd8930039fc5af7cf59c32f8171b00db8d82870a2de6c56c336a15d358fb5c7181cea7e861b1a4e82f98c52b54948923d4edee3aa26c2b2d371c19aa91525e5fbfef27b9436e9fbfcc00db7f64c31e6ace8c94f6b074a4aa6bda76b3e9a062e7e124343d0ca6669464f4592eeb02ab7f467fe3b364a183f6be75c4ae239d2ee6be4d77cd3246f2f83a4eacd0ada764ddb4e721223deb0362171c8607a1fe3dbef48184242ae183d220bfe68c230ecfec6bcc24443790f3cf9232506df8a8a1c8c32f40d028a27ea9394fc890c3d0cdc528de4470b971a56b46bb0effc8031691484bc942f24c2699d90719aacdbb4adf518a7cd1f44eaa5894c98e7f3bac8ceacbb72d19eba571c35a3a9eca102156dc2c3beee5e51fb8bd70610ffef0c70601871f668e7f3a6e4f27b166e678329026c9005fedf0e48677416f6f39f1cdc355ec760dd03ba4cd4b129bcf13eda1f59726117ae987c1e28f7dd3ab436ed877d2b1bd0b041bca2590d6ca7c0a1a2e64e8d23c6a42425e64b2f7a592cce4bfd3bb0796a372bfb47294c58c7d0483ebbf3a2da3dd5daa9e11b52bca6dc8c3e2211e1ea550603573f34f1ce36a0883e09bc1d49cb239f8870173d96fc6e07df60dde863be15a0556b2f87a4a50e8f6132aa5a847c354225adc51d6eb49fc179158bff2344e17371b7bc4eb6a60ea29e8be5b785cb63607a9433ede70109a88bb99770ae32dbb9064028893ecc7ff4b8161d9c3305bfa21cb5b73dc41c91be927111a5c98190025c867ace9358b4f6a6bd5138172e276bc6a5f1ebdc2b04d4cc015768c3a3cfbe04e449ff7fd9edb982aba62e60580ab1760bd6d8c7adcb606b3194ddb584dcf03fd1501183c77e644d6ade06c530c767c9bb4aef9ac82573884d887dc00b6b24c41d4d33988b97b9534ab06a94766c9971520a4f2eb816d47c8c5f383844117f6ae686114f6b51720667cefb3acd2ec8d7b6d6fb64bedfecc74424a60e5e4855a4468a62fbfbb94c522e0ebb1415c2df4843e8eb1b65806053e28930759262e0387741da281e48bae924a671c2998d08fe3a9a6a8c4e5a0c72384d8c2ed2a67701d5f7e46034ee7c4430395ff2953a5aa0ca9869f8e3d45477930134e1b763bdf7c75cd6ccd914c1f820bf938f922c070c22fe6853e5ec96227c8503df935290423dbde73aca4eb203f35e570c8abe4890dac5c7bafb8d9c9d5388e895c41574dcfde1fb23e82be0b8f90b140c07eb7a0077e9bac74f2e45a94b6b6ddc783143182ff95e0ec1318f5878649620c863dcd116515b2d379df6777166c280eda1303351e627362b4225b5057f8a0fadfd99b6db8a78396cd498143539f90f5be3b326b2e26faef68236eaaa0a5d00564f93f69f66d6442d56ff4d5cb7cccf8e10c467452703044710d38aaedc0cb5aac4e9aed47670fb54ba6d6ce0fe14cdb140c58d47bdffc0b2d28a26c053293a8fde201178c252edb515c15e5034802ec8f01b59a8eefe5b6fd1bec5cd99f1e5ae99eb06e52663688f75054a1d9d385c580e246e4f235c7bc571f793a5f3183696d881f3c01b7a48bc4e6a22f73f872c596d5200158aa39ac3dc9301fda6a4aeff63e45cb5d885fd8b3db414f4eaeb6132ab118576878d577aa7b989cfd1062c6bb58efed34a07d6c6896d79380996b54cf6287620a5fb143ac3e9ea6265a8a1ddbd7fca6878506985287c516fd629b52fcc97b72e7452817a4a2ea4527f3e7c983f60a76a9d5c1e52ed427ee065019ccec027d8cc1f132a9d2f1352fc85855f21d4cc40b86bf33fcc6f97fa3bd6941eb5bc5331d6766bb31fbda0eb46f978a336312b14b9e6af83d6ec793b89c486ec8c41ab9af53923938934931d387a29259034af2380da3105fd58eb21ae5e81230687c5dbf8a0fd1151937d9abd1f1736aeb50b6261e1ea7d5f4268f24540a6eee067a1d5f211067c8681b5d9f902fa5c2c08c0185a6484ebccf4b364fb41fdbc2d6c6eb8111a11afc5476ca5cc37913ff504178f22a6ce2ac4e60cbb0c2465116428fab889fa39246e31e60a39840771dc019d2ee25482959fd4aff7ffcfc3d583e6b686918a73d1db5dd658a8897da241b40951e5b078879b30007c8f914fc978ab93cbe92ee645d1eb14290e5af48c0948bcac2d401b448e397f5c80411772c122a021af51deffd3f998e31b25faf1aba08d7b48e18c16c2fab8c0eb45456b474091fcf373b91f4df98487852dcdb60e1361a8ab8b37f37f9417174a178f40aa98c574121441522cad634880dca326c13358baf0d77922f922d9af20e7764033b5958fed0b9ee786608319a661908d2f3c0cf5ca3c0683fad6738d40f4af7e73d48a9216c4649c8d8826bbc3d6e9b72c82a378049b1cf75214bc6fd99c8a6a403eb923329ec2aa50702aa03fd9a015da6449dcd9a071468f191bd6283100872182b4a89302797627cf5459b9abed93c01987aaabbb981f7014cd13e9cfd862728c3a29629c527c91fcafc6a1cd092dd4ce8af1e2230fea4d41be1a4cea6a87be841e1dd5a0cd4908cdebca27882376d9a2ff789bfdb7ba13314bce2b9a00eb6b71ef5d4bf498458a5e27245923c9407c0fe88755005174f6849475678ed491100c9fa4805678b349f4915e9aeb04dbfffa898bdd7f07083f50ebe6d3aa712e2030305142f968a20862359078e94f1f94c11783fa7d4d8967341358e74c063d40cc768da891c64cf92c92a6960db3ca484511c326b4d823efdad3198025b4fc3944ea72689b0b7120dfef825efbc7753b4a1b6cbe60a03395b382a9b62ac45388f0270990e5e720a5cbf61bd02bfeb221599d622e749557930841a1063591b57f00ce8ef8ab2d9518946a8b4d780d30e27cdff3748b705e4e4f683b513502d04b7213c4ba944325ab3ed7be4eb58744de16a7970fef27b23b2348b4d54b8e927fe322b98e47bc50404c9009a4423697326eea9d13f21b288152dffc6f9d433bbdf0a3119787a792e0f59f63ef6fc47bc7e22675279d621f8d7ef1eb96840e7928da8e9c51506876bbea54af8cd20c71585c8aa013c29babf38b4c1426e83525a6e4d56cc734de9ddb93cdfe373ac75ea8b7c8bd4d1faec95d1d805c8b12c3e680c2c909371bc95bcc579a431c4d5df19725b1444e3d0771c5350b17ba0cafe804f7af4cdce68a87f5fbbaac4b20c145bddf8059c524717cf860319c2c2dbc07dd3b41338a151ec6c3236c02620de1f5b40864bbfa85a6cacee63744a49ba070afc5a210a7ed25b8707c23b1b05e6ccc1659dadb9ad2bcb0d07e727f71cfbd67349aa34c442e6c23005b9ff921a3a7f36d8d3c0e2f23c06031d13016e07d1146995fcfe6bad4b7f2ee3a5a22e6e87307f710b8d8c3b00c2c55df509cf378fb6eb0b7627ad9939776c6d4f3a8e9b432ffabc3e8341416aa32de789dc06754f88633cb498581359ac3abfc7713da3bd7d91fb2ea5ff9e7a169deb3ef1947f1487e1fccfbc28f60734888c80b718a156659cb8919cdc5ccc702b1d7718126189db6d9bcb600060e216fcf0d5a4d5eda055b254bf3b63b1675324681675b328bf001f4509becb0150a79fe22b7c0269a9114009d4a9da4bca8a872e81efdfb46a0d6c4a73ee5b3b99acff49ffa404cb3614a1774d8655881e7d41fa8a4613bc98dc7b22fc913cf01f4aa990b984fcc540e3ea286cd3486b4f1cdd92cc3556118f02ff259b6c1893916998628db54b14c803b94958d0711695d90dfe0d8102618ef82bf999d96781928b284751ede7e3bca8b04ffc69825b8622f457b312eb95b31f765ae0891bcbbaa40fa886e9cf4a55d10ce20945f364b01cd76eeae456188e4d25f40d02e31675c085",
"spend_index": [
0,
1,
454989834,
4294967295
],
"result": [
"2ca8b7b26428b71b1c427e1bbde29e7219adc411a5857f92b67a57a4e17e4561",
"b835b1f1807d7c19fe9914cae81d288d884d5216e35a9f51f415e5415200c00d",
"626ae3ae67e58ef244df2e60c3219cf9bd30537828a70fd98e0d553db185ca6e",
"49953f533811a49e59f60d6b507d447528ee2e16af04c29653a889a7afa34c9c"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 3,
"Witness": true,
"Version": 1087930968,
"scriptSigs": true
},
"hex_tx": "5882d840000109d11d906e00000000000000000000000000000000000000000000000000000000d1c8d516fd1501a186435131d0d9ef0027ffcbfdedb642c4fa0450f8eed99b17f0c3474757c7c9d844b0f79dbaa823333099cd816f889cbb650ef5f599c314ecc363ab80a68eb7913e8ca1fca9ad2d1f75e26066b413e3f24791c53f25a09944458b4208adaed92438b3faadf525b7cb79d51e8b265508524ad32ad68cd8f6464a1391e9253dd90fefdce871b92cc10f04e87913c6dd1d8fd5335c078431a7a7845c9e258a624b0ca6a3d65be769f069de978996245fd855babcd48d319578805dfa8fe7491e6b0a9309fb0fabf259274696454968abb90af4333f53c74463894d537aba51c3146ed2253f6f492ec6ee2d6546476d1b604c152fc67bf838ee667e14543843e5fe841336d7e3fc1a0b772a8f0b68c09388bb3f333ec3c907612a9478af0a000000000000000000000000000000000000000000000000000000003247f14f004fa0189628f5b62500000000000000000000000000000000000000000000000000000000adf0cfc8fd9401e650024b0336cc11f1d733ff33ce9832236f517e86ad9d92dbe3f99a60d760e759cf036ea1df8f23f300cc21a84815a07ab8862ae5448fe48a61b5c4a73405f145e623c93ba814014d71e97007de76449596edab5e4c8199e617ab7f618b81b99c72d0fb093ea16e18ec1cd6b44b083511609a1ff64219f12673d869b7679b783a988b63ec97482780ada3354f4f7e60a7e646976c20c1435d7487dfca1927199086d9ba22ee53527675a890cc0ff97709d64f143eb8058a5f39c0c5e0b29aa5c1d336e8e1e4334a82db93d955a86a6180266aab667fd3411269a18862be399d8fcda14b86dcd4d8d01de1eff667e130ebc5f8446a68c65b69ae54a562daad3127c1eaa17fc3f25949b9c5ba6e56a4e0123f5906d552a3f40f54dff4bf599e0a36b8b59d381f67971d8210c4a874f22d4f32cf8c895df7db0343841b86d2dca2af9e6b5cc35aa853f35e3b7433ca49b47133e96b828e6edbd26b24e3a589f2b0479bb7d59bcad7e2c956208400d96ccfc612c04ef1f6772829902593fb73a1960415cf554e142a1ab4b7938c0b60c9371366d0f7aec032ea26d0cfd7000000000000000000000000000000000000000000000000000000000120c9ded03842ac4ac4f2978f342400cb7bf6c57742b077a4d151ad6a54242759f88508cb1b1d51a9a56ec7f3f60aa90d42f4d5785468f93ece58937ce5471b4b6a51c72b12b9f8ffb09271648f53d05df8b2541f07aa9f66747075f343b722acae5d11ee89bbdeb8c40cc6522f470f7141ea40874fd8f3823e3b3ea4be67928546f389a60f22f74916c48a2f74429bffa625f84acdb7a4cccd6b7cac765fb44708eadb66935a9d3dcc6e417835192a9426e5dcdd7cf4df24ddb9b2a9ae1a30dd22a5c6f6ed4ec3432ab322ee791a83f5c6991dbe864c96d9c48cfb500000000000000000000000000000000000000000000000000000000072325ce1fd6a01c9fab206814c27c190b8556df10cdb80f1ed8ed5083af50f2845bf463a85fc42c308f5b8d1f9474963a8a5f5857511b415f9c70b5544db3619208aab12822862c2f8032c1f34876b405d5c2ac3403902bb68b88f252cd58269e11774b803abe2f68a1dc2b81d2bab923278824c33187a91d94fa57523adf4c3bab05977d1b91f190314247c21402f31b9841c5dad2e91a55d2d55b8ab4c979e32c30b1c3878de7f96ac377d4c57f833b0610940ce513c6da1a96e24deb783b685a2505b021ae12f58a758bbf537ae7b22e0adfd0650699d14359c9969e2acd89115f4b5699f2d00034fdded9423cb93dc1a71f6c7044925787f8e7ac3763d265f8c6f8f601ca158d123065abf8e240d22331a3d8d6932e47424fb365f3b8817b2d6132b388e18b7750ea859979a9db75dfff5a3aaa3ac7651e90ac8323888ddffcb5d85f6fc44e21d4e745f1bb2f98709881372d1b02a5f98d59789230189cab9f2a0557deec93185ce163ffbb5a95f2794fde6401fc3e02c00000000000000000000000000000000000000000000000000000000ffa093e2aa83442cb66f504b4317063a9616dcdf3c7eb8342b8e376492929e3a7824af63c20f7e68933e09e050b7ad6ffa6d19c002f5c996f7ca21b3c6bce4c1c57aed09a215d190ac43450ee75121aafe112ef6530ad1300b578c063a7e0f6979d087fad031d8ece71fd924d40a989f439d4ee219b1940071338760e63e40f6f9a200f850cbb57bd28fc4d210e362442baff1c68e169a67ddeb5c18bfa9cdcae253d49b0fb5da5727657848505bd11b9e92aedb8703c8000000000000000000000000000000000000000000000000000000006aee706e91bdcc8afde1b433d68ab15dce8289e92773f52bf999aaee11d9752b3bbc21be66f0bdf751b9f3a76bc67e0e840c0732b95cb8a74d105f783fdcbb329a46ad2938e0cc234d070fcd78393c08f184ce76a813b90412ed507dcdb903dd84808041948e6157e6ace0e96da464a774c7d139114e61ba7dc70990a8adb253cba2761bed4fc16d95e0d25314efcbe73e6a624d1b2e1523f2ff2d4e3c8a0000000000000000000000000000000000000000000000000000000065580be9002ca46165d11b55af000000000000000000000000000000000000000000000000000000001f2269cd00f8a30788031542986735a1ff65c88b802469b6494733b38d715068adcc3e0f23abed17c489cd02f15910770b3a152124eb6817f964c952fc03b20916823e7b2eb78ce2bb699f7f75a8aabcc783ca20a173b1cb970eb856dddc4e7b015fb1483965c33881704f5f644c8cc5cc387f9f2093f6ab3a5202540c4cbb5926cd90029829f060ee1d1e58041e26438938c77ac452e235c147b1a2ba7ccbf7785c761f8025f76fba58cd5db56f8468865eac56349ba8cf7d071022895dbbbcb98f83ef1dd11be09567944512705cd0734439c2a48e504b442b576f90f8c577478562c83f7a4d2b36560505606450f8b1281ee013db911de9d028c660c70fbf36581b680b11c4f0f5e01892b94cf03e96be8e9b6f4ca3c8a17e221bb97e4059ba7b17e2c0e5bfec5151e62a590b11bf358ad25c2a621aef685f35acbb8a1b53af4fbb9e7fe764c6ee4593dfc940155c8a1f5de8ced50a7c938f18098d6b670f9fb66c161ae33b9cd140baa3f4179cf66aedd3467f4edac01f84fb6e3043137ab7915da543187b0149990ebf20499edf3cc1f61ec1cf66425c05c6e7cab47617587c114cb19b5e05a6aa1132a1cf1593ca35fc28c8f163da373bd0b2cf264e67a63e57608037982a3f73adc2987c09d2f394913abd30d7e60b63efdeb2ef7a3f44bb01019e87f85e5820fd2f154f3b8786062937a00e86a9fa0f241d6b27b16031371a8c5824917b7c64c39e15dec48551746085161b7af95b605faaba0acc9e02792ae92af2c9c827eb4dac215710d4717ac21b18734653e3f4399b4eb894d713e5de4ba1c27a12bc13587da6e47d77f135f3d7d9ce9a9003ea3915b05eeefb4c039145c669db6b8104e98ebadbb3386f8a7bf9865efb18e26fc8cdc901f76dad15fc0cd8f18be46323f16d425acfc170a8c20a84c3c2a081e120ff4c09210e694e9dde489d222b89be1e2124878bd42bf726df6a3ac2de8af64694b8c97cef3864efffda643656df603d61fc31fd1eeb499c4111b9dd0f1b612e48f0bef9d867c666bb8f2a3191714bbd4e80e8f5e994567eaa174b26e583fb9739b31235d03f5ab507575fa4c8c82970705fc581a32fdfa3cbd4140c9e8b01c8c1eedeca2177dd7be00f46063d23aa483ee1f69843fc5bd63dcc6024675f9044152e11d530fdeea913b329b2f13476da2d7d3db8e478147fef8bb97395bb32b394ef16629c0dc9a639d4f5501503efd255b65d1fe5ed611737f7fc0451d71f8c0f540000281bfef07fabe9ae65ddfa6641686f0425ffdb45264fa32aad79a72b717d14a9eb168e83d44ee35305b4c3c7c16fd6f63b4bb1ccd38087c905b653270e0720e92f3018ca90c78b4c679993edbbaf4e4851f021b32df88ecec3c41abe31e1832a7737ef0807ba8276a9e7979067a90c3d129f9bfbe14dbd5b3cf9d69ee074a20572e46988f8749e8f8c6b4646ab8e756ca2ff9015be14ba0008f3c7a00136dd300a33d81b2002f4146834b9ec1650eddab1b9c9e80a163072cb2675c50a8b474ef2690529fdffc56661dcd4565c4868571d38da25fa52f724d1717de4884e26c58ae97f89b6fb7d3a3330a833f09c037ee12087e23ac16ad70c9e0b15e733f5cd024efc3863fd6f01c342e5db193b50b4f28ac75a7936a31fdba44a1c82d62da1dc3b65259878d1e7ad1e35ccb6fc3dc5c76591df1975da5f241055b50f1794d201d4c9daa47b31ccf6ebe8209cc1b9bdce4d9255dba5d74d929bea4c142f3ba02e91c23bcae26b0c9055296cdcaba4067377604f297a799f431ddb0b2fe89c5d486a5b087a6d1a03f33985e2a5bb208e8a45cc67d3f4c167c61a01fb1caa413b910892fcc91055763f69b62c7acfb6f19223c0e39803da2face3aa5f97a0b460372a1a2b2b315c32a300779ae9f99888aa89936c6a7709035dc54fa32c5f7e4edcc06ba707acb5d21792717324d37a27d34a32e23f1ac6b499e944513e44e0082a1043ae01b4f7e56294d89e6138592f8482ebee6eae39541a1629afb8380e42a8b5cdcba9e5696c34cf55c29f3de0a4d9c02cbb42dc2ac325877487969dcbea36dbaa62e0f03b65efcd4134a15556691614e72d07a5edf5545ebfad0155ac976da8409047a32fbd44023d543848eac10a9431d0001e7904fdde018f6691643ab0a74363b5fc7bb25615aa7170cf1f708e8c664fa9ae853a619dbbb47dec3a02cd76e12319ce94052008449cf909db2fe00b20eb2ed0a36b39b9727590428f6a45d8e6ceef2ac582143bd467ee796274f5a92f84bafcbea39f295cdcf8de8474fe03c5709a43dc73ca0cf126c5b39d8ce8df0461d5dcdb6d29f9860c7b300dd571a62fe5ca81f0a96a0bb050fb11539a878e2c69c9f16793ba315c35886add81b33f3b39854e468288f92be2c8822e8f4e074bd7222200adf8e15f6214a9a69d73cdfe78f5a42e9dc5346287d83feab8c41052bff3757673bbec13182b1a2e18e581f1aa0d50f7868b9a947816cfafef7577eaa8280176002a13db76bc4fd36aa67aff8b000d5069ab18f619dbbe2687833c7ae1f8e4cd078d240c3a9bff7109081314b342b61387e86c83b646c1f47570ba13a9921488d591616e0c9cbd0bc565a43c5b77f8ebd4e6982c63afeba586bf05f70d3bcd130dfe29833c9f12a7be2d6d635eb5228cefd7e4490a2b8c6473e38450770c189af0de097367457c8abc7f22f80205c0504eaf5e8d19a3908a65467f7b1a4cef40c3369cc6ae4c8a4553081566a1667decb04f520ea73f3b2da9cb3febb2c5a84b623e21d620cece5b4bcb40de3641afb72ad71dc00673d414b2a5d1f45a289de1f6bb2226aa3a31711a931ae68f67ee9efaa0df12e6acfbf4485a5ad74e49a7355667fcd12efd4c0124aa6676322213513bd81322778887f8a83b90092801d318ab832bd270a37a5e97004e5da6f46eb97189f607217314320577dee6e47dabedffb2f5067ac1d50ab5164a2ae817671171e6a4e432657d856c75a3cee09cab538b90d3fa96aee3117a2fc5c780896fc6540f25e12ba8c9bf554fa2efde7126a039a64e7d830ccd735c753b52f048c30a613ea6524c774dbe4df42fba3cdc5827c9dbd1ea05c02968868bade637ad406ea12796a524e5388bcd354b622db22e14ad7c3b95a7c861ca1bd103e9a38288ceb4278f8b5ec7f60295ce9255e4c34eb6e4226969cbb5c0ef66e7d74e6853165028a58044101a07b68ec19e2cc37acc2114226379166297e53950b7b1078b5c0799c7f4805fd104ef202b50aa2011d3339d50fb9e2d37a0fbfaf303cc4011348acc833646286ea13ae7b4f13a655bf78edb1f30d1ac3495b67f22ba70bec37542c32efce0af454629a0f91384149cbd59991de11780ee8d3433fe8a4e9f465ea86bb0b5213d160bdf4de6de489dee6c60bb73281bd206d3deb9ad8e849c959d67df008179cf0e91b7a70785c55fb35bfb9853b17ffbd7ef7c82bd56d25b2a3e184a69d3aba2fea43f421597f4abd0c2b1a74758c55b5824ccc1474f0c8a7dc9eda88589025833d2abeaa53cb8c07ce020effea5ffd9febf976de95819fc60ae81b4b6e1918883b895e966259fdf13331ee8b7d7d301fd1c01e4befbac09ea666c088b6e686ad7dcf07a36dc9b4c3908014246a34efd904f6133908099d3772cd45f7862245fbfc2c3d935125ad06b84f2237759450d8ff071da1e798d4c092d49de5911de9bf172f9110f9c8adcbcb2e18b9ad0057f1df919387947ee0dc54933a7cf02d9883c711338951481ace24e570664b50a6a0c4d0990bd8d6dbeb1b70e6fed55f04715cab4213f5e01ec28f6fd3d03853485b1930e29b995a17aab9d411f7e55613d65a8b5558aeec5cf9c2361855a3031810ddaa5b0067554a269f72c3dfa4a7b591b8c2bb26e87c69e7aff9ce6458f908e855c3cd9c975ff35a49583fa1d6886160f6592e3b17765e192093b6d26f36ad1213f9e5b6e65830d73be96e4f0b431ff60e74e8cdde280c6f7ff184939bb5c04fd7001c298a056382619d7d85f178b3cd8399595d2209d32d07ac324718e88b0c65db437ae1126fb84baaab6f8b6d619c011c911fcbb4afc046b84053ac6b02c68a735853e7223db64de740311ced5992c9fc1707cb1ebcfed06adf122c0155c0be4ac95844607da8458835a72ad57936567a444bc3ea84a173246c14d8a3b38494e691d60f243798773c74e03c82a0290dc9761711d05439ed9a876f82fb0357cfa109b76229c60c79fe2cf1921c684fc46c3330eef8a581393010d8aabacc50a31fc5a6c6620f728986321cc9ae3922678a6315e356ebe2a3e92daef08adf3fad5308ff0c748d56dcf6d5f96bb4a5b3813dddb790abe43fac3c431a064229977d2b7573dcddaa1c18c11a3aa215960237418bfd39385885cb6ecdf7fc02737fd6eedbf9e3094eeeea9689e43d136cc721a119d1bdc90c42efed7c982251ed86876f4706ca58947bb1a3e2787b36fb3e19529947b066336553158b427a403902cde7a6d072a6aa6d6e15ab9e95ba3122da146403559d5107d51441f3e3bb40f5f869534c1f49f7aeadb7c6b9d18b3a496864928bca65656d7a562adb078a39292e2cdf08690837cdbb3d501bbfa6847f77bd924bb07c4518a843edbdfc7b1fde5eea2d4b702e7f839678749f090a8b803a8da0b80e9d248a8b689ca16bd79c0f7289b88160f0ffe998c00c484e30e7a978e99527540cb8d0a15ed505758664af7ec5983d9d08e380c22ddb230d8a542a5a0237577fa20399133db58849fea3a85fd4ed4efa30c4af23e3f14d0c8ddffb45f191145fca63229dcd83863db507a7a602bd5505466223ece20c65ac753d28efe27a122ae2563dc1bbd2449a4e80aaa19450af5cfc23c047e66b1b26074a72828cdd81cb00b3385d1c3f77722b232cf59bdfc23baac41e72872ea034a12fcff4b7cc903ce8e30140000034bb3c82984c566a5c3e95a1dfbd795ccf495b162339f7d767f0e75413394e755bafcb49d3ea87c1bc6272209b393af99bc6f17489e8292379922e659797454282366d4ebbb3408c2968cc9cefd8101ffc275bec9b00f0f305b937836bdee046d36a26aeba87b63e5ac2df090f02d7941e3c6cf3e0264b964014bb3d52d4050f8c5fdafb33c34ce9bc2e31e1c749a7cafc7c6d87fbc0862129e7a5c45927d84bc32bff30f4287dd27f9e35b61f92e9ce5d499ec93dcb0a093a94d2b2a400b0cda1e2edea33db0cadf89255ce9bafce2a6a8945bc4daaab6a0f4ade3ff870464daf7292b83987bb58804f93e17b80ba342bf439eda4ac68cbd01c27576fbe3b90d83ede7cbcb8bf3ebd1551bc167ffaf17fd20c63852990a9f84687ceecac6a3bc11eb9b02b31de864eb137ae8d34a49a5a31ff8c0c625aa2d0f8393769bc770f9c7a1c915bc854473dd9103e698b9554e8bfa569436849431510fc5bb3a7f5fc9a7cdada6b626a77b388a6c2ad8405103895236b58040368f107f78289007d9a701d03c8983f893c9bec8bd0bccf5cca6fe23b7f84a5c313482a07aa6d296beba70511ee4b731835ac15d19b5cd3fa56b2c7332261e05d3c45f3d0849be54149b30375ca6efdd8d5918b3c87ccec57e60fd81014bbb81619eb52cf7518feb7b9a7c31e06c1534ce2f9ce68c41a889119b8fb7a08a96b27663dbc2834624f89d42005eb25a9da928963f76505b41acfbb78307ab7fe7c803083e0ade89663491e0f34de4784b0767891931b0af5de19f784ffd32f005f367c4cbe20f0af216f1ba8e71d7328051037a843dd0b6464de272d4275e19ff4bd36984f32225bb85924422e8562fce3191fac0faf8901b97930fcdb2a75309a6439ae3cc8df4a1ff96535758ae123ce155c8723023f2119f34051c14af2f6f6ba3029fe0658535a1f156e5c57da55df9474df66b906129765b5330fd0364405a24393e00131dd8fcade97467846f2148492a419d7d026e3a06c8e1edd44ee3c2a5dcae4dd20f8ec446b74d90070753492c2656b064fb59396c3622723c5e7487395eb41258e2bb8319a5e9db2188b6a6bc5a6d24965ffd2105a94f139c6ac04905fdedb55f9b00344a9887c44f031553fcf6d0ec4ebb4c2b6cd8e8b4f53083cd46adbf10eaf646cecfb218ba8de1c7e5cedfd0a8142ad3ba730b71ea559d0210eaa026d85c7604f9d437b1fb6807e87c6cfc75d406506076ab631b7fc4f8681e9a09894da2fd0ffe79ad5bae1e4afbbd57c315fb1a566c8c1f320254db2a76544346a29280a06a5666c02aa07da806d46537a405f364e667f2215b2449e39f62dd441c3d5c9926787385679bf046b8839702dd2da4bab8d018a4b69ebf3747029b",
"spend_index": [
0,
1,
2069202832,
4294967295
],
"result": [
"1f828c6af674e8d1e1b008c6e775a4a20439e73177943bad98045c5bc590a9b8",
"6785d0e45096d3acf1afa0b0d6d20e11dfb69a021417ed14626a30009f792e5d",
"aface3587b476063d465dc2e4f9180a16f8af0d4123d1360ecfb135cab72aa80",
"47d0b57b0b89597c624964d6e436816435ba96288a0eb47cc2e6754ba2b9cb33"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 3,
"Witness": true,
"Version": 1959860592,
"scriptSigs": false
},
"hex_tx": "7019d1740001023867b0a9000000000000000000000000000000000000000000000000000000003f6d5dea00948107edf99ae02c00000000000000000000000000000000000000000000000000000000719a559b00560d4253039aa0dccd0e2dda6ac8985f9b143b2eb3bc5ff298f93ffb1893ae7e1884630415c30cab9e2c71abd1fd48e817b7277cbe3bb1fe28456fd8213fbe84ada36962c65fcf815971c8efc67f2f411c719222d4b376c6f92d1c56de8bf5baeb2cbaa72e48bd29c0ea4deb6bdfe3113f813eb872198e3f06ee4e3b646bc4b3626f720417c62b02256fdb4e0aeb747197900c0e3d51f55872aaac60354dc7595b42e115dc1927b4124c31fc37ee69072fba58d351794a70e9f313b26b23240c7d90c81c1b266ca54bfeae192ec32e132b386768a1675d8582d210ff1456c8da309f67def5d377144d0c9ed67d45da982bedff793f25d17cf19b2ac4033c0f5c9bb19ffa4946396e7076ce037987a48d486f647b9b48e2a968f46087283a20f817249893c88ea2d5ff64eb3c145c7c2cfda8b23d70ceb4ab4b984b655dc4e18fda081f7128cd63a8090041699cbafdd9f7bdb26f8235ed8b0ce542132ad77d09cfd14f51ecee08c8db139cc99d6df20bc3eb1c54da1e6f0db8558d157aaaa89ed1a0d983c081e5bd8e6fd248b5dcebc712b873765badcaa18c9ce22c8f9340ec89bb53cd007c0e6834282d3b7c703ec8daa6e5fd6cc4362abd4b47cbcb295996d437a58fd7851cca5d25819324e51da4177b79d1e1d35f082e482115db9d9b06a858f50d9ff0beab6eb83ff28deb3ed1df17f7d237e3fa6d70204cedf82f8f99837299dcf8889881a975ab09495dd64d2abafc40b852a7e97884ad42438c3906f743731020cc92c0b22657a72c9526e206368489a9d53697543b57f427a94bbdbd2fd3a4bd7afb2b56b6a1c3bbccb385e1717471320728441e47a1a74e714f060d495d8600002b57abdce9a077355f7c945e1fc62f91900702688b00bfb8bad563a266560213d087b0746ed67176c424d82828c0d69de039245e72074ca1499ad6b6d1058d85ae4a9e39965b2123c7cc0ff199aee0f6cbfd8f9dbc4defeb3f141fbe6d0d617efeac84c7548b8af3f7cc17c959fb3e8ad5e628b167ad72a7c7a7a454c492c37118da23435cc88f8b5660898f17e526638800a118a53fdaf094d55945e16ac956138070de1ff8bde5261cace53c565bf340660a60fcff95bb2fe24d936ea32990241f3f0f48d33fb385b468d08cfedcab0cbc36d5a7351a0026a7d4fa0cf4281303feab80cdb09ee1ba37592e8ad12e7ca891a736cc4452647461c3689eee1987eb292976b9b354d654dac5aa7a12c34dd3687766d65852381a2191d69d4cb84ed513728d7bcff8476279a31c022378afb2d4b57e53ab19a42ed52dac1ecb0edac702fd6501cfd5875908f51d2488056c6d6a38263649844b905436bf387ed391af5475bab504e0ab5c2e22ebbafdb5587e6e6cfe7b580a54c97554cc6254f07848b04f4ac982b69ef43cf3d1369429fa01433b292dd455c6e8e43efb4131dcd000d265f14418d6c2423bfe3d11061e1579a399ec0f0977c9b7ce77717765a90e2a93cacd67bd6148b43abe8d14f4cd01a050d06601d9468dd2e97d462aea18b474e659babf483abc0f102098600a69c1f5fd70d214710e29480ae4a28cf11873e99b647d650ce0dc5ac76333d60e3aff9005b0e9261da1684911bf0dc1a5c2f96e60c3dfe0c6a8df5fce68c61c604bb5a6bb7667957b79b226bfaef9dae992d10fb6f362d6b907a83ef12576d1907eb9e0144ef103ca20f83de50472417ad10513f6aa78219b1697ce9ae9447bd72bfcc7f5dc90327c1e4b5a70badb70b05107efb6746036695974129c2bf1a44eae2204daf10f7039edd39b136aa29b2d7ddc3225556cb5399b93cfe02852fad98e90a1f60f215d6025d84375ac2eb5773885e131a114feef4a95eaea11b12b7aa9366f5709d37dd494",
"spend_index": [
0,
1,
2627618632,
4294967295
],
"result": [
"e61c8a21d808bd6b58e40bec6069d31b548bc0e3fffa1e5e45cdfadafefeca65",
"b1c93d3736df196ab73e1715e4a3c773c687416531980a554e53f9aedd3cb4a8",
"c9acc5ecc7295e41dd9ce686bc64076f445f58a2787d07efe418319eb16b2440",
"ab97e6cac9ce22d4edf7a13ecd667a77ea8ec17530aa933f7e38757d921a0cd9"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 9,
"Witness": true,
"Version": -582183053,
"scriptSigs": true
},
"hex_tx": "73974cdd0001052083665a000000000000000000000000000000000000000000000000000000005f485b35fd6801431cd23801907a784851ac409634decbeb657f57e914e7b67f2356c0d3c5cb461117bd1a9912a81d4cc8e367c0188950dccffbf84079ccaaa02e97b84045ee87d4948a82cc6792911955a895f0bc5e2570ae9f852434b7e47b1f7bb28231e482746e73df3e7c9a2ff47dbd168250af81b1f67e54c017398a4e4966844da3d210608c53ef9df1e7e60f32d6b22bf91c34d594449bc7591bda0001af45cd07ad7da375271a6459d74451b3397b5a5c8b9fed2289e494204b1bf71101584faba6448186c0334ac5e2c00916b41d75cefdcea86aea5eb692847f544bb961f8a5f3762ab5f629b4f5b1b9fca38c83cd54a72438783aa2fb5b6e8bddf94879219c451ef242ed67486e3beafbb76b783f7cb40515a7ea86331ee5bf7b37642b35e816567fac199235e20350638382411d4775bc963de3cbc9c28dea3f88a422a619e57f11fb1433f0ff059ba8ccfe22792f8300eb3a9f6588c44639d34905114a6987ad1128cd3e1c327932bc918f00fab7da5e00000000000000000000000000000000000000000000000000000000c1bb96b53f4827f22ccc59cc5ee14fb8b748080bc0827affdd669ae7c9d32fc7268db1f6982d458303c024abf63e7070fb787690335b608ae35a4aae84ca4a7550991751df33c2c0b29622d700000000000000000000000000000000000000000000000000000000e92187c35477e0373a026fd7cea7643ab45571840eb7346f0e221cf4461bf35718c4319982e2672b7f083ab5958f47f816a911d8820feb67497661ffa931ffcc8b994e707ed10fecd6eade3a6d28ebf476a959c373d0f6f544f667d58a802a5cda00000000000000000000000000000000000000000000000000000000905a84e620eef79aacf885f15f01c0bcbee7a5c46c16b71c6570afc5836ddb84904e1c85f0cc02de39343596eb00000000000000000000000000000000000000000000000000000000c6e7076f000632e2bc09fbcee918c04d692fc831bf3c13d8f129beb80528e9bbd0cf3fa2d2ecc42785190d41ef3cec8f810d2d24e712fbdcc9d375550a823261269941a55d285ef2e861005fc69793aefc3d9c9674184c6581c0e565b2534716911216ba4c719779654d848f3c717d916fba785bbb7ea590000ff6efab5d5a7acd50e6df99388c5d3b8c045540ec29ee5624f9e558fd1f5042165f4c0d1cbb6ce585ac72399d10ff19e5cbb9713e6601755366bddc0deea6995b06197f8144ab4a0a3627b9597cdfbce33e89ed2d7b5dd1a046d3ef0a1975f420c0bc59acfb1431b624c84f41c1b6d99f9c389a4dde9f63be1a949bf3ed8f8981b95ba4224b31cb070b25a5a67265f32b9b74678a2df22acaaf0c733ef2010a01052135a6854b08805da0068833717c4ff09b6615aa9df33050a9f18a389d4bcfedd764552295604c35e84c20fe87a08224fc351ca935e2e036740dc094f5b3bf2436aae0410799c2a0d8edd7cfff3e4da4384c58f569a2bffc5c1317ef80a748ce2a87de5b42f23c388b502057286b3fd99b196394196d83980de7bbecc1146fb95d02a339ed56772528d0a5bbee26b26fba3c33b9db160df85dc83daaca965c5ebd71544474fc902ea694e7a148f8818ff3b0da797561bc04e039f5e97e55228165601c51b6db02dde391028db4c907076f1bdb3b78a49c53ff84ece976d9c1238cfce0e14073828aca0c765e09fa2d27e25fcd06c82d3ecdb3830370f55f1ea42b7e682cf79eb48f100303130f7cf2fe6722ffdcec99c71fa263ff68e133759ec9f672ccd10d8ebe6a0b8e2e27f4653e5926c9bdbe0b2fb5cd729a19cb252a83cdc44504304ba46b2c52311a98414d548849bdca6c6d57da3c53cd7e4df714a68ac5ac5f2f0a731ccb19c84114d8bbfb4fb0bc155c94059f79adb6d65063329e691f4a7872b9022675282e9baf7e64561378d0909036af437ce4b95e56a1374773c203c6b9ee712c9e0c745e5a457b8e37363c1cf584c36e633679cbeb79ffc743f4888027b4eed8e45fa8a582a2e9c43a319cebbf225b342e8f42a28c1455c2817b95f3eeeeda604a6e53ef7fbcc5b6785f02ecc2a71a1d39ebbafc9fecd825e231017654783a31cc05f01359ad89029273df798d37323ac5c4b3f401fc535660845c9e894106a0803e53dd3060be45985b6a7d48f0a3aff81b3fc8d2a7e5d9eb6e808224ac5dd721d731fbe7729a227d72d42621223c4500ca287f019e41c88483fd1c620c4315b3b7357664710a402d8ceb07a50590e8d5a5a6b59d22ef68ef6d35a0ab5154dbd0bdb218ce3f869b335b231065f2fcc1225a5508ee94a05588d0786b064abfe3e65f0def6d653e3d05445be6c561fd7102993b2e4dd89af1af2a7dc2950830d1e999e99960794a43e32e2ec5ff98e4abadd95073cddcc33d953c4424ab5f2161b95f870e002bc8aafc8023704cc86a250455a1481aadbcd07e1c0199c0e6e4363f4fb01dc8905983e39fa064ebe1de8401af7244da7216ff8893c01fbb974272e32494bb6eaabd4d6ecc0340e6de827018635ccd6386cd7a8d6cee64814e4c2d89eefbee931f110e230e8a33ad942e2d88374ef7fe5033bbc7bbf7d7b31c05f22e8081e25fb33faa7eeac363b6603e9e30f6cd5928e5308384e34acf8a41f6ea7c1169a710dd841caebec6416ff8a4e6f99b6cff1e937fdc90f8f194e112efa75982969e5671bfe73368ef62696da026a5e520d4f8249742b92ad5378c2ffaa318b368ade2a843cf1b88aa10037ea491e9b4bafb72c831ca50ba884dff5c4d99d0d8b129ca5583f1ab02a251f5e5db820e0327b98eaac31e53ae45d9d51d8a83cde314d21691239a02d0e5943804abb7dbf6bf03c1b7d6b101eddf5f13e31d0cd6108fa81a1d420b7f3fefa9e4d3b92b00fb8d416f25f7d15617bceec73361817f41875b699f7c3e98e1cec69f293d9778427cf1f94681c470db40e8b7e9f15507e86d9b938ab918958521798780c22cf8c3507cd0ffb1dbf8081679dba9c4cf9568e3e98aa402d18fc782414fdaaebf446f45a1d666ee5f024639d39b3bd7a00dc2b59ef55cc8a91cdcdecebf3f1bd6a655daf4b4965e51f9546d15c7967c661a2264b2ac28862b1543a92ae5b70931bd5371e30a9feeba18b42df6fa91dc9fd08b63a61bdbd2acf36bd8ac213cf2b24c1b23c20d8eb1b5bf66620cd247bd2f8e3de82f0c9ca0d0af57ff2e5553f95f25ff43949e56ccf672475218c634e5b1167b41cd2a5c02dd0a85f53850d322daa354939496e450f089ca64ad2167eceec5455a832b1f303daa81263434022c075c624e3cf7e0920735d3c91f6d8ec3c47a471a13855b55784ad09a6b5de74367e4dcb5b8a63433c81235449561ee0acb420ae4dadb0683f8fbba2ef50fbbdafa0a9035d3b3e13e6824c496cd14ba1047f1b9595dab67a5c50d56cd97e8a84af645eb33912a173248ac7678130e4191ac5fc1475932cf5735c2ab74588eff8a83a1f8bc9dd2448b2f11861b86f7e0856a64d7ca4d0f1d29837b1609b13e707e4e3c5e1ac43b0db62da81fcba12b2a1dc21eb30a200942b357bca55f57d9ec32d78018f64cd224a64bc7a6992092481778b7e0913226919c0d89a011fc20d6b47c554fe94158fed3fc92a5f2b2d2cba745044625f9da71e9b5f9879ec2860def5d9f6733545575917230d00f8ff5b51b472a1d4c3c87982c9f653b19a650c67a1bf7e33a7fbb89132ac9bd6fe727218759be282a1830696f06fd0001ddfba61b151c9ef04031e7a6e5b7ca15cb88da64fc97b303ea1f21640140ad0fe340d08c97e3549d20f777a5b8c6283a3636d8b4e409dd3266b7d09f981437aa2a893be0b8bac90f43f423e0c46c6f7b5c27bad92375da64ce7bc08dc3355af033d9b6303e9206cfcfd158b1fa01de372b208afd80febbc43b6f55c7836b66e399ea58c601ca9af4cf92ec8f0e5c3d385c332e38a21d5e55cbd741635a7b8b745d686a58332596ccae9dfbfde4f20103c7479ad14773cdc8d36c272882c34d34e261d112a5b6caac15bf931cf1315837e922312b3da35cffbb85e912853f5cf273e2878d726d9f71d8d39d0e2d2bc89ffca9c61b2bb3d9a986fe284df209d382b0f8f23996656e0457e3a6d43925e758a34bb9f545b8e1b7740236329fa93132fcaeb03f6949049fbd1c11f034628a2cca5ea733f7ec50bff1fcf1af770258a8f355b008ac044cb47c3972ebc4353dfe86c0835e6a2030fff1118b57923672aed6a96d4155d8e55367f9f0ea18d4e11cfc4143be5c027a399f6753017a25dee8ac50b710edfdb0d7c0b8e856223fa7dbd2a408c85496dbed5c8f13668a26832af397c2deaa466f21b5c6a0c38609a03b740f9993914838ca1c7cb18f88447e9c130467e268c50d9e62803d3219a7e10b38a6507c8a6ce000313c0aa9502fddbb3e3d131902e1878fa70ad449be7200b6a9604866a44c0db0bbfea05282a32864147d6d8fbf18ab6addf117af2157c4d13297c47743071f7932c902890510ea0c59dd5e14eeeb3a147b11bf39787e17a5d4966ae9eb5ea43fd150768cc09fd147891f87947291c61b4695d74ddda743ec995b7908afe38ad4f6d5e359fb40aaf489a7a4eb58480e7daa01a4919de1ec7494c326c3056d2bf1cec0ee165b00969a9173b98a614cce0bdccaa36fa0e636f4ed4b212dd088848a4f509cbff3d0f6bef613404d7b0bd90d6a8b9c1b0928c8d15cf057b111b9173ba9a07af0616b7d13af1dbc29b494462ab6484e51b889c71dc0e8c23df73231ab4cdfaab71a0ba40e6da76d954c785ee9236e486473fb6929b44cabb2c2b85bee99639c8b9a84be65cc7935314607c76479f927eaaa1ac21a7235c0098dcfc9cd0f4b6470b67f27b4df713b0b13e7d41227e3d420e107c4d9ecec86e4054b497c6e19c3609b09d573633052c60546d32b82304e393b78367343daaba6f592d4e2012e427e63f4e454287226305b9e5bac9eb3e82662fda422951b1343e1f72a035a4281752b0793fa582685e6a5c8b6e5d9ff9ee392370aaddb07b7d8ca6cddc75adcdac83e4d6622ca061c8bd9ed8f56c87bc1d9885002eb86fbbe35b890ec6758baa102b98762bb680ea2f633f7f77332737f1fef6a5bfdaef0458547e8a7b79c1dceb6739bd29d96472850565a43480636647fef16021b1e430aec2471cdf1d7c9a6ab573081ceb573ad18729784e78a0054016cb38870fe48e48a8070aabb03fd9701f5b670d772834589db835848a121c4b14407325ce7121518adaa5274eaa555bbbfec7f507b21c27116121f89f3c84167d4f1d42a2af145846db53e9c2a8f88f77a25f2087fe7745a025a8743f09c926719cec16db56ad11db0f1ab8f2648311639eb64dac15d4fb0dbad430fb8d629c3ef2af4f9e0968328a4c7d212764a1e94935134ff27240b648dcc23040174905aa7bd36f242e084a1698cbeb7a9a285a5bf611847654679d5e74036f0071d6491de3084f0192a6fb4bd0a1ba3749da843584171a951f2eb3e263f52cb052b9e5fdebff91fbcd6637a3ef9829fe7d93d6cacdaa4f94162192b8e93eb8e8f7af25736765bf28c366e1cb1a519d3136dc07028d1d0c560531d2911f901fb23a26e35a14869aa4cd5d55cfa6d9adb9f4bbc9bf8eec98caa09c3903ea2ed74f3da121d6cb4954b5998316c69b513935428e7447ac8b79fa41b0301304b8e9a05ec247f9ac281a91bd721d1263446209eeb6548a5266e8d2a82791758424e0cc8850ebb2340f6c1b0c24a0c328623826c8cc31b2ce3c059ec341394fc74888cb32dda5f25f5eff22ed26f7b2873c52df9178f28a0ed8f8f4faf432ca70aa6f6f6acb0574754bf8e6f10f4fbd07e9874a51e7fd1fa50518e6bdd9241bc0c027e702786af494739a4b72f37ba08e949b86a4e89926b73817749571dc874e4fcd473617071e87aa2871635227da9257600ccddbc68de9c5d8510187f7cafe3f6220db62d2d7e3af1c5ae926d39559c6c6dcabc38fc0e71a96c95eb2029a14a746bc26c4c0e559fe32a651e218091f5716c0328a510441cc728a83d66c0c519650aaf4dc46e55991649b6f5dd8189dca9f3eb351c8274681d4d644d926d3799cd44d7473f3a30fd130c199bfed08584f7916f1b44eff79348a36351ff39d0ce07df98fcc508a2831e51f5884f281be2a7c83e4b2b16cff1459e1b862b72ecd2696cc483ffc778448a42e0ff6309bc0ae5721dcb988239516dab328c96115b2b882c5112b1e36f52e737a0091007eb02e0074a914ea860e7a7ff042b9979cb9168f5de530e80b68384e1b3276e68693b0046e1f9a008fb013738615b577ec58f9419da832f30102cf6318f5878b322bdc9328640f7136c9b8592e892e675f26c32b5dd229166bc259459c10360aa8eedfeaf893ab8f818703a800b0409c1c4500d69ba1c7e157fdcee9989d23d86a9bac053e7055fa2c596859b3c8c3347f8f223290e4c1a7c5e9627bd5090ce562b27361ebdc2882d93a21dfe1bb0037e83500c8a81ebca2c5e3e117b5f0d50b3619fee8f89c18e5fb55bd147b0e89c39b6f8e027631eb1b0dd6d488e3079a55297452c64094d0c3a25323949801e623681a582dd9779816032bf3bce58f94601a8e9f04afcc639f08e81df7202ba85e06802128ca7f5d341b6b4e3c01ae93c12bd92cdb7223530f9993ba1dc0b0508bc08e2011ed3d3305759ac54a85d335bd31474b55a03bc909602fdf30193b3229e2a93a4f9153355a35039ee0d98ea713127cadd4b7ca9c488312930dbbf81bc938d1381b6c292f33385ca92eea8f131bc0c304575b9a48fa03a424e8c9766a179f844f6baac352b6da31e841673660de4ce2b6e6d5caf32368504fb84d1024a5b2f6c15dc4864bf48d8a645db39aed07eb762e9c2247752ceaf76f61f033e76191d9099e6e8ff5a9b787a1b7dd3643dc417f035a20b2d7a1d99e8b1b8dbeae858f6290566f7c608e5cc7964b6fed8496e8c579852b43c3a78060ca91f52afd035a5863491081d57dbf53ab7b4eb52176082bf0d717c68003aa77e82bcb70808601d6b95ca510248af410a722cd81e669d32cf4685f37b67487245c9a13497dccb9a30403efa4e1bb120d7540b4dc39bfd4992689c412146c4ac0f3043488094bf3549bf72664a58626d015df30b73d036f88b82b22b6807edbb5cf506b8b5d6ee6bd871ebcb3b8adaabf107033b02e92e0677ab627f5c844a19e891940a7f0c3c28ea98b5b338e986ed6e4dd6e25311eadc37cce458d238fff787079278f02efdedbf1dd4209ab789dcb4088d7495345d94794a94025e9caefa53ff460955c1660154668fe4c8fd63491b2b5bd7f5335c99c7d05dc104ba24172e074092ce5fa7949d0d9d2c449d8c0682236e400cfceda2ab232def19549656bd6abdcadbd12c95edf6c7f62545b3f7916421987062fd76010064da9e389a4577abccaef484c55fe77253d4367a1ff3f92b7fa0565ab489eeafb573af93c4773fda641358ada7250a85ec5348b96a15d455e1cd206a82f0ad00e602d450acd57463de4e23e29003839f5bf84e3a3c415536699d8f961ba8f76152178c7fdac2898f0fea6968926804df265145ce7cb9f5dde543f70e2b458c76e2a53f08069abfdf76f4586f9d31287b1fc08056645b3405abef22d911bf44bc0cc23aa8c29338d6cf775043a4d32868159c596fc75d7a924e4ee242fb1e59c7d22f923448a55625c0f8999351a95e4d49ada8ac1902d395da4e52ea81f3aeb429d9becbd4e6f8057b3a1a3d48b7607227f9bcda609b68be03efd4eb8a87d9709151d0bafef2ab615b12d9a77f3178c89df1044c0ad048af1e60de6eb617403cc7c6500d778d33695b9d37b01509fc46e3766ea9589e6bb3998416618bc732ae38734aad3ddcb927044bd0180281db02df1e54076b5b273739136b4348a00ab2369de94ddb335c8d10c568e10b189a50dc87fa2862b5fcb760",
"spend_index": [
0,
1,
835738094,
4294967295
],
"result": [
"2d734581aaf467bace1e46b59c39c08db99f072fccf6d23e82f9b1f702f458de",
"a98393b820c393220b19ac97419980b868d41ecd214d61e2daa6044c4a3fa760",
"ef56d4431fd774fa93b02e9da15bbb015bb38c500c4ff276c96ef05b9597ecde",
"d3ecb3e839c3a66e296e15c974fa1f0d33c52dd94a4ae5ec27f4d6744c17313e"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 4,
"Witness": true,
"Version": 1967939290,
"scriptSigs": false
},
"hex_tx": "da5e4c7500010792fd8d6c000000000000000000000000000000000000000000000000000000007e46af8600670e1b8f697adbd600000000000000000000000000000000000000000000000000000000bbdef6f60068d2d65f6bbb38570000000000000000000000000000000000000000000000000000000032d173c7001daee86dca936cf2000000000000000000000000000000000000000000000000000000006aa761b900f3e89cd460eb4c6b00000000000000000000000000000000000000000000000000000000ccb6e26800c31e0cbc5c9b6ef0000000000000000000000000000000000000000000000000000000007c58f6fe00fefa15063e583a62000000000000000000000000000000000000000000000000000000005689de2700c319399c04718e01085f77ef49c88c42059d42ca7a64f34426c8de3e6388197bb6e68742b62c0ebd42bfef7261f3950313fb5348377be1f14a7b95157d3fbd0226e22d7b43bb9f9c673c5435e4e0a25186e2c9f5aa2da6d9b1e018092349d7515cd9d2a44f01f84a41b20fb8fbe769954f571bc17e0c8a187c3188f9644a04f1f05dc9c1bc1a17049d3ce44f0e93d0ff50fade0bc4914220a417f0f88c606a32a14d8dbe845e5ffd40f2b082154df5a3543873606c2345a51fe46d20736d0c50ed7e041576d5ce3ad328d6340a37cb92de870a7c817483240fda75a7417bc8d2c1de8734dc523c6f13243aa80ee7c8ab5935d30bcc41f282c6cd3f91dda229a81cdbadca68124bb0de3e4a771095ea80f1da2a7d620bd8a2ce5c7d96ea062a02608eae58b356a379967bcaf927ae3d41b2dab5d56551d0d346c36911640feade98759a6fc0fe3dd7a1468cdaca58772ef7c9f8b1eba14b7715055e2d94340c985ecc4cc2e1216fc2824f0fffa7dfd70821382101b329fa42803b056079272ddfbb2eaf65ba7da081945bcb30af729b41c1856d7ac14ae2d6e59a5abf6e8565774e200f8c6fd01d31b48d3c5b1dcf48c8bef79640c2adbdcb929a8f72fed800ff41b23ad81f6ada2423a0aa2e2fe5dcf20ad7b92861551c9c6e8bd6228cf17a05e99bd5eed4d7a6d4b685a80515f4786fee03c420eba331852dddca8d34a0d136b5be7d2b5d3429e6ecfabcbd870dba31bb70c3350485f4178089c6390c40d8a75ee8465088ca2595fa8204989c2fa59ebdeb8b3c90aa3e81532effbc2570b1ec44a1878a3716c39186ee2d6a56a67b2bbc76d7939bf689d563e17608fa6ba8fe05a0265a4cd1c910ad6e9cfd1271c9e38f1d3471f7ee7f57909d6712d0723c4fc8a0c1f216596616304915263c772111ba3dc6da9b8fc3896e147c9cde7ca13fdc5d010f41137edd51006bd67201d94952091f2ca39494d34e979c2c5897668e5a0828dd9b291e428d31654117836723782cae1cce61cef09e26dbaa140b7dd935b1e18e9820555573e4a93c49764091500121fa50472e53851e3c28e9bd3cec955bb39721d863de139025bc4be8ba05b973ef67fcebf908afecaa127c7f9aed12512392a6d3f102595c3d5a2b3286f4c7bfaeb5c5fbc486399b74966a6abf6e262baea23a2d14332e02fd37014a3d1c9c7c5d3e01670cf5111047e0f5adcd1436c627d32c9e8faf5e273b5639f42303936be5a7ede623355493773150aec93259469c59d68ae2b7a52a190c277d9ddada8176a20e83cf2eeb5b6bd2f4edd9d27f5f99f50db42bb54415ce5dbbe680bed7b908d8206bb5039459f5e1cecc2f589475336671007e213eb21d5657d45b3a33f21c705ed0719f8fa8fb9489753b308eee1d538c5cdeba642771b0fdff3a9e53e58c501bddd7a7469d5d5e7e65935e26ef17d07b8808513bbed340efd109c4804c53fa45c02102605ee740e5b003c9d054b88ae9051124ed669ebe901147a3b37289438b6f4124b321fbbab415524ccdb4f2f47845f08e7b58aee2c166e0d4ddc799c94830ba8798820e535f897fbd8afca6822e3bf4d20bb0b92c759c7d5b60350ec086cd1665adafbb02f605d23bebb19b2d520d98dda7ac6cf45255b8db17bb1e42be38d633e9b4053631199db0fbf58444a5b5781d03b68fd0ceb10c0e936360326db9db8b159de2b9466fff9cfd5e8fed6e4612e2964488192b6398fcc9d3e826aed8b8000002fdac0194f9857e10851d93f9508bdb431a5ca40feb9d5b69b4a47d1450c76f16958363ccdf47967c344c60d0a1eb62fd11b5a1f5f951548014b47513bd1e3a4365f9adac793e028caaf5553697ab6d0cfc0193d709453b5f4e94a2d717e3246f1a6a058557ce0b9bb36ea5261ccfc83cb1a60fc2ea36ba94343ef55b22acd8cab7c7ff573a87d654fa0a4396bdd9f870c0469027c6fd3986c99d83df7e602a75dba070ba7c79b58d1d4ae65c84f70551b47ab9f8ca7aa29b9afabb1d5a2c446b42cddabc0f6d8c2803558ff6f1fd28da66abff385d277cc0b63977d2a53c6feb24f52a324fbe84e6c5f620255759b7e001dfe5c82b473851e81f14177359560714bdf9c2f2a606c6dd3baf68670f6ef095ab26985bf537a9009362c07339e5160065b66ce65d674a84b7c95507cf71447999674cb227eb743e649bbb92fe1ac08a4da3bac66726610754d3b6a64d59d94bea2d2060920ebdb319c52d44bd23fe315b6b86a2ab9a5fc54f1c6dbca08694709ead0dd992d3f418daa01e0026bb481f99a16107166f8594e698e85e2f10b91e75dc9d58c5ca9616a69252263a2faeeed71d64ccb86e768d550cedc24fee65ad9e897769481060679e209212cd4e6e9483905cb7725baff7f4c43c2c7f8b256b731559be1888d99002a768622a51af6bb03deba3d185bef9de84c994bc6196ff4696620169b7f53caf763cc9ea0496cb933fe7b8765d8005f79265f2c9b2d9d82ec810fb02e8832dbfc9745156343ad74f0c11fac3ddd911b6d16a669937d29321c8a606b9d1d3afffd15cafcfe822b44ba2d01216bb06da8294d58e81fc9035b3aafb957d0c99dd72fa61c4c4661f11c585180c512409f3cf3bee6333b0fe475417ec9c2a1f781f3353596eb3daaef8b91576b9deb419f0e4adafd8c5e028efef2e9faab37fad21e8c8188059a5954391ecca6aa9b87002b35e2290ff63dcef5640f60032d491cb72645f97d24276944076e30bf34e386cfc1e0ce0ac3632dafb9fb0c2634077c2f2fdc97bef19fc576c12b7a6f84b2c4ece672ee1c60e26548a1af55c90e6fa04a12352a00d2a2f3fcfad95249d997548c672f52775a86d441cacef8aea861786320730e7999fc0475e8a9afa4ae2097e9709596cd45903555b2d18365a5225696b7ab404ecad8089fa0860aef0d4705a49e8c46f660d1ad90d7b518514ab547a567b7ce06f65ef471381de14d98fa8d612c693b634a9a1c2bff887bdf9de59bcd97279f1203feb5f0e024c81b4662edc92e324162dd7690804ae96af23904b5b78be7da356159928d3123bf37ed90f97cb754df65419ebc9ce97cb1bb6afee8516c06e9327fa0323752832124c4a8c609397fc5be98ab28ab976d17447980c31c37ca2995bef7b0d6ad7fc8cee2dd1f59fc35928fddf01dec12348c3c693c66765ca7200c7e2193bac0656d0626a024d5186c7e885308ebdd055e233c4eb5cb82295a6f5c6472a49dd90b9ffea4aa82900ed8f498be4cd0d444d96ac5ff0c5feb63d7c960942a3308eb4dfd3632692b5cb793aba0e2e0b321d663c86cc5841c91ec570f19237dcc3c575476506b463503bd66d377103f985c3a2d4d6fb325dd9347346bd74b4281ac439dc364e999e5345f5261445c89f758c7b04c67c132db5ef7dea7cc14e099ab2558c91e46be167256dc9ef770e4e0726b694db32b7f56a5d40e34d7ce88406db1556137260e8fe8671ed8f75ae5819a7a81bc45e7cfcda70272b6872216afebf9085e58f0cafe86cfeac94257e596848d95b98ba1667b2e39facb8f69c603ebbd68cad1a4fee47c8c8efc058642b95cfd4e672ceab02a83c58d93179bd2a7de2d5c0392b132c76f807ea754d24523eb912429476410e6fc91b5ee277c7177bf947c3571f8396b78156136030f4108402bfa362df0c7ac29ee852dc1996b5e7aaf3bf0e6ee74dab654e5e5050ff8c43f5ee6d433d2c420b4d0b10c99b0625c358b5b4570eb113589eb2c7f89e33079e9c9f9bd5b6b8add1a101fad6db97f2c9a8db4281b490ed4dacde83dac9bc078225daa5c099fb2cb23727fb56e1300b70c94b1e7bf9a5ee6f8fafc49e91e300b03f884d",
"spend_index": [
0,
1,
4201556418,
4294967295
],
"result": [
"f376684bfa2b0db930959566252814fdc4ff59ba9d5203faa7330d050ad97efd",
"72e9356eb5405b41e6b2ac587ddc98d847d0bb08eef936d7fb0860c07bcd74ac",
"09ddcfd0d8cf5ab3c2f6af59118f0b2f7bd7624145cf4a4b9145c32f844e7729",
"02b1bff8bf3a967804f28065609b74af482b26f4a64621ddeb70d428a32add89"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 9,
"Witness": true,
"Version": 1625509545,
"scriptSigs": true
},
"hex_tx": "a94ee3600001046790111b00000000000000000000000000000000000000000000000000000000545943e30092a9a53f1c4b2ec5000000000000000000000000000000000000000000000000000000006ee094afb7b4f5af7c7d82265bd2e2b8bc5ae38828fbe8ffaf3091f8ecd537b26b7aa2e3e240f30cdfa8dc2a412bd416bb9b99d503d26886841452e317616b800818ba2a3b9ece930fff3d87773c4a604246a03ee5f0a0a0b4a989708bdbf7280c966c9492e1dd84e9b3d0a84789bf1d8d6cfc6971992779d694ff4a772663abceffcef63b87915658906a877ebbedb213f9536469d33f69bcac651ed5f213b1289ab8199581a4bf27349250ef44b05cf43ae0615b43595ff95b98ddd78ba90e1757864b00000000000000000000000000000000000000000000000000000000da523d1800c1add33322b102b500000000000000000000000000000000000000000000000000000000f87411a8fdcc01bd9a5d2365676f47378ab9d858c3624bcf2df9a516a3c0b9043d4388daec747865a95d5f297c59881192b98a81f2b6af3baf5b36c19ca448a31314f00e4de81ba068cc65a1d764d7efd1a11d8b0982bfb50f374125485e5f081ebcc697f013f8d837d41dee720bb04208768565835328bae9b514f2440087c3c8da37b5d46cf93a6bd93841f6fa5fb64477422875716dda7ac0662c682e20afed97aeaa4ad186fcb18c82b14bbabf4273e00ead6c6175f610e737d6fb2d817b8706e89b78450f04a04afc16bac6cab646697323eda5efd55a80eb1b44a283820390d6ac28b1c13836609ad1aafb7bce2378fb966b087307b1ede3f58d981881fb8781ab9dcb65bf0d360d7da6f8bdaf010a779a1209011545f5cf0e85bc2c43de609fbe2a1efc57e11ccd369f8470e819dda356034f097a6e520e192e158630d6ebcd6edf35961d9868dbbf99255e97234e3c41d468c7b1a225d843abf70d0688381f46da144aa45fabe763e887a670831f844a3867cd3a2921bd275178985622c4fc0540ca3d2574ccddb0992b53e7716eb1d7c92c6be2022f14bf68543fe8149f3fc0ee2e9374e7bd5225622e8f35b4b41a244253736d447febfee9575f98bb2cc370f714485c5fc5ddb785a5fe55d022e75d5fcfcf09b1287f580a860d03c8d2fa4a5de87d9f56b5644209805c61d4b4415dcd71b4e97f802dfd5d60acaf49e7872b3280c301d76bf39c4390723778cf31b80319e948ad8b7da2984e7395fb0ae8fbb0183692d7832ec38f80ceed3b8caeedb9fe463cc8e16f9ac50e139d6c541f72b55ed51fb92abd808f453d34af516eacb831f49512cc72dabc6bfbcde8efd93e95d751ec26bc4af76eb9450c0872aab95f49ff69fe074da673eb3c6ff28d48c5085578639e185b7fa4df87bf247945cbdb7e4681355d5c36b763ec54138dcf19e74321344aec55871ff545cc3cc836ff9d62c65cd510f0cca9943b1e4ecd81101cf022ddfd7e3e609f1183623f01e7d2700dd625b0c781f81274634c48b073e000b910064abd4cd212853533b9712eda61542dbab88554b497f8533550d59be0f18976e59a27fcc106bd36cdcbe93ecdc92588288a043c1ba996b73f4df2e934eac749aafc81914da297c4852b3f4e2beaa5fe134c4e5240d84bddd864913ee59be547c78c6e4dc495ededd981e97bf6437cb88d8f5b34b675bbcf07372af1b5fe9c4e2944fd7e15e85a99b7149c1c7eaa680919b6958ecc569ea7d19e76c820e9aeb1b7f916620778b3df37059578da8d8df69b940b5b84d11a60a35e9bec9eaa708492fcd333d0584435146a29cf2987e5bfeb3fd44548fc8b1f15477aa8f004c2f2f3a8552dfe2a691ebd19e6786da5c851f9ebb3083c4da27bcad3338ee61f2145a18951db4fa729e8d3cf1b52bd6538982422196bfac0cb601d0d54057f1f89b59377e85ea9dd796d6181a23744f555a286a80b8df454d06679da9ed2f16533978b4ea26ca74f3c36a6adafa4d253cfffcce4563e936fa51aae9ef4b95e935bd2dc791ee2bc51f28521e4c51fc867fcfa70db703c750ba2f009c3143a2fd0a63b9551caa3cb90d562b749cbe3cc6b8bf4e6ae0932f949c53be5e1f240834696f14d3d8c99519649591ac3b86b4ca1ad05582aa26c278424d516544cc8f3d6ff78c81fe0172865a971cdc2e34ec9946426bc9bb8dce8cbf9ad7515f9fc30f005f267e56701fc0d34397e3214e9c682025ea6adbe454d693bb749a3050b1f18d665ae6df1b42ab548e5574d9ff63f570dd287e3ad60c2733d4491fea889bbd362961c51bb3b103900fdf2027f7170cae464b486f1438f0085231fd8f3d664c80dca6b4287ba08bc7d7242c6dc9787a217eda280bf8a21795d9c474504f45357f0fa404d3e2e5bca1e5929f66dc5bf01967debc0ca6a209f831f1603a89ab336e0e9c10d4f4b9635daacb43824d3e2b847a4ce64da9e24fe72fda4b5b926686a9344a9fe6dd119f7c4c295f346e2b711bffa3c72fd45896cfd99aff673b98ba4e1766d0023aabdcebe3f345149a56c8a4cd2b6c129fd43351a028e4858f431432aa54b10dc568667b4e4fe36bb61578f3a4dc48f5923e7d5c0a1a6df4d97e94c9bc99592bdf224d70f2141a685ff7f45c86499af059c1b445d3fed29bc3649bd14f32b2ce4ce858612a0ae69613167349f100847ef13a44d0d89693b4b78d8aadcf4d49288d4f2455167ade93d1a5b974c8e196c8b0a7f998426ba6b3d6c03e0df46c5981ccfb23933fc271ebe83d341cbf869e2efc8cffa4233e306d9110f9a32317cc0b1e2b8a7e3360c75322212fa2be127995bf61337f17230f5390780e9828597c30db06ab9649a0627267bfaf7376840c9c0044554a8cc141897d931b89c276f051de68818643eff90ac3a8098c7f5796bd2ad6c219c37bb5fbc200bd83bc8f2af1fec796fe37b7fbaf000570f7586ab2653b0bd68f6fdde362067a7c1348faa2818c9449fd8a6d9fd602fc61f247894c3d0ff817ddbf3e247b98501738d5c7cccbc57ba124e3c6cbcdc164eb1820a0e259a812c5609b3b0a904ae9e8c979cacd5dcbe17f0131bf1ccb89e085515421f71c0bf5ae6146c4b918274d6b89ec04d9f1ce291ffc0f4cfbdc249ca96bed942cb72a9b8d358ccbde6522c3365ee8927f8ce7c526ad36f1d77846399de60f7b6a52dd5bbd522e285943bc9a909dc7ec39251d8e971583ad02fa3dc500aa869c8759d711fae7947cbf5b0195d58b7405e58d4ac9e54a58f9a621a8b51bee3f8abd9d4b6c226e48d92c3420cc7d3303b078715b9d567dffd7d3bac2b5a57c9432112b907e1796deccce0cd4042694958cd658e9d3c04546a9982de3eb37d0ed50a0ebb29f133c0501fb838d62ed0df0d838242911390f4d43f044a15a7715c255ef19b4d5b11dd4731f274707d777b8632515559867a4aa3f003ac3939aa6e30aba14664c99fdfd8934db73bd06294665d6e32f90d5c83e838d7ab72010df44e05d0e5286d561c2a4f81eb587a4b6b254fc8d5daead403eaf3764b89b764c7dd731d1be3174e18b11dd3b6b4e98519a778d6c0e1f499c310af93b1560f96e10efcd3a9084e59c4ff47a0c5c4c7ecfc4e6d589bd6e08bd06e942d1247b88121e50047d301f4a869be59b34955c715bd446dc67eebf193d8fe00d76b23db2ecfc3dcb6a06d056725758f33951c2b5fa120d47b484635e1f2d8020bef59a16cc7421160009ed3b6069e479a824b11893222ff60ed1980ca3bf88de8ce972a644a752163af20b36d943b41970aac4b850a443d9f18b514bb3e03b67d033da77b25fb4f1c489db95b2f78c9665218274e62c98273301bde352ae86b846ccd821885d3361f1d5afc13c1b1636a997ca26dea1b334bb78946fbac6569fd69014c9bf5ab713a2ee8f6a72bc6bf10190258c6f48bd0b395be267414097baefb1456aa0a0884cb33c76a123667ea435cd0de4dc413650c0538ed978e291aa24e93559ece861b675275721f926ecd381c53dfe7291b8cf22f747f5c55036bf465aa4f153cf1624a574b5c080c4ca682d1f42b91a4e82b9511c5d275eec167cf49a3a89450731350eae2c9e5f309ea1f8e68472d3a49831c5c4b4362d8f61aeaeec632b9706983da569b85395823ea55e93b23bfcb64f684a9f4a68aff2c93b86e7cdb58ef623e5d59eed84f2b3eed20a4de1132bd2f812b61efa9b17aa25927e42dbab8c21f4af249905dc0166af99fd611c43607654c01cfa46592c3d9cd0b0776da70f86a1b55b9c06006691ad3705177fe1e6c2cebda66f941eaf97364130787a06b2a214fa3bb038367313e6131498a62b0b30ba56edcbe7a58fce7608310a0228537181fb19ab602a5e9372fcf7492f1ed0beb70be36f0f757d0df2cbe73332dd7ac05d60b2e83e8fd87019ff6bc3d4fb512dfcda6a3e29e1c01fddd37c6ab6c11929cdb86df09441e2d4b0f80d6576b0570ef9843a7607d7b970cb8a8e99314effcfc1f0e913920ca0bdbaafb2234d1a77128a2838d20c4656451b5e8d72ea1efd414b08c15ef9306abc123d56037e1f59bd27d63aa88be5ebe28245c80ca9e0be4c4011407bb4120b9717fab695371e21ed13aa01ab717fad00575a9d85478f1fc7d53302e939716485f3b852d91afb3564021c1ee7a8ad9bf20d7433c16a01451fe4e1e2f6dfd1aecf77bd9303c54ac2fdea612fb2c87df6c34342685a0f03ae21b19748a15cf1a60e3712458a9bf1d2d3e04d2f414b2451f1813f8592898c1c5a36a73d71271aea66e10ec13c2dd490339e5dbbce6f3b16b3b35fbe08160b5be033603f72e3f3ff5aca86746f7250e9a359827d0ca7618ec524c00d73bcd4fae39ba28e87c35ffcf4463af0e48a70c86bcf132aec94fda1ea17caa02cfa703aecf748c6c6e5c1c5d169fe95aeb9a6ea012705c5b01a6c6973a2725bcbe9f9ef40de926702c21d7283979ae1c8b585f3e0004fd8801deba48b98f0262a3c550d27c988f26f10a49267a3d9a85b3c409b50857c67b3ece0331cef7532c133de6e7f6b54a4853698a3244fc6fd15c596ea05458c4424c20b6339c0e744852463beb3ec3cfcf8bbf65d08899dd74d6e3a556a7049a7bd61d698a17b34b30e9941b71350a5be9e9e8e0089a4874e5342849590637b707437f77ff172b712ebd9a9ac1b6e76b2fd33a49f3d36f50497f46c6f2d3a085b7eb0563149fb8f2f39c047f50525ff854b14558bc8f7c8beac426c3dcac538f75fdf4fd49aac42969cfb20585bff065ae5ef60945eab906e742e1e749223590c50118e8359a90a4843de23a1c823dee772648ae06f35ab654effde4ad6c34ceaf25eed5b0a18a505b3cfc207e0113d5518792cf40e9b3aeec4c87d9a17a4e6dc5f2c695526feccd08f5ab9ddf88175342fdbfe98ae206397a3643cbfd14625dc5c82c6298ccd7664f08ce5dfe1a0301287fc001a00c2bf659cb177ff56a62034075ca4aa4f7e8c1be7c628f9d15708de52f91419e873f90f21834047609445f15d252341e36ef057beafd8701d2f319c25614864faaf46ee3f5e36b4fdebc127eda0ca9ce6ed22a9d416457931fd9b0740d9683c1204b16bfb6df57cbe29e7256f34cc3ee19c5d577462ebaa2b4ec7ee3176e57a3f79aa277113d2739a2956160696327ab0b9e3db0ced2658c31473838a29150bcf4ac3de0d46d3aea6c779f907a3fb76e207bdcee02b7d90c1b7204b7c98252606c46a9551d641a7a7140ac45ea398037035e9423c7f63ff7e69e9bb627ad9024f3f8c668bfe5139e811a250a8841c1f7a3ea54a61663c120d0beb3d3adf70d2cd9828adefebf536f0b17d92069393652253f4435fb5a598678de9812c439c4a0ade84407b092fec5efa833da4acd19d7ad43964f418c99c1a5bc26e5508c67f092c04a5535c09bb73407a65565d6ac5d77d3ff6a71fc086281421ee787941473c0b72c2209baecde9ef437fe3754b3765c5ebecbe225afe368d811e41ab8ca75f6cf45f7f1264defee12f268375cdff5d336b63df800e88bb686172b18b9ce4b02f1121e44ec7496413da8a1c32ec09692bd3c2a3f826a9eefd534112cb1e8fdde01cc3319f7151e3dd276c948be81cadd2baba98d7dbf4397cb6ddd4c7b31a3d95eb7f125ed79e15c4c30299514baf3cf2881db7711b8d7af60704e76ee3d86ccbbd0aa86c2f308b8ab89f534b9c2b3a1546b3c9821a0c6b9f616f256421b345d25bb84e5fed0c509a52e1f0796e510601e794019e1c3332134f19c477e4888756a274fd8bb63c79fbf5c780c0b1b1fe937200857d7d0b0d5603f6f1d1b3a0ff9d036b237d2f1bdcaba86d10304456c8c696ea600a9f7c4dbeccde3d115b01a70003ed688814b3969775446edef9fc0c72c1296ebf7e4693ba15aebafddd53b77e0e3804fe4b822196180b8a6d9ed5bce10bacd1403ee2767ba6fca2d776f862446b5dc5fe3897bd8a77ce3eab32eafb75ec6fec7734e476cea87adc2b97e83afedd43cfaf2a624cbb5d5a047d967d53ecf8e72f8adf3c0f24307cb46a16af5df7e47b7107a1531cf92ba131aa35da4ae08877bda6a76249f8f57ad0ea0f9f6115cf2aaae61ffef87a64081db7a1575c5ddedf1629cdbaa784dbf9392eba55e6ee4fb8e52bef936fcdeeb66873fe99328b445719ad443ee1df5d82d6526361e09ec9d0ab477b1e46f6fc23bf333f58514e346168b48d1985acb25e57f74ddf8eaffb148d2dc8d8fe02016a81475b0c29c8cdd9e28b2532892c4b39076106c96fd3e019291b4454d04ec10b2971444d6b66099e958baa1108e46459c9280763fddcd814ba82ab527abb7d5768d9682c1374750e942b9dee5eabdf79abf8451d61314882fbd3013048800148390a072afc8ed947b3ea74937f2b22e13cd03ca7c9751a2d21dbe4d81d0875324fcc6a2583b5bebb87e99d16c80b91d76a346d06e9dd494d762bd9b1d742cd0bbd9a4de5c420da980007ac55cbd5c46640e3ac3bcf084dfe5ced8ff5a11fd807e6c5ee8fe32329a24d3ddaf560dcfa4648314fdc14db47f8d6534cedef625f421847f9226d83b3dddea5b41470e67ade0459c15bb726023b6d27467c5a08044a14812ea24c4e68000bb0bfc90cda986e7c81f6ff341526efac4241e82f6430b430a43e9c4114f7eec04126071855707fe8d1e2787167ddf3a2b8d30f95f38d1b3a2405ce83768780a0648b330dfac7d7c1426f7564103fddc01f370c6b93e266c89104335521b28688187286103eac0168283c11af57ac7f0d05d4f9336c1a30009d860851b8cec27587266059f21478e7ef2752ccacd71705f951d6b55b3afad1d0ebc583be05ee6e0f6c5e756596efdcbc83059f6bb593beaa91a490a556e78cde7e6f3821de41e7324057908131f0c7f37e2837a6cc0f1321ce62b93e399b0b4a79062024783a8446c9b9427349d90c7a4d5ba6722bd48628c30d159948f0f93fff844650a00f6bda9b10faed50f3940f38c5968ab767e80bf4ac572c8397842e8efdbbee5939f6a4445813ed3c57c9b1fd9cd7dd4a6dc40d109194058129e7cc3f7e0487fd2f556fffa898904c8866abb30d66d2c1c6bbb3d042ad8fd9fbe3bb093b2141ce2e4c3c7db1f15859f769b3ab8929e852a3fcde1f6dcd25fd8174ffc71c42f7a64996c65dfdb0c12ea543106fbe9a5bdef74604e103706097a66b8adceb20961602b87a2702ec0b193f22756488cb3bda03d988795b2392e1ee0730eb182142534ee7f4c3208c63aeb157e932271bd934ca5fbd56462cffc8a9f3e6b3d99d8e2d8871304111f2d1c93f26e6b5df35219e5e992c51b5df47ef739bb08b44271059c9dc1e1944d7ac8f6c05eb919aa5a6aa7da1c1b90e8f0bbb104652d26d8a8b5e2fff42ff63930635bb12fd1ad614cfd2501bd4acb786378759292bbf8282711c45aba70d535e33b5ce634fd9beb6d7f1d0b1fbd32688186d4e6f8555236544a2661050973b0ecc043c4d63905dd40189755b2359905ef140aba96ceb5de166187fd0f0872f9a90e39cacd0bdf3a9b560c699a0968b3f092f3284f4ded68f2fb90fe02b737a4aef55cda3411ff463924dac13fa10a7b904656337b0c4b94d3107e917335138b4ffd5f1ab7f54292bcc733fd69d3ae4b34e0e08fd1f5a0d305890b9ac16d87cd7fc97e4cf944e25695f0fb619dfeb5e8acae19827707c3f54f0762da943d8dbea354b23cfe5fe09e2afbf9e21c987e46da2468044a3a5cde33d290666d4a3aac527b0a71c905e9219ab03f0c29d6e54d3422c4124d0ea2398f7632bd71ba93209bbaea4fd2a79585c3c21d631f045e57fbfdca0130e43926801072279cc31ec402215ee3e5e757c17e78f261083211705f6dde460d6a5c02bd5131e513ad7d344e7b55aedd78dfd52dfd1f9abcddc0e673e358976b0c71c50ac2a36cbbfcc11ca367ee9b1e452caee62117eef0da47549af53b89c429eb9f3f79acbad5844ff3dde317abbe534ea297792e3513801dc8248d2cb8f9d1a92badeb6af91a299dd29fa42c5d1d227b03d4a747e54c31b9f3d61f3b9ad05155a30261e8c7d6323591c315b165e3fbb683abf854a30dba09b5e5e5966b010bde007c1b491a70218b8080dffaaf21815aa7cdfa0ed109dd9fa5c5cb2e11600e405a3774e45ca56ea2fd3845d134f3d6a020c5b7840735199a45093ebb8c7f8cb2a242525bff4e597d581d1a705584736b7401a21f4f8715d2b6e9f1323abc953dde8e2053e1a53a0c07f892b06289274fe690d42359698dc1c96fc18e1ce600eb76a57aeb872831ef5978b5e05377c02719a4e936572dbab0c175dc8fbcad4b862bfe1207ebd76b3fcd0663eaf52d1c6700987a012336b3e832d6ee2cdfeb82b428e269b0325f92e5b7f3a5cb5fccc139a2bacb72eacb15ef991e9815ed4c8d5f89ac442a0c37d528748aceafd7e37fa4721feb0f523b350c4784d8a6da7fd1b6d18ebce4dd39f9b15660db",
"spend_index": [
0,
1,
441925001,
4294967295
],
"result": [
"61fed38368a342a1336624b783391c389a388c8cdc13dbffd4b6cb1d14d5f663",
"5a7ee9baa9110eaa3059128e189c6ae509ac87cf1ff8e1d367c04a2dbb969e57",
"b54fa08173a4158b4e4f070ec71a9f6c0ab419375a8973fafe5f60233881d668",
"30b58522d3d002c2183b16d31e615a7e236d041534f9348506841732136ea676"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 10,
"Witness": true,
"Version": -185036123,
"scriptSigs": false
},
"hex_tx": "a592f8f4000106e8bb51a700000000000000000000000000000000000000000000000000000000708d7cf40065e4b9d0c8ef8fb300000000000000000000000000000000000000000000000000000000c71111ef002814037f453325a5000000000000000000000000000000000000000000000000000000001ffe84d400740f76d220e3e8bf0000000000000000000000000000000000000000000000000000000029e6fc760068e41b6d3a60b1f500000000000000000000000000000000000000000000000000000000b93bee93008c720b4adf815472000000000000000000000000000000000000000000000000000000000f7d388900619856160a2508eb4263293469c87e673a485139c7e465bcce5f1fea90e7b138534b906028798e78f92bf2a148c43ed94759ab86113a6be774baee58de044d18b2835257c627292f7b6d561b14377ce45a7b0a12fed1a76edf981cc235366749e396363bde8211ab5b80ee9601d1d433822b04500dd6c32d14e368deedaf2f51a41eb8ed771488d77beaed08a70e41d25f72d5e33bc8cf26a5b023935750e26d1a87063ad1213a796793be36ea06117b39ba7ca3863f5897455a80c2a9cd5f6ff415186855ecc867b986bee4c71d70fd0e64e996b72715c71f9d7032f163c81dcacfaaea94cfdf0b0580941468687583017c3d656772be4b5ac32abaf5858faeb566e3264c009fdca65083a4103ad9c694c683713d6e70186c8749b2fcb35e1eedd7c087bfd5f3409a8266538f1531a52bd0d0cae3c8390022a5a95e85145d4a8b01a1818450b6925f942282b956a64dd577367381090753e13e7cb2eb4c3188b92881270282d6c755063854a620e90d41ba317fd49710fbb2ba7e895e715a544dc09317995d9e498ec7b22f35b3cc100ed5249a3bc0c0a0e73a37057d531bc869310b647e75cbee6f7a85032dfe60c882f84ee1a6bbcf97c5a739292cbc5e0978875d89f6dbfbfb2d29e9d4cc5019a5c07767a583100f8027648e9babc85d50db2e9dfd881326802fcb616b3b5e65f92fbb505951ff066dba1bebf9c6fe78c182950a5ce2c366741b00e42491d025db7af388ce99c304f629e97934aa96c807944eca1a07bd49ee8fba88fa023f99017f418a20fa297647308b556e9e7840724b2643d16785ba345362229af335bc23649c13a19110342169229061ecb8b2a9b232aafe35bf87482e9efbb9909da3fab76ed83f968a898464c6ddc595cf7a7ac802a23f70e6b5efea1a5b3bf0c3c0ab7afbeaf577984126cd9943f922601da4973dab58d17fff67a95551e95c2e62fa13a9b8cea640d6c26a28781db18f5444762975955d52dc16ff4b427603f86d581ab40df1caa10bfcbfc4dc8a416ded825a724af5cc4d3f9c1f7391a187a6ebebf61b8d5c02192dfe9bdfb46ea4818d98cbf73d11958d24949cf6b646038ca369d9768f634332578c67ea500bd6b0e76ba43a072f582613a0ab6ea413da30a1b1f544a1dc4304451dd8e01fe38ce9dbaaa5f372274f16d0ba26f9ed4fba285b341ec86da0bd79ae04455ebd2e94e4a2387d46dca72cebc7f92bf194dfb9ab31182c1d0511288463dfca0545a8ef6c02c600ab0cf51d018d780245adaa303f222098e7839e5c174f1260a9dd3edea1d71ce9012e60f2b7dd66c010b6e75fb7bd5de8b79a853f2834cc827ce248c377ca91973fc6514ebff8eea7188b05b36f5cd36ba6124c36e94ad816afdbf19e32f7d5c0959bb617c70ded54a69e1db94d6d006f88aa9cc5f30ebe39dbdb8ff24ac67284dbefbefc3ed7c1861f4b04169d453e4b6ab7cc6fecc83631b2faef2f11ec45b749c81d5bc69cd40291d68aabdb6fd91df9180070004a03696d7963dada036e07f16e2e737a7b16b1e6f7012d399d59b91f19455339ea675703128911f39dad30e14b82947e3a7d329bd40fa08f2b807e5a1d8e1e521479cbbab88e684a7f1c4328a46c5012bdc7b55008d5e12ca1d0b2e996a4caec0becbf8ca2a1b69d767b610e791071e4c1a338002a383ced4c092b0b67ae2caf2fca7b57a06bdd6ef17d9f587362823695d6105360245294e53d2dfec39d4e29ddb7eac0235ecc41531c0b8a7ec0a7311fe2b6f3e45a0f7c65afa43471c89f0b73cf419d469914720d7ed4a30ad43c7e59b22e4c60265b29a8fd2b5ccf83b31f4eee6fc9935ca18ffeea7b7ece9361a6a353e44988f14e3ae548e61dfc8fb6756c5d5e5349b021820a1a45390b4d81b0aba648ae282da6e7d38f1c6b358c7a310d67dcbaf3febf3b6aa7f7065404c9a1520b2ba52c4d66c309ab1d93f3c29966ea72e779c60a0402fd5a58984ea80b8934b0837281a5c7c821ffa2fe84eb683557c2aa26f113adda1f8bdf6b3dd0f26299795bad6930fabb06292c50f1856ef520f7110fe8307946483ac4ce0a26c80048f4ba48022365925ea34fd6e87373481f83fe30bae83a1ab3a830d23360defe7cd1b26a40aa38ec40f82e22f21233055af6739efb49f6fcc59143a22f0d8c4ba7fb4eb6bf9f9d742ba20c84a2124fd41b5f9988a2579e0b337e17e8cedb9d6b633557961f84005a365da0a71b15b272cc1c3ca14f542b1e0ea0cdd0eea992f5dbbd2776b798c050a383e3d20fbf367656f15cdb45194bb8795619ebcd1345104aa9160392ccfa4cf5d961075f0299bfe063ad6cbd027d64a889ecca40c3ed47dd19f12f5baa5aced2942b80e6704ac877a3018be07c0f7b567017a0b041674e6c0c677f475442353417390080dd4bd88ef7e559afc7f7ade37b3a0b6d00bd296c70be73a74120ec94c0df09f139768c526b1812b25b1ba1889a81b35804c3b6dd591a020b163f35ac2b4e23e325350e7c41724578e2902ead93425874a6a7866afbeb94cc08aaa4dcaf4abc6c2f7faad48afed0c0ce1a46fb61c894954d8ba1a880744943f9648952e10a23b3f694435af62572bfdd43a1346e8a728664280d30354a11530848dfa565984e193bf2f80e5541c5c4ea71b63e731367af2d1d23c88c3d6dccef78ca0e80733260b125affdbc83c062c46cbc9f1187711d73ff98e0cb9e1c6cb2dc7453cb73186a40b63b95d284a326098513dc6ed550c582f94af981c735439f4fa7b52dd9d05d1b0cc4faaaf30ad277d9bba88de0db5f10cf6ea9d407f19f6e5d742967333c80b5043d972d6e3a21b650a54e68118da346fa78f4811d3b4d7891286558d239534e9127bc9e920dfb5da93f949ab693cc848825e076d9f8f7726196b87e133b3e8085b2a6b38c5b1c840d3efc6f512d64c0218ad1faa5c749cb565aee02fd5d0166df4262f22cf93019bcfdf0ae93f18e3afd615f902b0844ad0e168fc77056c0b636109b94d69d12cf284dbb992aace32c9a32c0bbe5ec5380fa143c8c123282a80c543222df4e22bced32c1b7890a5fb2a67efd5027966d6d68e055c43d0c2c0634906feaa9eadb0b2e0fe6d91a5bca320bd8273cc15db9e0f7dba60c6e8bc2b77a1d70825af39fd0052a6e6c8ce373d3b5e71a8b60a3ed1018cd34de29f2cace3d0157fb0fce42ece8624e72d86df89e8ac9eed176f41db7e729e5912cff3cd81ee07916771505a1890b8d7bc997f2ec973aabafa130b2c5be17c28a13cce96b29bc991b088ceab221ee920b84c2a5cd755019628fd205afe3cafbbbcf42ce72a1242535ec9b100d3603fce9dc2e72febc65c03625eaff0e91b76ea8cac0ebf55782ec1f10c7c40cc2659ed91e1e7d3f30b1e3f440ab8fbeeee9d236a116019ce6aecc8c48bf9fe9c03a210762f8639936c71a65662f269acf39426edd58d2aac43a771bc9e246c283fec3607309ac425a1cbf9f8ed292d015ba9622ace377d1b5c6e86d9a11423541caa1c63bb362bf5ada5143523e9610e8d61019005c4b8727dd9d92987a1dce4ccf5fba3ba3490a374e86eb8ae296dc9166f733d87f6923a3eed1230a01dd7f2083f1cb704e0755d1c1a5bd97799c9cebfe1ba928427fc12a0a67ee5dff4b1470bdd431900bbac2b7da6e07f6b29bbf10c704b36bbc79edc4339ad4868c0fe62170882ec0da64384f6935648542befa1f2204414afbfd854141090f51b927a8551fc5e949b35d37c319e812e89de5ebaf2c03e635389a5e37546006abd699a42ca3c6120af0f0a24cdcf60d735849594a6aeb3899a51c37afd9c5684032d22df98124733078f8a1f327ffafa2e9f8a142a8d8df4b9de5b70bf88706e78525cda73e190d6f8ce061353a15fb888cf976abbb993ecf7d7c4a8a066bc0c64610f24aaef64bcbe65220b2069134489eb7562aeb7af7dbbfccb87ad43a363bf2e79ec2b0f7c117fd0bad18668e91c6d98ab2616848f371b54663d3903fd26f5ebe9c63d034beb49ebebcc6c0493c8dd91ccd5e59fc428ae437e65f8790f4b48096e2d381a39f8332cdb77d1996451b4fc356a3380f41a1009b6aa5b22d73993fdb373a7bb25903bc6b608effadfd557c4101e6e9362d77e94f641742d2b0f209f4ae631531bc0b1a0597a166f102b64311b477e9bc44aed12f32751ce27a31e0d8723c9a776a61f30817e6c4a4f8cefc00c1c67f68e93b0d52f5f714968b5485bf4b3b0b53a9660fb8fe1aee1c739cdd558773b369894ffb841f16333fe04133e53957ca1b69ec84a0624bbca7aed95dd752871eb76a371a86a532714a99ff10cd593bee078efafbc1e96dfdb8f79b9529ce2835848b84f2cc370827616fa756cbdf59a22bdac3d7d18a5fbe0408c74b0f37ebc8fc00bc4fc5046fd9105bf8dbd6da4f5b8b6fd569e183b67c397e3cfd8a65713cb44eff2de2842755410381344b9f3a8e23deb6d9ba8898699806185f3d978d56abfea986178ba3269241a922b48e1868767a1ee86ac04b188c1102c11aad73997a4dba08ce0ab3d63d71d7bf04876047b7f286c751addb76ae409c4ea330d6eeccb6f4432acc38a1cc059aaa4c587847ad530b43bd791ac68c29a5e428e93b15a43909456b6fa10292ee5a4c532d7dc5e7554f7b467849a935ffcacf99f8d6fd650111d53e07e199961d5088b46450a9f6ce448a93de8caaf1058f65a6613bbedf7ae9cd22aa28a3140c4cc18b73fa4c3bf92f92561af4c19f1635976d1fc239405b2068328e3431214462385b9bc5c710025f06759758dc3d6ff1b62d4e397c7107e1405d6cbbca13a352ce7e04e918bd6bf4f0fbe9b394673cd98aa55d93eb6d11b649e58a5aa5c223650d1024c94fed3d0b9efd48dd4da24dfdbe5c952c9b1d80e057e3efeb51b609d3e1422898db4a8ec004ff2c38104ba42d3584e0915fe6a2cbcec85ebf8939ab11ba4be91b35ba6ff694dc45d4aa7094a86ada6e5f5a522902f0a134e61b5f5f7daae5936a9c38d85f29df0e1a77323308669ec947f7237ff4053160ba6d170330f726a7b2f59dbc1680d401bc9dc7b29640ba834904d6f1b293f5989f2d65611addb03e539d62c294d184995600f5d369de172fcedbb9ea34ae61b31f4d7832ec575fceec2ea685d272a854507d2185fd25cc96250869d6908901c5c6fd92012ccfbe6ed1a8fac96f7331cd08635e6c3e73338876181d3efee51741760358df9487da9cdccd382dc0567750bd7774bca526b1720246bfd8aa992289459aa5e95ee0b45743ecbe1fa8b302a7e403cf7644e174634e15656c343de781410b2b7dbd0e37c6b93bb709b161159887c287739a57d4ee08b9a11083463a8d344e272b80ad6cdb8626901d5b1b0ce41d73a4b107585d13f28de8f9891a799085c826ed2ad8d7bb78c15e1de032cd25c772e63e9695cc23d4877881f73148cdc8161c287478665eeaaa23113a07887f69efc146ffd7dbdbbf9a3bcadfa7c64fa293f4d535550e8419c8bc4192fb6c5dce42aa6dc9c67c0e967af4438390f0e972371a5216c0253863f34c6c4e631b522ffa1889f4c38017e0b23c3fd63ecdf486ea34f1fe019a40a254277c4ebaef0ba2362e25fbe7f806c7c227085aa6231932cf303a87658fa7a4c001f0d4e46a5edf05972c2bb6bfd2f1501837135e8f8b6c2e079936002ded1a010ea9f171b622d3ff68e234e20274ec550d02acbaf5fbfac2b737a8ac6023ab533dae8ec9bd8401aa0d0b2fba000001fd2f01404141e579ee903e56f1289243287c5dd84e17d7b55a303eb34c2797bcdfd22c36f435bf8812771181ece68d6e5d6243b8668e54b86788aa5649a7e233da4905bc311a5915019b062e61f0cbe3e90a920d2f0affe0dceb8f275ea37b006e3f784c1abda9cb69d750b29bdce86cfe03a649d2f8236846936d3394ee53a8b5a73e4af97ad20fde17b4d63058c012b39b0b0469da5a2d0ce8f7f9c5d4f65f3f8ea0a8fbbb8b4a9f6f156ebc54e2860c82ec59879f3704f25bfee0866f4d68c6dad93119a23f167d21724ed0bb22211f26c055cdabdb3f19a74550bb65f405bb1209b341d0b5b5287eb8a5a2c6c0908b39a4755bd65891ce628fc900df05cbea37713ee7347e24cd8e89c16bbcf87f9226e4007342a2b969acd20e8e49988443fb8edec541aca26f9b7ad5a2e38b385f266abbb711",
"spend_index": [
0,
1,
1289772662,
4294967295
],
"result": [
"c971010563dc437bf26f5b6a07a3113fd9784b8725d9d2188ec91c1f264a52d2",
"a38937f3366efcff64e1d6bdb117038a18aa143fbb2e5b86752244913dad4faf",
"89e143275f8f32676495cabb322f8fcc10acc1a35b1197c168eb54e1fbb6c982",
"85affd74d62d7d0451005be0147e1e1a0b5f9af8a53352b9a0973ae4421abc5e"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 10,
"Witness": true,
"Version": 632683292,
"scriptSigs": true
},
"hex_tx": "1cfbb52500010740e8f8f7000000000000000000000000000000000000000000000000000000002503d248e30e77076ace70e26fcd219b9b6bfb7da2fe31a7fe80640b536b6f84e2946e7d0cb86e3ec469ec52bfb084fa3c79ba3f1a27234354742a68a78b7ef9f8602429e9e7f04490be0dde782835638b16df8dc7735753dfec0b66ad9af204ffc6a7fe4ae94c987117a1b7002f666ff18401727e0943f61b7218d48433deb61571c2df7b4b3166339a78bc8e6a59decbb68af1272b44e4bc4a8c1795fed1f9090c50f78587e90c494b1f6a8e3b3f6cd8eeb23d2390dc0ed7c70ec38d0fe8b33eea242ed0d8f349f8c5dd479d3d21bf4f5b7331b2f662ffdd06d44d17fe30fe8c22e11cfc3e525beec6b625d48b2a9200000000000000000000000000000000000000000000000000000000cc0029c83596530dad7556553e8288c54663c9f586851157d1b7895f5de0cfd012e97f28eb4e1c704b641a5bcaae6ec5cdfb97a4b4b655bc5f6232e2435f8f013a7f00000000000000000000000000000000000000000000000000000000a25ce8dae8d0bd30cc050c5ec668359b7bfff30586601d75650a44148724413213039fdca7c5efe0e9ea35920f8cfd55dee485edf867b21670ec04132cb56109bf31881a792d5c668f476fbc790f1e2869fc256a2d5ade656975f973d90c7dbd89d0b873770407aca7cb1268117a62fa4436934f7ea9495ba52cedf6d3512ab53f9f98f030160e9bed83005f47e366be298218cccff6524f3eb2e082ab64f8762e8202497c5d307f3fd5e36a6ea8ed6afbdff9ebed70578447ef094eb798065cbe67f05182b086e26d08a52a69fe7b289b579e7a4839d49ca250cb05f82bb0374cff7e40866caf731abdf99f9612b4c2f798adb808000000000000000000000000000000000000000000000000000000003646d723007c5c6fed6e889a6c00000000000000000000000000000000000000000000000000000000259275d60b532873914391bcd42b2b4cc3859e21fc8f86ec000000000000000000000000000000000000000000000000000000006554e6f9fdce01cde0bf967002bda3fe15efb88cb1e3eaf33ce78d4d9ba8fb3596f871af10a8a629642cbf2f4554477ebd643352b11bd2aff04071fc580d206ca4a61c1f0f0d95e4a04954363f4c4722eafc091bb96d34f30467c4f1dfa9b11de2d042f028d73f74afe9588f852e196b84d236d0a7fcb26ea5674b1070dc64cbf69cc9afe692232b0758b250eeed4cbdbd687e51876fc4b029b27bbb0ec3c17f64b85ddc5e58972d7e352a5299c1133c94004431b09706bc6a1d036e8b204d7b77895d718d57c5eda7311dac7643d1c2ac235bda874b019f6c83ae637225928bf46bbf54173a5c5612e61d956075c3024511be9f51f08f65a9d83b2f2f2080a036fe744e35e727af51460ce75fa1b5e8d4d502e7143e850921b7520dc6f1b289093c83225618fb6eddbafb041e7236c1fdb8f921bf081802482f717d7ec5eacf0ffdac78eb4dbfc3f34ee84163f2482671f82acb18e7315f08c34967e541d63e279c796a2345b75d4166a0298ac47a2c4ecae9bea1dd47a7f406eac66ca3a42c6a5542c1340f943ff61ea33814174fac06f5341ce7e6a3dddad8b92ee3bd88e78ccb5bd5a7d20c72dba952614f853af114976d00eea017bf408acf76ceb48884903e6f09dcc115fb8149e3198366721fa6a6a9bc854e53a405bae316960000000000000000000000000000000000000000000000000000000045c5aa5ffdb20165f92f6a5c7c09ead853a6d6facd976acd79bfd6f5f0422a051db97502c31654a791f1df0272fcbb102e5fce40805c15c17b0d2d6e2afc3a43e6f780994c4f599b4e203ec6c4703f7a84667bdff6a3e37dab6bb2558217e04b542ba15d12482a280122c3c821765ea73974b6f9328f25525d0d8092e932c685bff1e5dc98acec92f1a5a7a54e64639fd3e2211f7afd9b370310fcb1d8236c5c72493a378e5ccb90124150ef2d36fef47986d64ed1eeedc48bb7c165ac9ae46ac9bd1c7b7e9138cd48fb649affbeec0b85c46b5328eaebde9973a45eba938dde2e73342ee91c14022ee4d605c7ec48fabbfd84ae2a8f1394c44f1c50b5ad4130c7d88c5fec42fb71759670c72230c49cd9be5e3c3010f3345dfae932cf254f00a189edf638b4dd430dfa4297e0ee8ba504f694f59b8b4b3575366869fb949987fe0cdedf3c143a58feee268aec26f507ce5094e6a5e616bd088d94117bba64dc680458cc548fd62d89e48db5d1e8eeeb4ad5616176eef10ca0145833bd9d889ed7d7acea7092984d1e41dc2ee836b1377bf2c28f9d6ea4ce19305e5acb39070b3d1154dfc3e67dbcd9d2c3b81e4f5dfec5e682b1800db327067227066b0a42dff4e340f41924c868d2446d37bf6b0c024a357e127207787f0baffdbd93417605c2d649d8f12b68d24bb1f6e6c104e0ea524e980047184c1beed4f75b8de6a1da57a3c8872a5b7f6bd00a4f9b75bf0522a679ec3dcf3fb02f49cb84b8e689956ad27b6a68265fe0f0ff76b5ffb2afeffc6f241b7374b7acebb4d20252f0fa17f208dd45a644135c5f9561a77ec440b4008910e789152816693ccde8783f1b0af94cc9cefcd840491b33ca75931ea979324136f54edbe30eac853f730a5735ad3e0975c8e75e8f0cf44b7c648e4ca1550989a08cdc9a1239c8f93aa0920d8947f069b0431072f236b7af1ff78b369883c5e4788cb29ff9573d2b259d34cd9b644ca07ef9ed4ab30d65313eefef0b75f4d1f9a56592bb80510804a1b3b25440cfbb02f15c3f8d333411ca73625eda1c72d4b5173335f171fae4b7abf15c064c4c55c42ad8d99647313e8108c951e280a6e08f7212a3f370b7de4b0c99f4a2b9c4c2281105d75fc21057bfa36d817b62dd8977ff4fcb97297b42c63aa12ae3c7deddfa83dd9c16131d5db81ff81b0bc847efe37230355ef89e9a15ee88625d93138634d7251cfa50e801c8ec09da22b3c72bc23bd02e672fc0294484287569d22cea3cc58942cc1b74160e69d587e656f9a7ca7d42b4ac8f19fe8157151ae05503f168960f1375be6801b113bf1b0b11a413e743c2e26272a062b1cd389e531a4ea08c9ab34c52e707d732866e6ebc5a017d8d316a019cdbca19cbae476a412cedf917b72c509b03de852d86a0284e4714f3326aed6379bd7fab762257b7279a4de32b185657a615e8fab2ff3a7ac444ed21bf8c4ae53b281fe33ba3d3e74ca57f8eb54cbccc116d6c7325f82e954d74e33f350143ebec3544853bc87cf5b3227365459b2fac2d291c5d8cad2189a927a65de0325b23bf52ee21cb7857010749a4861e477c6479020f1dbb3d07e4943cb09f916a7cc5c4501d7eaa44a99764127c4c47f9e650e795596aa3c519fbaf3eb332ded4c781fc43c9e16ce1f21b4bde71b16c889ae2d9a907647ad4241e388663e5c06ae9000265d6816dd37467adc1d5a9671bdc5c1f6dec146266012b87e817e5c92bb3732a7c90f1bae3782fa4a61fd0c515a41a4791d051e3598dc30d1fea9a65771f161b4a7ca220defa0cad49fbb1d74a11563d01e0d59b3fc8a2209fd016cd395b05463ca538d972af482a6c81c1ee19be57886ce9d8d41632bb965591f5f0c8d9199d30d320f2deddd21c21d12029c0b0b3de350b40a4679830d0b849c55cab2e840992c9ac04dd915cfa2f3ece904e44575e5559cf403f1003c753f9b9eb6a383fe5e5ca813f23ae7bc0b69e0afa751634d8d46a3344b4e4feb8d89747cb1a06ca8d69dd18e22470ea7b103f37573e8722b4e0182d817ce7e12a0bdd0c33f932a4217eed288c46d697d3a0c466092da8b15677381a771cb6329bb171a42afc1b58f9c04c837dfb42c82debd37d02a4b894532e679c369ef5694b5c9252b0307bcfadf5de0cb6e5ce3b50bb4a7b5aeb2ea37512abe25b078eaa556af334717c86dcc818061401b75ad7428e45a81658af39220989ecb975df9c25601f0b6af3ae30b81ae1e008f506cbc2bd28fe58e8b4bbc0d848405394a9a5dcc8066c748cd82d9d07c654e872395058dd6d7a9cc53ce212c68215ce838a803c92e829f5c6c998078c82a0d3891fc286bfecf071d8bec2da0934f58dfc9c4253d94e1f8e3c774e6461b1050388ba268a404100f6cf2d590f2e59cc29f52451c87c6394cce83c8b04ce1ca5afb63e001bf8b99aff752f9e41b028164f21e610e59b4a6745677fc058bed3b215fcac0176ef4a425762f2b93a02d4673ae6eb51c7b967c154136664576c28c9ef153ef3035f4522cc19d880738d0efc8c30ad75fad6a7e458246a30d6fbac6f86fd911bcf8f031822253bab684da4ff67ae8d7080e90931395f3e61d70cd1db561ec3fa5d0bd046b636b9891e064e7ead4d2745ba78a3b0c09947e0661033b784153f8e3bac5d4535c4b932b492b29d1518a1deb730c1132e2ce4f6e9c9da9126407e0710c8f37d86e4836164cf35a302a412527979fcb1e17e2d56ac2124c7681313d872eb6c09365754e5cdd90b73bb832a4f2165d3801fcb0c4810d37d8f07d337de25220d01f239af918fbd3ebcfc221799323856d6f259f84f33794a149c0f994c1d0f082d217ac2ca4c08271c66f3628fc4d8910c23e2a518d553973078b6159072443955faf3ea16a00cc1a128f73e84ecfab6e7d1eb4a8518764d4a5c12a98cc54fe88288550666495923497a02904a9fb0b5c182fbbb1d9933d33452b2d05895b938bff9cd092488f796a2cd952e3daf40c85e2fe6038870d9edefbe468f1ead00a86b3be9c7fe5a028f5bdd4df57077cc826cdc55b5ca5ff5a61a46182049c7031d6411e3edd9c1ed2bd5976db20355d8a7883271f4b3b62b1d0076cf6413cd209b6c71a1e3dd4f4a0ff7eed310d4685c8b3c5c18e2c929be043acace3e4ce06a0a700fc73ffb004b99f8d3f6f19a037e99322fcc5805d6c9e0af4bda816be0a99b64daed3737d371512ac8ab0674c653b5976c44d2a6752d535d6b0d0699353b098f1a77744aab7507244eebafd5c07f75457d4415e38524eef250fc3e17f63f07c84e52295102f1ad924ece3e12a47087baf0335dae60d09c5818dce4a171763098d80bc6b17f602c148fb8106eb113f8a4624feb32b4f387f5cb9dd784f209cf0b40cd20f691d76ceb68112316ee846c5f295f0b92dc8723a21a62cbb5470bf8c6369e8d83394d12d1b9add0475355fc53c26a3fb8d852a6768ef87cdfbee42304187b1feb352b7983dc505d5b6d16a5b59dcc526e7f4f57ddf8fcafdb3786fa8ef80b829bacae1471564cfd7ca01d7506277f942d32e46453b3505c3bdd33b73fff1e824a04180b2b02fd3201e5a964f58eb9fe6d456d8687365bc025fb61e1416698426779edc304935c7c40b77e734f8a4719a1143506abfae35cc90c015427e5d8e5f711301b13715df9de0ca1aa1c9ec2793becebae862447ee50a1e87d23830d75bd18d669733863f9274bb00c06097d60af40ac4c2c8cce250a9603fc98f773f4db26572da6be8eba111157e170dd56f0095847f278cab301ea14f114d6a9154338e55e80f0e42fa53f7ab912ba0101a76d5184719f6d7b2480933fb036d840d867b1b97bd0eb17e1c0873ba84fb1ffa666e31931a6e1adeb03802e503f7ccbd2be787d762893615cefee231686d4228eb4f04c456a8177005833e5801ba4252ca667c9c731de7c0967667f01659be3cbba0cecd1f1c33609c74b4ddf04347f13d05a9e42990618249f5a73f26c2fea6d3cd6b630872d90a807bd754b5489bdc8ac377edfce91db0e5cca3a94e62cbef5d48855d6d0a74456ba4eebc6059390203cb39a7fd5b6a3d3604169e105d7a3e3c25a2f7cf1b5051381b02eb5240fae7a82e78b7b2b11650405b9e72b0a86fd81019f416ab13d09f757cd171e903464facbe3be563a6d9ed0f9f6bda71d645b87e0a295786affd5b968080fe681e1112ea7864571f1454a0f047773e87b99e366892e5c900ae9c9f4e088ac07f5a00f6da3a38e3d516a94750f3008d9843b5de26623c30148c71edda866fdaf63ee47a28860d4366fda2b9c97aa8df17a239d2bec2f5557ede90cd158a2a9d8900b297245218b1867ca9a4037a59d615a68eb04421726d1ca055f5c2664448ef25e7b0e82f2c6468f8502e5835e1081b0d84b7abf47c7747b6fbb6e981e027c1e9637d231a2fb63b30d21f182693425c3d0cde31be1737e3fb20e95b6a89a872c0a20aeb8fa1258a91911e6f036f40e1a1054f82dfb829448f5abb53e77d15a76dff6dfcd6268afc12efc5d2fa37f355f9a915c4d3098c149abea6b0db3509d8706b5400173bcd11b52c8adc65c0297897367a851b7791c301219047adc20410bb73b8bb98519495d6f91cac3ed14e5f2c4de971470c8439c61a8527be6bbc93a75123875dfcf20ed6eb9b1127bcfb17fe6a7b8c6a7fd1d01b68679e1c45625f3eb18744191f27c381f6d07d154aa5b82211b492b5df98b90a093be6cbec9b53f63bcddad8beeab48643151da8ccdad95da617f9508d99cd4f61619b3a02a3344c3633063bb32809353a63047e426e2d2ed33a076ca893f551e0ff2d912fcd3666601cbbe18db4831c113ca7626c3c3070994a0bebd64465a817e9571ae6cdf4dd0379a3f8b46e84b4c54cd9648640e58c34adfc793493bb28971d20266cd5bd3d2f2fa0fa209ab27a421778c5f78539d64ce7e4f98183573cc31811032d243b87e962a1527bee80bf5abf237c9d78aedfb338b56f9d37b251dd27e5aa10e180fa150a642bfe64b9a12aaef314c726b925cb9ea0c1b89d4545420149e224ab645aa7f91910d6697f8002fc31929c4c5d6824d34d20bfd6f01f6781fcc115c7f7c6fcb7cf0acc72b9ca8792c8e094d19255823afe740706c08863c9030f8b2dc50502833556e0833206b190ea2e22ac8bb0b9d00284c387b32c634ebfb141bcf69caa9f1b6ebcedbb8091173d8b5cb6cbac712cf8efc9bf6678ecf798f5373b4c0161240dad65755eefc28be8ffa48b9797a0332e3a3ee30d1a329ad85e062f0ea33987edb77bfcee2ae6fe719405dbc1b872a3b64652aa8501f10589a0018be1c2a783eca3e7a74b804980f08f77d8e6148691636a259b24f89a67594d127c05e55f33a104f71a6d2f29b0d0e0a5e2a2e23a2a913ac22d89c94dd216517c66b05d2bc7f51230baeea214bcfb5cfe1a1de7c3dd4f40ed42252991210679a602509306a368a1e882324aec1621b2e64603cc7169c0f0190793654c956b24f01934fb159e1ce8e01016ae65cb0643249fd905d05c0cbe8218c96ea8fbd576e48689755d761e7c691dd8098aa106a1810a8362328d8c23f56c342c772bbe521e7493cd74b5e1f087ee90302eca6fdc401b24939258bdf675b60e3cb390e5aab2435d59a0b1039215a337aa8b663651b70ebd041cfdc6a60678996cd47520550868a57694ff7213bb95877da00c12fd1d4469a405022eb1a81ca2f9c90a9631a10a419219072e9807132e9ed063093a50d949cff1b8367e703f9ac009e95367952df582cb1c61a68bfd9ea67048770e3bb3df521633bd5f9d05d8bdc29a35fab8b8989562a089bf8e2bbabb61d8ab678d3cf811b117bccc93457205a5c9aa70f903efc8206ff992c7462b814ce39c534a3c4bf1cbaa61701544e88924039eca613e5e2f3b5f5c1762e493a6f0a2c3af8d6240b32dcd533852132fe486ae07d9eb746b829b5ecdbc547a72b2d22bb926f75a0cec8a85074511e9060be7c931e3e878936abbd6342cc5fa54bdd83517e0cb4c351134f9368704798cb1faed35975aa72c499349b9f35ee9aba2c79934f5da4c4a3f631c16a41e2e672aeb602796c0ea2ed30e1b2e4c42a3c752948b95aa46730fe628e61b5b91a7cc5a76ab8026f7bc24a81095017cb6a752eb4915d5cfcbbeb828827edf21c0d9f1a029ba9a54ae322e73134a9f4160a41a7e230378c6d0bb39c9a83d8f298f121797cd9f3f1f19d40a0cd927d0ed9eb94f2c90cbd50f5c759588da5fd9b014718314f3ddbaf7a75b10210092b5d0976c521b24db0699b8020c0daf9d534b8d4ded49c28dfd3e73b6f669ab564383bcd7674305ab2308088cb59aae588b75929aedc543df0c5ac4d97fa4ed9a3ca48a8fbe7c74b935c8c383a24b4cf71c045b42f163bfebd5a2216b19c6c48e158325b79044ca640c32b8c83b85c3ad5f829563ec1ad84fd131226481aca3783a929936bcd4022f1e9664ac859d7082e938405ec57a940d037fddbb55db2c63bababc89c4946e2e15901396ebaf3a3404a73f8f274c681ca9465dc62a97655b39422562eab306d34ec12c8abebf6204b430477b9588861c3ca764d1521ce9e48e3ea632f4316cfe9891ff2b396fb44f0746ad7f33b94cfdd02aebb0d7ccf46315518a5e432154c9fa733c7049c6c06384272c2820dcd23d64f75649c4ff5575f7a86f8152eb81a9852386e3ded479db614ae321f62ff43646287d16a8dcda99fdaa324da4cec58928600a44c438fc4a762904489aa5ffe55edbca342581c23f97a1f08e17f60f0333a59ae567843813b6ec1fbe23338b11197bf309570bb7fe8f3ac921dda4947416009e1074e03fd9701c043f20920307de99e25e6df3818bd1ec8cdc450950aa4e1f6e3fd832067f83cd611f14e1071d367e1657cf5ebff715f8f8373982504bddec6358338779cd7562a5b7edb35499289fb83db7542327a3fd2bb8cf38d580906b88dbce9243053c29af1e151ebb4478b7263e47111013af7cee1403739d4dfbd1c1ab697eba71cbb3ab8897c1d4f39020868a8cdfcd4f005ef075c362145a5dc8a23639d6fed292e80489b28d64978b94714ee6baf61cf65cb0f8c2ff834d2de8c57505fe19cf4b8ddedf017504e5fc66e023795c6d084025b1478967b3d3a05c37aa1c14d58c5c9fb0257c64179ec664662bae6f9bdc45b7cb87ad0a9ec24144adf1957b32c04cc400b6f3e604946a5ef72a4b5fd0a518f0c315a66837c6055f3e0362e758d4d7478c8e6b0d19fdaba7d07e6604ba962e34ac26c30ebbfd72eca581323028c66465d327345b9ca2306cf3cd07fad775a116428c6c1a1c7f299bf03e92201e4f6ae9677801066ffd8ea4e6576f43257ca0f0b3f085aaed63af068c457efe55c169d4a975518d9752a966c971058d5c4a296248f91a0ba4d8598d59633ccea1be634a67e857f80816c41701bab0af1af996805980470b63838aa2c7ddb90a402eee21e8fcc3a01bb6f58edcf134ac578d7b4cd514ae30204cca56f46ff2ac8c100ff7db6fc74e8a234c0dfed97f5bafd8707fafcb8e67481de7fe894db6ec7e6496dd8b03c0d4a58846c98881e91c1e9f99e612bec3dfb0c820b19e91a28038141ee876929eecc7fc3814e851af12067ef12fdaa01fcf045c59941e5035e20cd11b8ddd40e2aa72cf0f74f3e519e407469a5f6ebac53f44a55289078a00776b487ea0cb3b1cd0d48162a713738a72cf56c0eee32201906fbfdbc113533b4195807db61479d7cbdf32d176642448ef2be97b5f58e65bbdcb6e46bd157a90bd8a28d044bd74f9dfb5d9ce9c85948d752e1dcb587f913d363014ab71f477ff45c0736adcec8300e12e77b0a0c6a224e90b78bd5b708563ed19306e388b9fd7a3ae61097fb9a482c972c5b33e2eee656ee89f6f0e0554efc6da73dcecb70ead0f8d2ac8d1727384c4c51717b6101e94c9f3ec10572f87ddf071dea6be3187653fa2b4e3743689eb64aa02aff507f43dda2d39cbcf715c49bfa640bee3cb8a023596633b2fa3ef9a09e4ef4912e09e492812094117fdb6dbcde7648fef48e92aa9a2a2eb8ca3c15fabbe1e589898189e0f30e9440716073b2e30f9a4b523ecab5d9fff2d605d7655b6c91db20988ae6726d1339f0e285adb03d99c0235ca80442c672d0a0270c41e8f6052430a8480fc1c1a9d730b6e32d7593aa48385e46acd81450df9c0ec9a5c44a35159017604431f9313706540eceb48a0b2d6fb7e89c71e901fd2501b243cb9f954d8b8f8368cf5d79758a8b97576796c5c18d509c95354278a020a0b7673335ffb69860a09db9728c7d1fb1257d8ccd3ac9bce6ce7765b74f8531d53721dcddc07eb7454df4a818575c8149869b7231c4abea270570a67f51139b1ff0a7048fce2477da14ff2b40f3856a21b0926b987f8644f3ce870ef1999ddae736359fe5cf317b104b2bf627b4fdca10a526d4535a9bfdc1c93c86cd096598f1f7e7fccc3e914bca3c41e42b05b14d30cad1db2cb81a88d473c24f7bb40e5bbad7a46dd7a6c8c2e4d0e6ea8d69bbf9586d2874f47e6246bd275a4b424e32fd5dda26504e3fa2b7643237b66eb276d1967cdb81271be91033669629f0cab03569c96d94f3c61afae0dddd035196323e4136c84bab5fa6dbed8af35ad08829e2f4ca51f13c7802fd8f019762865a2701fd9a62ee13d102ed51bf14c4dd249272ad2c2b11cfff639edb559bd3accd2eb1a4461f7b0faabcffe72b0563607ae8dee319aeb9f34dac34d1c8c39e37baa5df56d0b0f1c5ebf9d11f4b837bf6f5b0eaa12c2e2a2589296edbb27632035d3a42bf185baa32a8f9efae6abc8785c0ff09fbed29dd7fac7a095fdc1561cf4ef06c8352bee42ea5558224d7886552a7686fdbebb57b9f3640bb96ff50795d3fb5dc8bd5b11e6ecdfd29226548586bae3863a4aadc69dec312b7137213556a28f7d5309d89f38964659605fbd7f633406ad66fd2e64a036957c75cafd0abc7afae86bf79e75f714285b66c9d57a056a8d2d3578745204a868cc7bfd65b56c659f7a8b5bedbdd79ef91dd5ad566377e5428c0b01942dbfaea35a26f452910e416acc84bd12fb521c5f14e16da9a944b28063693e8308f28d5e7b6bbcf7125d07d47ca367479a38ce7d166dd3d297e9edaeb8aa21dc6ad26162ea6e16292c81bd1bdfb06605ccd09500c6cc561f889b804305fbdc3f3b87d2bd1aeecb5483f466444e5d4473bf8d7cb57ea5a78ccf8eb54c41bf8db67afabe1988fad2e59c0b3e95c47480486e0635a1d79fc76b81c8a32e85326f960d48c6acf73023adc95a02e6f2189d3d9a9c713b0524eb58682d1d2ba39b3cb40ca7fe36ee3daf2edf56f07759744c7ebc4faecd3285394a113cd0dde20bc2aa01fd1c364af98ddedfc694435ac994903d08a80632480061ad16cb3660eec48dd652a99fc112793956ff7c17c53c062b1aeaf5cf0f26a7eb89e2b068e5bfc98246edea3fa2ed35b22341a3fb9c5a81222dfcdda883a9e1c47d231a7411127fe47292ae20109aa869b0500dabc3528d36a7f6750c539386ea71da0889ff6a6c1c6fceffe7854f0ea482cdba6c99e7b199c33fef2da395c3db679789ad78c4989bf03c9811cd54ff754d46bb000146374d108098e05fdaabfbecbcd8a662f97a347366449b5cfadcb90dbdb80da54f49aae02f26736bb439669981af2775a974c624e25e0432ffc7d737871b7aadebc8a5c76baf84d4210df11bda86e44545116d0ea1a7a0cba02fdc2621a41e95108cab01d83b2e87092a030c38eb68203f9c76cb955907dea684fb9b2ead2358474cfd649f915baba237c113d57a568a72db98e905d17356aa97d24b439a84fee8e3907847f5028b9bdf66606d339dcc3ceced74d810217192475cb58145fd6d90f60036040f1cd87ce89d1f264efa049a6198ed2e900fb6d359012366088e2c5e34d80de53dcfc2233e9fda09f5ce6ba451d9a70b292fee607851644570041662666314a20493fe1e9483f729965fb58f8202f838901f36e6aada07b08aaca45e5",
"spend_index": [
0,
1,
1123610827,
4294967295
],
"result": [
"cecc808d192a9f822f3d0fe65f9b06406c53acb64a6cd783b406585b643a21a9",
"099a679b991f97f847309a96f0bc71e33f2bd4c06f4e31dbcb1a58583b778476",
"43f91b8025baec1f25dc121a3099b787babce80802b1737cd8188c26c17eb777",
"d40d554dbb960ad52858d382ad44b4eb7ec6f917be4da8f24b00bd7a5eb53738"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 4,
"Witness": true,
"Version": -1199693507,
"scriptSigs": false
},
"hex_tx": "3d217eb8000102869733b100000000000000000000000000000000000000000000000000000000c7186b0500b5165934b34ff67d000000000000000000000000000000000000000000000000000000009c073fec004e976226044f06990221d7b31cc816fd9aecc340fd2a4478e48f1a24573435b5e58fec618c86f9ef5b28f90c63ce7d250099ab463a98bc1dfab993f8b53b1c0dd69d51b2b0d44f1b27beda090ba650e025f7def2ef392f9e889636b6519a52724a14118f77b49cd4b43008caf5dd9543aab138e336a85467d0be24f4308f004569a61fd2817e43c1222ec3273fb0b9898e095a77cef35afbb7fc9b567d7e02124ae96d15398a81ac1e673aff6294d79e17c0c04e47ae18e80ade55c80305dac6592bfe465468741566f126ffa73850db4086d43c3d645a0b670bb1e87f00c8a6509a1ee76d9a4bfe91f51a36e5f3491b2387df1a0573a15ea3044ea534c4330c0f4627fa6a167099b2e53d17c2fa95d0643b5270685e3e0516d95725fb2cc3f7219163830e6e14b4258177cc8c9bddaa05c09549320b2465f471dc6c094bc06ddde5dacb8721aad1a3ac46eab1abb5e5b0facd59f0d8598d6ffd21c9596c73d7cc0328ee01ec7da03e815f87fcf3c5b4cd684bd6a83fd112887f38a3bed1e0bf2f8461b07f459a3e8c763431a1913993ce4679d32ef1fbaa70965a1caf20e5152e7b2d21a90ba3c79fffc713a2cd12c8d706091319157784b3c9fcc1c9d9dcc488822f5d1e955f210eaf46d02caa7b654d23ffd346c33411fe812078a535c7e4ef152a7219c039b631399ba8717b5379c528724bf0daa87e5e2795f38759cec0a9a6a9d8850fbaafc9be8eca828094ba93c72734d4ce99fc6ea5d990d0cea219c78c19ef246c8087f15785b4bb8b747411c95b1f00d1be2355cf509f1a3208916a851ff87e7417d559f7225f5793384ef30ae6a5f8e625d2915ac23fe4a884c12e0cfadecb350b7b6712859b4c0ec05b38fe28ef1450862009e0420de3c68579c8f870ab50417b7fb2d7a9f9b17e8dad1e16b220d8fd52c56ce35cf715b848984c8558e7c479d0b10708e74fc19f43a79df102f4c2f13f4e5d3a344b65eaa525ea0d52df29877b53dd78d116e1834fd7131f93a160c740072ee12b42132c663887360cbe49b6fce6301d2ed6055406bd794b68c70b1b1507ad14b41e0681198d76d38773592c6fa9c4bb334fb361400c266e3b6b9c939ab7ed6bbd0c5b6c56b43ba0419da478a34800a85a236524fdf386f9e3cced8cc9e220dfd0d60ced5c93638c1a7ab9cf7713080114d2aa6baacdff3edef871bf11cef706dea1c3250c0040d9d7ee",
"spend_index": [
0,
1,
4223522144,
4294967295
],
"result": [
"8d9a8c73db734fa3fc183e185040fb3baa67be526f03b54f5289c32abf2b43e1",
"dd2096b3b9dd56a759f368b1e43d0c69c86bbc583eba22bdb69bf0f43fd96fa1",
"df608c08ec965201c2a83de9f2034cc59b52867b780ccc276fec845dfe59c25b",
"95633cc720202a26d62f9f827fa159c88599567e810863b9021e344c12416912"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 1,
"Witness": true,
"Version": -1735281,
"scriptSigs": true
},
"hex_tx": "8f85e5ff000104ffc381310000000000000000000000000000000000000000000000000000000028d09d5afd6201ee54e6f3450342d4c5bb74215ba323767a92077b9f5f7e658bafa016578cfefb60990a08cf221b1e790ee35cc98b50b81fef4bab14a25a29865a250bd5a29abeefe0e1d4b87098beeaa9a54aef8cc00e512824baa5a3c7b6f3b9271cf99da5b946b73f048d67e6cd2bf8ef4a215f94ce86d5376ef4024e11fb258ca5ae1e4296f6456bf39d1cd9b5be23fcbe336bec2c683504ddbd48e2788d423fceefa4601da5d73d9053c0a9e25165339347f1f7e308b9afebf23a65a436b411601c08eaa3002c741ab2b05739ff95ef7e78adb65137b302ce37d8a86bdefe20577359fb4b4c7b3d21c4f7fb9bfacd140d849727558107f7dd8cc49b2d46b37d6e35d6b0c3a4f0d59599a6c65402734c57daa79fe0d4e3c143f8908bdc625d210897c9eb94d93f6eb929dffecfb2ade04ed4855d64994bd7954f424a1c627dff832bc101f99b74acaa50763dd4272d74c9e52e750dda5ecabdc1eb6948d78f87d1735e14f929da1108ce59ff8737e400000000000000000000000000000000000000000000000000000000320cdbc203ead0cacad7b06225f5844900000000000000000000000000000000000000000000000000000000bb5043d788c687a07d2027be6229e44e58d5d12060794ba4ae66bf50a20f75b9f83a634c80a70ccce7650de8fc42762ca9702027aa6968dd093a0ec75d20affaa898e9c1fab64720f09f22a5f5f737e06997e8fd5de8de5d22568d8fb38767f34188dad7c60dcf725ee60c5070b741f14ef7655d44684751ed6e22170aa5b26e324d3bd2908547bd953255e19fd77ffdb244a7f6d100000000000000000000000000000000000000000000000000000000d9fe45da005a210d4b011ec587ee33a3f378c8bf915d96596c5561538659382ed8c9925d717143ce297c3edce55d077b04e066f0dd33c04814ff65e091796355a7571e15e3e299ad1565cbd54f313aba50cc9b83d04b8eb639c78a8141ed1a602050f15c063ccab4bf412c6dc361be36716928d073a7e0e6425fef880904bf6ce3777db0218bb936e466840f1cd30a57b2909d485040e34663c58fb3d29368151caa4c61ed8b759b3d2581c4a1c710c94cc0e535fbdd9c73d2f543a0caf927a9e7c1e05c9820d304312732fb1649a6d4dc4b9d3ccfbce3e48ccce902d4954f49430f625aa8262e289b19ee1cb08a9a1e25b987521ccc4d2461c36be71f5720027f33b42e688009eccd0ea247bd580759c7f8372797a9a2c400a22141a749cae3dc3dc492a0eb83ebf51d62fff490cde1aaa28dfe481d065384b60c98d01998a8b61ed3663b6e0b4d461cc2ce2c8537093b70dd22d5bdd235836e8561561bbd35f941257ee8381bec20e7572389e73091d73ccf67b6a51ea55dbab446795afe1b619a85a26e7dbaa5e50e382055e0acbfbf10d6dbb2a9a95e1a537de9e7aa49ebf77a24675a7e19071a6fa30535a8ac100e9b8a7c896e72913872b1fc11b9167de507b00291020d18c9ac897f9bff461130f2093e0602332afec99e78556834e36134c29cd87780c21bd1503a3eec4a778a12d2a041ac45116683f0cbacac9f06c91a51150fac9d89d3de0501eda7cdd5dea795a0b9d6a9b0654597ed2c63c3019ebfec1dfd02b4193e1bed92d0dfc044496ba50d7c082d1e4af5d1b9d3759e2a8395cca838cd4fb19211b5833202fd1d015de2bce81ef7a464a58b1bfdfead64af9a18256e9d29045b1355baaccc915e8340942649c6c06a8a5ae0c2185ff641343e673b08750ec4f66bca04a4f5fc31ea4268ba26281738d1a5ed7bb3a0e10e3286dd8894582e06d130b4e2e8283bc80b0d0eee98a38eaba530463ebbd4c66682c7cfdc1e48f3188fed7434a4649c50c88b61b589b73944585965132393e5c2c3eb803b1f7139b0756378353c7b2dad385d16502ccece41654d7e33836c030bc00c5912cd5d59bc58df1b9e9d42b7e1693840399b715cd2b257a8778a29076822cf737ca5ef490d70bae95ef821e37c5b1ac993d87f3bf5d77a8324fd7b7398859672fd9e3045ad90f1dfa74cf1cfbb935eb8674838e431c547b7418740371ad173b1c06ba7c007c1c258f8376bfd0c01cf95133eff377bcddc3dcc18e3fe408941d48e3d8ab940797e37e500ffb7a8e701f197983d99c3ccc8b7deef5ba474a30ec5a2c54a4bc0b038bfe91f7cc523a1f977670cec06e500c42519b1c280bd8527c6a97a23772fa8248833e9499b9aef387e836e9bfe5ab77c0d7bd27e049e4ba1db6c0976ff2e624059ae9ba82656a7cc95c563e6027f88efd28f513a145908196236e795d1081eab8591ca98c9a6c8c4f7c0d26c759a844ab3dcafc2dc8c3cd16dc340a2b9167c50049839fa9b24564c1e6bdf2ba8b122515f1923b057362e09685fe4e6e72fab2ab7c78c36fbfb06ed4217fced8d2435a53b24cc625e9ab9916271f367c84dd812787bfb3f5894c1f10e32868e41b6f4205bc78401e81f6ba376baa4d80ef2e39fd4ff591c942262a765b350f0af63b2c62af1d9baf08b4465d1bf2fba18604dd42dc19ea6ee72245cfc9c20d05647755f59bfde7ed324eca0ca9c44cfb29cc5c77b13c7034e5958217c09f23722bec9ab2f6e0a8962b9980e92e12a473ed8fd86f263f690c13d2a52acd5ddfa770674c4b0a31cb05bc216475913c6e7bcfcb7ca29fc5be402f59b4d1e82413bf56d1715a830ba9830dbd43c24cbbeab79ea0237c24b916dc4336162ab2257a2d5599a70e53cfcc5e193ea2cb36619ed612f5d74e91bb267084573d1522a35c97b78752124706f587b2fffd8a0d7704628003708def1",
"spend_index": [
0,
1,
2131463707,
4294967295
],
"result": [
"4fe13a1cbbe51a9d65bda87f260152b4d574eef0e4d0300270e316072665e23b",
"a851f99ab09182aa209c3f4fd664792fd0b92cc84c31bb9516e62576788d4eec",
"deaf1eff3294114ce43e1aec0c88cc9cb3fc241ce513bf074e38b96540aa30d2",
"03f5bab0971c67b25b3a88311a1bbd1b2a0fe26152e6a937f3f259d4df7459fd"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 4,
"Witness": true,
"Version": 1733870626,
"scriptSigs": false
},
"hex_tx": "22c458670001096f7212f50000000000000000000000000000000000000000000000000000000062a1048c005edf053e8aeff6cb00000000000000000000000000000000000000000000000000000000dac108e300e5d783739466929a000000000000000000000000000000000000000000000000000000002de0905c00777de5af16a35187000000000000000000000000000000000000000000000000000000002afde50b00d1b9cc304ccbd8ac000000000000000000000000000000000000000000000000000000003a56fd7600f01c0d056e9eb32000000000000000000000000000000000000000000000000000000000e1c4a348003ecda43595b67527000000000000000000000000000000000000000000000000000000008ad4f82d000f390b1df02c0ffa0000000000000000000000000000000000000000000000000000000073b185d200b715cbad589ed0c40000000000000000000000000000000000000000000000000000000099d22a0a00a5a351710493b498540927de59c8f7af8f30d26d6c728b59f6187e0301c522d3dbd8c291d8cfd66ce0c06d1f7732db576902539dd2700663fea2169b834fd33ff931c4a9481952c6a54b70864cf6d4a70ac6f3768f165299bfc2f6deea322f58b3cd8f4c87886cb7341b4b7ca4dd8ddc02f233f13b7c1f8d439d81f6c9bba322a0620eda5e7520c92dfb0e3df4104c37281c4987e360e666bd99ebfd2f40f961d37a098437835258215d2fbcf11888768155988b6a0bb4228a946032c2532dbd887c4136482adf7e361d0d5e4d78f16463769d7f050c423835ad76036c7dc8d0e2a83d8c7bd26c66d65b2084560ec8d55abd5ab63177b7731cfa9c638f2eb3b3503331c861c69a517baf8cd002638b337de905f218e4284768b790557a0775271e062280092e7e5e8d2005126edd91089c2907ec5ec0dfbdf333a956552090e47479385a04c853d24b4d1a859f4a09c8cf72b26ce6a886e4ab2411be5b997651d584f966dd4726af6945559989b33043f327278cdee1f5c3b623fc2b872f82281d6d67ae2fbeca6aea5c9b2a22b7a99e8a532b15831a5f0b1f791dfc4c951ebbea55e4a6a75710b1e05c29e4ae0270c888c573e1a4db07136b031b33af99a812d2ed300ff87240e7b2fc0cda7bfa0c2cb9f6a79d5855080771b44df1cf6cecd7452970cedab9690f97527e4c184517dbb01f029626599ebd9b6a876d80504ac0e9dd175617f716c0e107a1a4e9e0a7a992642e31416c97eb89ebb13afddc61d61d0f5f7bf863a8016d46b48c996f0c4633a7f6280a516bb89238946fb76bc19e6615d2c74ac90babf5a5060313b39edc9ea6017836335eabe3e6f530cdc94bd671f2a418c148a69bae6c9b836bc1b3636f2b78fc7aac56836256078dd3878c7ec8f5135e734df6838a803b49e8e5cd9b2b4c8b1aaccf8469dad80b8ad8c9830d9522c5b7d093e6e3fad572b6a9dd7c3e2b81acd1118880c6762e14fb0897e08df8246088750bb9c0435ba4ba6a15d31b833d1dac5a26dd155aac95e5f7915758db1f314c4d485da9277051904a861b0cbdabc0b9fea084038ec9cf8e379d5df3f22ebefef3ee3940190728b5872b467e40a554e21a8c53ad16357296f2c0dcc1dedcff1f0c5e1f2ea070b093d326dba8ead52968dec413b22b422c07c0c1e5efc0cd601ebb4955d65704fd5a0185f186b4e771955f422f4cf3ed6e25ad78805884225a74782592d039004e57618384c597837e76fe0b4f2f8ad5522834d5b5c34fe76369e4dfad831145924b4caccade3bb236cf6a74fc53d1a9d8bc6917b98f12d4abdc132b22e058c68c4fa9f23fe94033012bdd75b1587c896211f1a1453e95a83dda6e5400d1f0a638a146ef6512058161bc585df8f3e8ebd1df87241b3a10ae802fa1e84d584b6d08f7802177e5ed5b5e6a5c92bdac2bab36a5bf20a5f41fcdea3102e0dc6f765da80f26546fcb1507c5ca0831c79cfdacd3aeeabb0ea9476c1b0502c27032c4aba7402b0851d56fb4330645ff6db91b55129617c84a1f0e461d66428603eedf0280b4060f8432d2d98446d8384693c6ad6fd7e86af5a8cd2cd5594689bb2c7405901adbdcfee95fa4bf559f3be9dddd16aeef7f24b3ea637b1923e78861ddea7a7e3dfedac523c10892b7d8a0aa54d242754382ec4aafdd3afbeadf01150a1755354af291dc6e4d5afdb2010b6b8a618ee68fe294d6604b4c2f97a6c633f1446adf96cbe7761c1b8625ad056932fe99c7e73181edd37ab3113dc1a9220f03879274e5d2e103a8df16ba3b617a47378e000a2e2cc6f924b739286e55519cf6f676e3055efa644e2f7ca6c9785f36c05fa620062cd5f3db3afbe31586b65302cd13b0348edfb5dbefa8ebbd4744df86090c5fd59fff5ac4e16b0b1ff5cb88e1771a4093a1b2e27022f59e4809885b0cc2ec371d394dbb9e4e3e2a8a6c8b1d0c43bf392707fd532dc552ee05f071186922a1f4601e0e06e54235e3ea632b35cb398ca8e75406500f978da6e3380c82689ca48d571ef39387fa56a9c73add03eb17bc9205fce7984b86d4f6087b6d34b6c1b13d7f2808180ed8bc8fefa836da42c94dd1f831b333952d16d06305c8521ccc93c99cd2b610992b11a9d62cfb1b32e0e6325eca20f63beb24aa06aa0c5a3d5d0ee2ca3c0853692289faaa18572054745e4416f786231556a2e9318306c17a10f20b9de8b8a6d4d4461eaf41d458ec6162f55db880efa9e205fa62d52cc29af68aaaa1786fd7fd0547f8144e2d58ac931c1edc5f33b518206f6cf35ce96db6bbafc9434582d5b36e28e0925e991cfd6e019554bf4d69db646e3271b99624f611d9b1eb2d21c4e21c989ca28bf9692197ae94ea3b3c7c2e78b7349c2032008f138cc3f2746b6d572ad4f15bd73753e10dd359d31a86a1df75863699546dffe13c2a3a38c9561636c2dd67a2343d8edf6a90a87d51be488ca2c149d19c1d916d657d4b1ed32ef48ce82049eb9dae9e041fdc10c8024ae0b5454f8e1f92881fc8de84e7a52bda9362d315e3cf2c83855b12f39cbaa05c0bc6302d20480f6004a66765668e98bcb65df066270a81648efe375c7a0cb77138622c136da8856e6b124085ea56ffe06a8be180c8975193ed254ce94ab43f159c90b1cfe762e6c8b5fc0577cae3b8bb01ce9ab7d1a7787e13988c53a732e9be3ff5e87145fd3f983ea8a788b3097a94ed7ccd75f6c5182ca64ba92875e4a82c41fde6df1a724ee348b51d8fa415b4f150222629205be4019e0da9d2bacd21e382b57150d9cb11e11bc9c2ce5ab97968b05b4d19841ffa03cfeefa9dd6505832a92e972bd917afde03e4000387fec5ac1ca2d8b3ac2a2c271753bbbd3ba654a0b82d3fbdad9bc7be71459740e6e6320f3ba073c567e7b8e611398308b5d8b626e2f6c02933eaa09286abf9cefb2085a7f2848b902f9903b2256f2f806d353ada1f098df1107346b4d394ead153f271295877c83e9c41d0dd78e675652e42b085c8095e9a9de8f473b47354e57fd8b0cad264f637fd13014c2d744babcbed7c0c578bc1566c5ed637d8e0f624c79209d53a930cebc2e32402b7e0b0b1fb5c6d4b7284553191b8dc387f763f17d3e85fc2157b40c625572cd39f04a33a7b3c087d034c1926486e20b9d42d1e0b73735957ec0d1d3f0356c91f3e26415e97e4dfcd005f7192c3e6665d070e1d830f60ec6e180e575593c4f4837b390bf0e13a7a82e504e6d41dfe74a576b92b0951697cc733544b76b9d5c4a55d134dc84ae1fda4156694e6b6c336c46e2d242de862d1f0d702e1b55a5a4e01434b200f872e95bc97baaf1805fa72c186ecceb1ffef5dacfcb7365941b24d594fc7d7b53291a478315829bda5c482e218bfef52845c57e90eb0bf2fe30329fdbfb06ed257f63a8e173ac1422c4dd658b5e8069776e55f486e01fdc801145af5a25424e31f35169b218004ecda01b83c4405824b5bd3da11542f0532e84e1697a76461ee5e6d1ab09d9cd80b0db5fe2c6b81ba508bec14ba638884a949005bd464769fae70759ac0ac5427bc8b60a299035596e76f14f7bf63fa7b621aab900b9f66f99971ab5a60059b761728c4f669023a8b9f2098909515bd83dcc06bc7b2482fa39cc0c68ac0774f8644bb6946f64468753d06918e4c52f29ad8ac6eee95ae6abd22a702e80d902c888235f7225634883a47bed302c7f401d476a33e720fefb7d168b656999e2ac698aa87c5e8273277b3c1f42fb5c948be7c2aae2e6aaae98e159e21aac7ce52625a7e6905213dc5117be4c54ac3797fd18c4912d1b6e3c4e71d689de23f77467eed4023325d5c437f6d09ef57c63f8378caf30c156685253529dd7277f9ae03874343a12ca699b998eb8a37b5c3c903c582fd6adc9db5e6896d1b5f31b4cc0865d02e371634246164a0da11c3f22f002db813af2056783bcffd14c97eb2b1411794c9e9b22c4a5a11a4bdd7c3df303b8127df65a5e027d6e58e44a4b988a4c351c899d09533b702b85deff28f1cd8075d039cbed8e4fc61853ae823494f388adfaa021e35a7323782f27781d87408321c6649ea3158f2c66332893900017493d18dc5883869c3fd0abb16b34ca6b899078648b8d371d69a2411efec50ec4acfda6261d73bd2a2091a22e3d4afd678487e69fb18a5a94088715d5bc504ddc157b739d6d3253f7a64c62ee97626e33820d2d90335bbbb09cec8d2ef05db06bd952fadd5198e788e17a1e5bccdba514eb975aab10004fd6b013a9a44cf9cb743d0c315faf6ead2f541bb0ca8f592abd875fb9c99736fc9c1890e74ad624d50026389fac8e91541c7209ef10ff8f53d3435d208a3f1fd866dba4c3df7643a1b5fe43f030523d239af63a932f2a0d92f969c9930c218a57e1735e84748d7e83464463898891a4f380bd1d21f7c508baccccd48a559dd2ff04d7ac1b8088a50cfbae0a6dfa18b673a80b70fba0514265473579ad60714d4b058d3ef31fde93e2cd9b8db8b008d4cc5a1b6fdd5c07ce54f88c179e3ffcd9ba45a5aaccc18fa63fd82c4c8adca2e0d23fc3c5118470bd23fe22edcc45b4494e1a9133a24f0b053a1ae10a9d9000eb191a6f7d7374f934dd7b806bb1b9ef4ff2cc2d0cdf41e2c207e93ad2590b1326b089226e82d573dc96f97bcf35391353f5c10b2c246f31d3b12b3444e133dd84da02eef00ff83383c74463018e0c5f4498fac8c325691e78f3d914283c0db2f9a26b4736e5c902cc06ebe623146baad65e812a66138a9f36486b51467c75ca0a7a191a849a3e1bef14c784d08ecfacc10eeca5e3ad4b3948fdb4c7f68f800422b05f9ab85ff9e5658b863830e8a31800b7a1c8e8a2dd8da6aca55f6f53e7c3bbba823817f4a3c8553f503bcfb80d49cf8ef1b744fc16dde83d8f3de9318bb7688dca09850b9578973d4c51d7779d98e8dee78f6c51bd29f0e811650032e9301e567717df8759d3c0d36e1f2cfc811cef4ac71c71834091693d778d2bb7553a1699348c2a5bd7102c9e96759d6392cdd149e0d25db6f43f601ae86c6858ad71ee9f0ec3db6e647d0fda369ae28db01cd957a7d02cd1d215c0c12a7fa52e1d03cd5c661cebcc40d15bf382204cc5cb2c22fdad68561dd3d2b47f2a98b553f97f79e572d59ff7230866a9bfd7201b32437c819d65a1776e982dc23a99078cf39af67a4ba9b750993d2fd1b2e2fb5cd2325cc226d0d6eb8939a4d09931f6b6409820f85c5e2664bdaeff43b02db7a1eafb67478afb5799222937bfa7ee7a876fc2704778c8fda58b156649e13584d572f3a2232eba727e8e94f408fafa6dfe8dfc317812cc8a1ceddf3c0bd39ae7bf89c84c4cdb8337c98e228dece59e42996d6ff71c615aef4680e82f894bfd62ecbc9e237ee4f4c19f0710f601ca64a0fb86cdf55dc307019a095a8dd8231a311583d2afef7c23812d612bd85d23cdb2cfd8e94e16bf597060341b91496ea2700b637c892b92f0d36aa22706f2df9b2e666cb8dfa5f756594d35952fb512dde04819859eab4b520576d586d0f609cf3dd7a0e67804363acadf85f7bb4ac33e86df9957f753fabc917b61e866638e339c0c055edf4cc46fe778de5cf995fe2dba574eaac60b0aef801344900727b1a3307383d6043b2b682ce861f0f1adf698502c8b8ec7bb3c9af285784c133935c5cd0378000974cb616",
"spend_index": [
0,
1,
3288593228,
4294967295
],
"result": [
"d8ce2e1d4f993d80b93d9956f3c15a5f89316530af085a0cea683f01676c8284",
"9c67e9fc5bda459813093f8fa21ab952e96e72e3a04d05d067a39c6a5738da4d",
"76e1652b9b48ba4f0a01fac838c9760e726099c5f203b5446e532c36e5a9f317",
"e7f5256e07be8a1ed57e7cbcfe588fdf1b70c576bc3b7bd5078571839449583c"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 1,
"Witness": true,
"Version": 1754886582,
"scriptSigs": true
},
"hex_tx": "b6719968000104bfe09d86000000000000000000000000000000000000000000000000000000007f415c3b3901b4da5201d6d25f5bb507eb28f25ac0a45e1c60ae59ab6f230ee9e0a8038f669b452ea61c6300b1c5d6e851a96c59427dba1b39c05b38ddbabd990f7e7c0dffd0000000000000000000000000000000000000000000000000000000008c09425cfd3301a8d5e0e291373c1bff507382bae5d6ce1833d8c15e877c107334468aeb6b72c9a09ba11e1aa7d5ef9a9376c6b601742dd04aecf8cedd88994cf42d95812057bb26afc5885a524233543ec555cdd77fe16042d5a6c69d98acfdbf4844fc81133a3414da7024624645b22dc8b56bbd6ec6f34845ad665b16dcbc427f6217d400e07ca77cdf48f2d15282c49f97d92f953c720be235df4c7636d930f72e1d0a1148479de8f7a5034e7ccc2497481ce01c3b0458a3817b0d49cdd68c37ea42cdc4765b361036c9d28cc5e072d1520a417695b9e985dcf00557c1bdb3a1da9ea1810615b005991b10b0dc9cf2aedf0d12ef16b9a89519657cc7e1ca1e24a91d4a0d7bfaea19730a69f10aba757c78c6867e6df21948da8b4590ccdc0299cb73b154b05f408de71db58aba399dbb6bf518e4b10f4ab3a6fcdd55c71b0b05000000000000000000000000000000000000000000000000000000001f993e63fdc7019615afd82fc2b3cd8d062fe3a9e8d8f1fb9b45227251f0f361bb87d276fb98e6f8eca5b3e8caecfc94843582c12214534508bb33f0b2ccd9ef4015da7d972166e41681dabfda8f05c14a0fee0bbd0e6835f5765abad828d3fae2254140ab076ce76dfc627bd5b153b504554504dc5a48432978d289abceef32604e5f1088ea47e296b194e03aae8fac44192915c0462bbf683c1f3502acf15e172c9cffa008d43c6293c5a1f18888f83eaba45ed9f28f7c5510e35dc950c73b67e3e97a2cc30834b2692a3de7d7a24aca97e383feb184e541dc79894b45111a6ef85c86874bdc2034c454e2128af84dd6c4ec09261a43606715ff15de4fad8f61000285ac67bf240d11db76a7944a56630bb18502ddde8c10ceef385764c0586d9ea9f70335cc4efc13f4a90ab313c5a5d1d485c4ded28ae1a63c6840cc8414b83a7ed7d7f794f10df610fdd96a28a3a6884318511efc718eb4b78b0f7552834e088cffabb2cd6de26d651d28a399e747b306eff114f535a0a6cb2e5c50020adbf40637af5aef705c0b1f990037c42e16cb22b397c25d69aa18b20271bc57785ba78d90454c54e6f5091bcc3ae3e254f7324cf5128895783ee7dd0830d58ef45b72e6f80e66e10cf626c23b2e4317edaf120c32450300000000000000000000000000000000000000000000000000000000302cffc34037ca29fbfc7254ef74677d5a0a1dd9edab14430248dee41ee135aa1adc5c3defa628b4eb451fd3de45c412cbabed345de0194b1ef856258b38750bbc7af5dd6811f8e4ec01254685e44c321255c8d6e63d6596548a2c1ae46ee488cd601b57cc34a0821c5c2c70a42629fb17491eab9f15cac1c984d88b1750cccd424e699d5bd38deab6ae973b3caded32bb66aa079bd71f41d12f0c2a631fe211951e1b73be1314386a27249a8f99b476cb681859a7dde3fb7eb39944f4e85968dde8619369aa60e7055c37d2fc5ee61d24d72379bd5db7c9772919356190c8e741042444f242a8e07621e4eea66558e2ce2bdcb835351af05aaefd0baa7b3f74ec2784ab58177fd464a41fe27b54f5c43e045a641682afe78c922502fd7901615845961828f878d854b0f3bc851849456fb0f4b7b4cc5121cab42bcc29c0df4f30b0acfa923a3dafe00ced04bb8673326bf01f386e11c38842786cf06898a15b3b3aff0d5f1d30048ba3dedb31620a58d4cab0174022709e4bc16c815597e6626cfb5291144e3ef992c440233c01cfcb740208f8c68cd8b033f9ee0ed268b7f2d66c0c43f426d9061977495fffd9e34e381c5ff8c7a5310f62b0e44a1ca60435b7f2e3ec142786488556433fdedcdd0bd27496c16e6469ce237e77f2539e0b44ae38a31bd0c489eb9478a282d345acd3e88dab18176e0358af9dafebbd1031e301cae77f14deaf7e2f5e89e968c5c26992660caba67d396449f002cf6445bd52464ed7463e7c2d91d562ab19573b9ecbaa20c513b3b9bfea47b270361f7495dcb01f8cc48a64e12a2f26efd92a4fc1bb5003f6f1b3c96200fafa180f0c1b45b7f1e42fcb729ebd618f7371aafbb383a0a25aec4b8bd11b06531274bb0b99e69e79f651c4aebd6bd7dcd84d87b78b9cb90f28ff907ffbb04efda801e9e298a6283a0d04e9e2b97156ec63a089cac2d886754a842258b3baa9493235b3a5b152b67eaa1c205762d856a0adcd0228d15b40b27c28b4cc6d425fb63b814548b33f8c14644fa9ae59e696bf2987d3a9beae13e80df0c7a1374d8e02d98505fc0653280d6626b212747b5f6674d5fed865b1ea7717f5038e60ae2184d7c38f33a2f1d09256af36006d2f2b8bd7884aed92cbc3e59f88918833a22ed5f8e58af8ef4867c972cd3c1e2fcadcbae449366e597aa42aaf25a1a784a51429046f15bf93c3ab45c7c204e27979b06b921d9bbf158ad15da955425da5f284364150113e4f0f8e984c0d395f20e3b68cdd74a16da57138af2b2b3afea6d5266f1d454465b0a1bd5c99baa8ba28bd0faa8c5a2148b9502d178bc6323a5139211a8e45ca8e17f29c7bbf60e31ecb6ee0f40a833ce368fe76b1226b9a891d025067e52454fdc01d4e15d250d446c9798497111514505dd550ecc1a85e34e4fbe3ee8a36d745c734366ca4ff4332f30f999bb25b75e5a0e6c974afc939745a19e2959fe53332455e3cb177e2266b5b06d7ebae7061f60ac0b8a63a9e2b85dd8b03448407355210ce040ecf4d04ea4257840216c12750535b705938afe6682631872b2f5b5a7fe16bc033a3e51dc8624b8358678113639c8cfed90221b5bab71ed59aac7fda49e8bca12e2798c4f8254e392469a4c707aeb88318108786cef333bff1cc28587d50bde563fab00803bb994522291cb5f6be0734f1a60115e409f695b5ee95a7f672fe89c9798d0e54efc764f09d4fd5d4d76c8d572a94752576c715506b959bf6a97efb4d5816144dd361759626064939eed3ba9f109949f10324297a193ccd0b96c54469a2d5bd03f2802fbcc7f6dec6e41d7232d5faa01b410515ba93b4cee9dadddb096ee7ed26acdcbe2df7d9a09183a7fdf1017ad94f7f5adea6c118d07a1bb4bfe665f56e662b4296c9a45761c3ef964fa68d0ff2acc99b93767bdb84bed5daeecfb876535104cc7d03f8d633a1852dcc5bac2e8a3da14a25e0f2e3ece3fe258fa509ea5736277465c73980dc05284082d2760b4d28e7daf6220fed54dc0ad6569a4388c4e158451755e1da8778b4c719e24e3de8bae3e4a500d025fd7e44890f40e20b2e81e046e97fb4d6cf7d4c0594a507b72f921f1ecc51e526e26931a074e4c886855a60794dbdfbd5347ceb68f920b4dc09dfa95e6937ee50057d176a93107dd79c62fb984c54c0313e0ddb793f1205cc303e2b5cf49508da7d722aa39817377f0100cac0fbaf528ea92ee2ff9a6404a82c246cb64fd512599696f9ca54453b5c289fe2a8c9f47ff06562f6f8022798cd2ab96d80b67663de6926ffe8a167fbf502d75e2cc3762d6f5ea430df86b3a4c092178c8d93d8a17d81d6a3816fddcd7b853dbd6a73ccbaf947046776499c379b32aa61624c4333ec102b6cb9727db72a05b1073ea3fa25c58e7a584b834d843108da493e5ac12852291bf79051fff738d190dc574f734e8d2c02964b26a6e72e79a80ce30fc01307a625f65ff9327611167647f78653b76b52b895c04de7c57c45dc5ab5bd0056ac11ea5b69fccbb8d4230b19e375889a24e0af12e15ecc637ec3f64308029eb1811791cd1e45e8c08dfde401906a55cf1fb1728fbb8678b23892b8106767fd88c6d4daac475d2049602af4c88fc1c0fa35699833f3f1964584106b6eec40035706348da0b8bf80ec902d43b59c9222c4c47b0e2cc583da3782a2a1ca203d549e7a41ae3ace15efce1039d719159630e33c1a58e9b70acb623f836894ed630e56bb1c5f0d53a7c4e5a0cbaf2b135a7563d8c2bc01b109bb7fbb0d7e31c1c1e02975c20d56ac788884602096f119c66a2582c5ccb3b40ac018bf54870398899b1c0f2c8539db367de94dd59d9a477eb59632323e3cae0aa8a3862c02dff0671b774a73ceb065b003b26727bc34a419d3215a9851e606a99f6f67e87681c520c9ab64a357c4193f2992152bd21c82bd7342a9e67671205d58c277973840aa9dc248cfdef8582db39e89b722fd7952469b135728f599f04f50135e9dbf670ce1471ba455af11e9815a644bad4b082a2f0ccb720f160e5a7c99d5708b9cd1100708523679aab25b8df9edd7f3e2b463f2e665f46dfb711b92acc4a2d9ac889273dac6de5b49cf49fa6b861ade01354a090e40e510ef9bc0d3d5f0e81b041d10bc3f44d8c55687ae1b934115739012b8e5986c7986f58706eb34b57cd06dbb081fca17fd012e03435aa7e6cf3ca87323b27ee006ffa1189315d9949d10963107fb2e60fa71bc028d63129abbcbba529195e6dae830736f2e54cf82b5179fc31a0a184aa367f41f288a9fb1cd67dc824ed5872339f1cd62a70e09e900bfb2bc33e6c98f3be2f2c79d514eca0e3d906e4703840612e628e00999e31d49cb77fd535f897bae838bbb82d52ac656b4d14a8c28a360ff99e0c5fe4664690eb148f021b76d34d1451dddf5283e37e53ffdde58628d5f7fba4596ea7ed5de41e558fc1dbb54f59b560f889699763bcd879581915987a283c9b6f48ad6341e960e43012914836d6fd66ea9c40151f26f8940d85644aff50a5f409a54175664954fa9d403d0aa827463fd7044c9462cfe8d06b67db7b5e431e704259c9a2ac37404522d53a018c597cea2c65e33a8c95703887741cd40cef467786c70f9c5ec7abe118931a31a9700119f7ec36cdfcc2a642d6d1eb83192c5c1613bdfb2d23640b962d2ac942064fd357bc65d26a0e5e12b3f176ee2b380b69a5e23794c8858c8eea1a263a8dd65b2c5662850fec717c73c47131851d8e63a342540c395d89d390a1ee7d64d2bb9deb7b8115383a3fad5c9e75f8eacf5a95c310df332e95f39b8192fc4899cfdbe19ae9ca2e0fb037220c94a802745c77f8bd7aa44f78ed2e36ad3fde0fa5965a7bf2ee842f29792bc6941d3092a0749e15359b67792ed5a92eb56057c355349b9034860b82d718f0c0fd677167bd1b2c5e1d47d78e858b22c4f564470e36fa0910193c2b5f64e51a257405334a7554074469ddca9adbb18cf8b75d397c9e73935744410cae8a5b467e3aaa091bdfb57400e3e19a716a29184a48ef3eb050211fd1d0194dff49d0bac4810fea61271d1a7ca7b37aad8a2c1c490558a88bcaeefe462561f59d4d9801aa08b5c69f7eaf563e5b33329348699504ea7227648996c260c74be8cf8d3714cdc06eb743181882330e74e9c421dd820f7d8d2cfa3d5631ae76e6e09620144981ab39e1de4a1612d535f5b373cd618855790e360eea543d2e38b32929cdfa1452149a4228822fc3db30a28132d3502a90802253c9a2e98f4a03c48df241ccf9d1e5bcea45eb6210c2a6f36510b27d516588b7853b22e587776658004372ef9f4eda5e7dee2eca8468bbabfc6ceda592b756eca20d78c3a68f2c0343221be7fa178120107c6a02f112c88526eba614511752d63319749240f937bf2132ce0d7bd340eec501bbd4e8ee4fa7b6da799b38ce0d6ff3f7baa4e046dca81c5c794b25fb0352b63fd9778b35b21425ff6fe3853a88752acdd8b4fa577492b2ae07fb235e8557ce58e87936945a0aa580d784bf8be5e5e0cb7aa5adf3b6872b1497d61167956422b7e05446da6c407cef83d6459251eea4fd1d6f5afc503fa1ad9b8d00218270a238556fde801f36785ae45760a44e3b192fd7767afc2a961cb684b3e8ae7746e7553183c943068357103bccdd1bfa6546fbb74a02d103b58085ff12c40efe2a83537f34393e7b42ca0f641dc5e3485bda65a599b89f5a29d0ebaf8c63f31f356bdfed202c8101740fd87c770783917b0dfcf49a08901aa4860b036c978cafc0be58f7c8e4ccbd7cb70025b6b4e65cab10ec424c7fe165d3b74aeffc7ce13196dce6d9e204e141fee977ecfc7dbf25b2db6a0eb965e15428c2df3fa8feb9366b9c1a7da05f16884fd38665fd6727833e50c64ad2eaa76d86b1c136733e8830b2dc669bd032d22eda3664204b72f81ce4e20184d5f36acaf45b9bece856c34143e296cc9a58ffb3cfd6baf84d0f5bb8d3a152d3bb828feb85317c550a7bbc176a6da8e9580303ac189917a95a144d2437577727284016e8201db43c22e12918bbf741e62d7e9a4c7b5d6f5a88305a6b7be34498707158eb8670a246b30e8a01c8246f2ea410e9fac6e05d77e6e288a9b2ecea55d460c9e7b2cf922a1df2bad4ceaf64fc56dc8ee3f2bd208dca08af340d7d081ac6d00c94132b161104f337278259867539d23cfff7a199702d26d13aa10ced33d53bbe0a144ac9398c1246f7913f867f4dff717abefe0d9357b49395b5a0e560d50c728dd080b90942f8076869c8258de963f3a42a0cb5753ad0da3fd92010c1a9f703bb8c985668faeed360be26a08efe15b5704089cb3cdbdf189334e35fa9fc0980d8500b09f27e826ae0e3e10d3c265b4873568a23f28da2224eb56af4538fe6ae09697171af15639020005d2ad0fd9127b2720cc48f87e04b8109079988d9a1a3dccfe6436ecbb217f1310dd88f6682ba35d13fe3da0bdd495377db25875b17628f4c286fd0b2a1098ce8aeeb0a3d649fdb912b3bd62dbff1986d481746cfd86894aadc6c6dbbda7f5a53286e933eb93228c932c0d4bd3b305ef1e0af76db8f6d2a3914418cbd51e045d34623a4c9b32ed5742f9d78e618de740cf0aa7f09714ea0d97eb039e55ec1859459d89758a30ba7a195dd3bbe3f9602cb8f00ada6436a70d53b23d054c942af87339230f5aca168debd7c91ba671b5aee55052a858eff633a91b2dd8abc86642f723f5cbe910e3314ecc58ca561d2713970a10bde27b27766c3ea121dd5879dedd1a51f0907cd7df219938bfc415a8bc818997b66d96b138d5a28a91be44625e39f742cb0610e54e14fc4363e81e2c1b6c6fe2eddc3c8307059200097b0338cf6172f14fbd2f615af97839a2cb00f9d1df4b1afa867173a86456de48e544a8c1fa136356f45957ee3e82e80daa2952e50d44c37d33cd890fb8bd07a6c85471cf49b5764b18286dee4f590934d4407f6dff9caab986ce96e05fbde069c6fccc88b53a2482a9b0d28a0bb512e8ac87b7aadfd3065dc10b64651564eeee94fe8ee82fec118dab7cabc15cb2ea5af2f12a6eb7a3d223f777ce7afa9377ee4e4bb511754eee876aaf1476481405342c5a795757e05e6c9452eda7b56f4711023e69822ca8047b5e4e",
"spend_index": [
0,
1,
2456065750,
4294967295
],
"result": [
"c82d09e378448c2347aa8b02314eac9cfa4c796916807ebb845ce1c028126a6a",
"ed6848e169de1f42c18dcc704df0c25f7b0f4827f9bfa9873e5964f6df654a6a",
"df757ba39fb4d09ab4b637e8dd3354131b705e9059886c6b3bb2bced658ab523",
"61cffdb2f37ce69bc6c6e8231ec05be879b0d916c970b54bbeb61cee67f8864a"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 10,
"Witness": true,
"Version": 1850961967,
"scriptSigs": false
},
"hex_tx": "2f70536e000109f85f992f0000000000000000000000000000000000000000000000000000000044335c0500eec64bf50c1476b20000000000000000000000000000000000000000000000000000000042bdb17500a5bbf1a7c9a55fb300000000000000000000000000000000000000000000000000000000a518288000ae1db2440108c938000000000000000000000000000000000000000000000000000000002560ec6c00ea6b2056e540a2ac0000000000000000000000000000000000000000000000000000000025c2635b000aeae0aa3ec6cf47000000000000000000000000000000000000000000000000000000009dd2a48f00cef4d6b234bd3bf9000000000000000000000000000000000000000000000000000000006099e415002c6e9c1e2120f3e000000000000000000000000000000000000000000000000000000000aaa3a8be00c3405a7e384ea1af0000000000000000000000000000000000000000000000000000000011ebf86f005d74bab90a03966bc38b140670c83394993b41faa192bcc2bbf00e8c84cfe3e2280e40cf1918e7330a675f8ed6bff8c9c645949a01eb2e877b3d20648c4740742fae4b364dba1ed09c2eb9b16cdb40cfc03ccb3346256365923f08b6e3971563460fdbede483a37fe322f85983fe0e80ec9fa1dc674321ded07cb0b7e8053e1f6fa324e70b962914517800a1332dbe56ff58acf7b170cb5345bab32984a78cb3ecb0e48cfe65bfbc0e3416ee22c581fc3976b01d2f43abc52d14d6b3137d4f33c1840b336edc071ee3b86ad436d20f848dc6f7bb36652edbf78e8d655767c8df722b085dfb5d15b04373cba8eba2d0cc3cca8ba3359d2005c45587848dd008627aa4b5e2ad12ef5c6810d4c759f8a566dbfd20e19549cda73ffdc82398a215e1835c2813f551df4b79a06908c8a8e0ad5c8ea7f9ae7d3bda24fe46228edc32a9d71145bcdd916f6159169f0f2e3c9395cdc4d88f0643ff15896612ee1ec12d3e9bea09e3b4edb8bf30a0afdb95a33ec4b806a747cccfc217b87ed3d710f2a37193b24595f1a86a4c7ec7c411f18a3d29b3bbbf0ce1fde4445f0c1d539a78ede20f28bbf4d7726f5b5122f43d70432ac8e66bfe2c61106a330842df487463980ca9530c934e2d76a1fb08fca7c97bf7dd8ccce16e1df9a48a380467c6daffbe488dff8620049a2d58f40a4e3814ce4a23798677fbe0b7cc459049a4e08e03cf28b1aede25dada2c93b55fac1288bc14f3d0e86bb8aa242446e5df3bdd068c2892dca2e7c1de634d79dd045a2c8041205c07287c45ec6587172612c09df05dbcc67c72efa72f74890237b7e4be92aeb7e1930de7e56e587e907a5ea9b8f63276530a64927070491cca1f7f8c15e216163cefa25f4957bd0c6d0e1a8718bc44e303c843293aab1ab86efce72ddebce679fb9127d3c3297f40b7cb621e7e32d7c3938509298b5c93d7578628e46004592970b554d6e7c646928e071e6d64f645c7e473dbe2fab2cdda498945171be258ebf8f5e87c6de412479f85dbb30d130a19002090678792191d41c72d52787f3f60b78feeb415ac7bb76611ee22ce49473a6b3bcb4788e2da9c4fb90fb794e0af9dbffa4ad566d338f6df6e5c0bdb325a3956ba076d4825e4040d0373f5a40fdc648f73ae33baba93cbadb1243d71b946bf5d7bbf32f1972d1c4aea869489a2741b7807c8c805a16f5ad540b6ec1553b9a499128f911c41718d2118f7b563ccf55ebacc740d8b349b5a720a388d8126df9b2d97d8038b9a8c810a9f51713a0a84d9085325b8be5ac6cb4e3b02a14b99ed71b73532e59d4a55e5df1f036d880c594f2404c307d04de8feeee4ee26106288ba82b6de60a87c08b75778de94422562d8905bbfa09c2e8f61e2cd1ebda6ccd60425d66a2be59f83f48f1be9eedb5d8d4bc3671361d3898232734cbf87685ecbe3d5f49e768db834328704978c8e75ce1dc780cd5921eee0feb6e6e3d7d19e842269c22dc8ba860c6ca2ffe1ca6cd2fba9f5ff7b6a08c1ca4ff6f6824fc969b24aa5794d1fb8d91c893ff5cf878dafe7ab0897dbb7c16e1ab3a26311b16bb4f09bd93c8882a1c3a7df054171813ec7ad8d5a744261c6048fdf1bb1d3ccdf80e306021d35f58a51ae1d21b980f21f6642ee562db6ff57480b7c752929fc429455e698edb79f256ae09afd3e3e3fdad5a2bde732e86f942bb022fc93bc6e4dfa38dbad3db45ed411f3043c64a8f4e9ed3ca9925e5d8dd5673f6e51469f7f9eddb3b01e3a9827c51c18abb2f358e5a0e0a8ad82452d7fc851633f813ce1d77d2794d2ce74ae2a97710d80ff41198d054981b9b1fef2eafe5bb66e71d7c0dc7b1c8f016c65a55483dbf2c9e587b924e2bf0b43afc36c854a4d1717000ca36a667e1efe33fba38f91ae3c39b0267c6e65181d80ef636767a63cc16f64768db995dff66a4e3945e3dea78ecc54babd5a0d5b449ecd761577cd3f55e0b81305e3cd67562b6ce6067ebe33af3aa1a07cb0a8faaee604f5639af21acdf9ce454a3d4cc6a464bdbf2508ee9c561cf2f00e2511f0453702c9afdf888d8c4b182bbadb4ad45042c3ecaa3c3ec88f24d00678351eccf9d38f2c4e48239ccf94c6f2a00c6c2fd1ed3dc0c9b40150d4e5a0d3974c8baeb040d9e2c267c6007e1f3522b3524cbcbfbe73119630abb7b8058953fa6f1dbaa9373494804a21cc84b6e1359e6a6726a25c2659a89aea05571f0f60e9e011f33b4a66cca44addc19227ac0fa01fb3905b37d34f116785060ea25f2b1c828e5da49f8883fffc4c81ea3906fbdece5ae3be2469ed2bea57f870f3cf9b0402de22bdfe1823b21a61c1b356dda7beed30bfc3b6011aaafd2b063504d7c858b49394c7d6a470bb1cb76cc89fe94b6c26cdd13611cf699022e5f6f4e2e1aa0a5d9616b904f939c024d560b653e9e7f7207734bcbf1aa2633d161c811df4c88ca27bddaf1f6c80ec96b6187b7807ea3e63d80e0bdea17a2c2bc3c7c23df2b423ba99bbca5f567aff27651cd76987c6f3857e197ac68fef1342cfaeb45408aadd7a47693c14516ed88eee4101d6b1f986139ac0b04fc0467ebb13de1fd45261fa3a72b8ef9cd1f770240e81ea5946c7a3b5594f2d6ef955af638ea0717dcb0424fd9491827382cbb19191ab5d60e87ea53947499f33ef753004b57e59c810eb763b90c6c78416f2eab8902fec49a2d4b553338dbd7e50430a0ba38f8d1ce8c07ba23fa036b0641ab7c26f9c6a6636a3e01809ad4ec629d616c2ee3a468d2160e1fc9851d9b232e366a417634c998a3455f9b5802308332b83e9ed5eb8de216e6349a727720694248619822e0b53302d06b4e2fb3e04a13d2629f5d992319713a5a4a71f9bca80b213592e1ef0a506537ac4ccd84b4f54acffd9d187dad2d7748630c420a55d024499ec1a1cdff7d70aec883e08654c2688e4dc68eef97b774c0af5235111590212cbfcc8ccad71d504757e347d41ae8e5223753368e4aafc12d8233410b1a0381cdce6980045ad74aad209731dde0b53d7c8b8b7d85633405149a62f8bbef4d247f139ca57adc10413c1f5f363fcd18b6d10d45d1f6ff0812a868ca1cffe4a2382b7482ba11d72993a98fa68795838d017d6dd3431346c92e44437d0cd7d336082022ac155d9b8edccba7cacdc3dd51e2ec90e80467a4a23e7abb19e89ae5d99ad66eb3cd024301c10ef387828d1fdbe95a6a987c721aba65f6e8eb0e417f8ace678c7b0261efb99f2572d1a089ebe6de2226480c264b5b9378199f82425fb21fe768ef465bb135a2b3adcc72f732b17cf2b7374f38cf36ccec54b92c905e49c359406c87d1554fecc9c76301ce3a4364ad5184d8ca399609c12716eed4239ceceb9f79c3ee9fcc960c85037fd7001f218dfb4201c5fd81f35cd1b9cd5b12be52d69a070593b7f0f6c07fcc824fe9c2641bacdea9b8f056e02173b4302ede936084d0a2265da131be4a760f8c9777387e3270dbe16864478f15cd1058a02b7dcfd7ba9724a121ea665f1530d725c75591175cf907f30710cb62196b6dc19c10580a2a04232352975bf4f9d2df87029b089f01dc421138a2fb9b52859f3688b4eea3349ea6209b9c23c455c11c7c7c16c13d6afdc01dd4ef7c705253274f7a8dd005bd5292c45830f77320352b44f5d965c07bc3ef8005f047b670dfb25f2410d41c8d3a946e939349dbe26229e5c45b8f090db8d7f555583841bdd029148e65b6e178ba4cc2f663a9cd7be81bf2080fa468cc57539704decbb4c9b66b90b5f336abc975cd0897ce3d63eeb97ea6dff6dcb16efc99bb3426a0cf5503d9cb305231b1b7e06391e403d46678f7397049f56e5ba3ca3667b1d128236aed8089b3835098f9f0e5fd2e345c756b6d42f8517db441f592d1a1130da0506f3ce4a7525cde8d07c028557323b40194c4e5c652670bdfadcd7c7bf69180dcdbae7a3f5e5e75dbe9b1dd44453337fc9f1ca71265ac6f6b46607ec90b0e0c174f18327c7493c9ec89b6d41f9c8421a16199cf6e21cf3c200d17a3916eed78b642b2738ee2ea5318582d106ff55932713f90e40edbbca83fbabf015483a0b590d2fad17666a5b005191d0568f8532b26600e3ce1ac76b5d09b79c044c21aa78c6eaf6549035d77f3098a1b93c9ecae5b71adabbae9fae038b9b93cd9e241adca0ff5cb79077c3a35c52100b3909eba72da0b33d028dcfbc741fd6d747b9bbaff07f57e878c11adc874e0c5cc998c7808ae18069ff512bf7a3c4c446ea1f46927e91358c11a37982603f68f35bdc7e745f9c1b09d63435be5646c127e3c5ac10c6896e029049a7c23cce42e42bda087fc701a2d557a37c634e05f495c870be70c8ae154b53015c0447d198b9a1a6a0e658762d5e79c7bcb77b4bbf68667b20b5282179523965dfba42ddd87ffa4bd1c7830af752c831f4ab8b90030fff792411835015bdbb4c5331bc6e401747bb7a6942d54721eac39a404ac7afe75daffda519432aa89d511ee638d7244eee5bfaaa071f4dfa4ede03fd0701fb945082d31238e1d44c9c2d6d97e2aa5727798743c9a40da6e1272a461dc6bea8d0603fa35b269dd61d007f87065b598ca89d8b1226969c32d387da0610fa6fb410f5166b8bffe9d89fa98d6a75b4cd53922c8cc803c195a298d7983467b818a5a988fd1d5ac4ed797da0f2b412ad5b4256ef1bd36255e1fb2279c4c5241cd9ba165c3a6f41c1b965331ecb3674d61b53488ed6e165d0aa851582a9aba9af23d8827b6e5270b028f2e01c9d06e65a7e9ff731969be02bd1dedf4d9b257582dff87182e3b5c6afe36a76960687906b7795fea759861fd65e5f7274535b13067f18b535cd5fe05946dc0d56673e42bbda15bac7c653f1f605a38ac0b82a35f878858542a7d8bdabb3d64b9bb6b7278568a6ca81962afe21b8e0d6748b3df548e3511c246c7d348b90297cbb4225bd1d6abee7bd0da73e79ba09a05a3cf1a9524f1774f6d4a767c21fa2944eb5605f28db18fa3a78e6700f4b9e178271d09d74f9aacdebea26d1d9d9a02323ce72dceeda95340d5bdcfdceda1a78c7e5ae3f08244c826a8c3ec5110785d1097f4e6c525f61afed882f3f17689c14993c2970ad57db6d08d5a927c4eef41afd7730825f292ddacead1db33c48fae178e8fac562b39b5270c4bb513a9474f23a2fbeb758999a5a8ee3b28c0192d908861a00c53af214843d65731b190919835e49d5fb61abb8faa69cd2dd732df1798e6e7100c2cfe41d1a0a61c86838009d7e72d2ed8902de3e4d691f4eb1cb207516f86cfceee6317595df37601d7446ded069b5e128748b9f4eec83d37ef824629fc6d3d1be1d08acc91765918da6f5350c5568320155c9d490fd1390f6d2cd80740896c2537d8f4b10883d295db035ed6b5c1915523aa1445d175379a22616632f54ee4ff1c74703152884d906997df9ef3284951cda8a225c0c4ddd60174f71bebf3d68866b43277afc02fdea0119e43b0f5b995e3bd061691a7782d37ebabbe6f55645039d85ae6aac891bfc5fd44a389a99bd403716e14f2676e8be1308a5b341c04dff01b231eee21fa47576fe0a208b6166f23934db7af97ac638efd93bdfe3bdd89882cdb05f261e0f8cd1177b1ebf6846fa157c586483403e8ff72ecb917e06699b94b5c8b7debb525b450a9c5c18188ffbad5a7459b459151e8a717be46863a77a09850ccb83fd04343fcae6b38a6145b92a57064a3f3ef00c0441ef2d401b76ebe25b53c7a274086c65f8f9d876849e4e34f7bea927daecb57396ed2c9d0d127e8a9fb8f26f1eedf1aa47f83a599e7ec38a8c9f68b0608a9b3617e740017fad3ee95f284d6cd486bd291f64710c8d1591cbc6d79105748f229a7b75470bfe177b164c4d69e359c79c249da9c8b77970f68ee21e335621134595a705b373c376679a5af132a3c34144e47f8f65ec8800b5744c11455e376b5719067e4bb143fe610540cb2bfa6993a892439f8f60dea02872ae1e1c84b5114284b85d0809e30cf8564b8e6082bc4acd8fe0d6cf8520f9108d44c468b0fe90e5138be027061af7ae5b003edbeabbc71c887f7283657e5ffc4eb244bb0a87e82d45434e9e738012493eddab9c1a515e7964250eec0a31393ec4e1f04f302b0d5b52c5ba189b09be8fc3ec9c77e1d9044753abbdc2472fd55889945893183a578a98e582bdedb667c652e1523ce1b4b39d17522cb092e54b9e85cee4a898817e09e6be76c893a99d6260b8befe99f47bcb84248b0682ec4e648db712762d5332f465a8c17b48f52b02b3f9ad34b289cb46456bd22a31c9ed0077844c73853d9485418d348f91c2b72f7e7e6acf86dd0bcd6ae480b5be027f44a2314501aeb46bcb874106b7f1b1e67fd394b203d5e80604fdc8015e38b5f452a13177c96ea1d8dbb09f24e77a75f581e44d6804cbdc6e11fcfe9db27cd719498f59c3c593a3cf5c90ca7cf69ecda45849fe5e42ea09b344e4018fe14e8bb6e1a690e8f9f70d0c90ce8cc0d409dd5c5c3a9e377e01bf13d7f7108a74f27619a8c2ffcf243eee19b4f80f2d8c7a69682551e95da57b6d4fa6cc98641ee863b69a0b3b939bca49162a4b78f69c43c87390709547ebd58a4e1c7b9060952c333026883473984e64682bebfe1d5fc0395e97d3fd9784029dadfda634ab9606a663c2efca19c8c7dc3c45ca6fe4162a4b354c056ac468a65d62b17c0694471bce90db75d471ad38dfdef1b119ed49dec8351f9f8abd790793fd8bee2c7163bba5ffbcca3ca462bdc6ffda7413be2da0dc8017a08909591dbbdc255f62eabb39527fe21de79a8318b93feff109d941a93f1608768365eef42974f3ba832ea06a99c23f9151bd29a4f8011f6a813549e3a2225980dd99865d7a2c174cb50bde4bb67c34fe2ea5b91f2921ac2f02f8181b1140c9f280d137b4787c1b47282c413877ce7c30d38c06889851d3ea5e13a0a5a07b3aa4f1949f9b4e59340a260a7a8331859663aac5e75eb3d579df201e967ee6e69940ed719f24d8bc4ac4d289f0cbad1ae8285069917b8a8f1e2dac42a4a8460b5cf96768fc1f18d0c6551f77c5c530d346c0a2c5b9eb4daa0c12b8a2d1f599e9e0d50620af8e88c924461b388fb5a48269f026a7d7d85b0bee6b1db1f9f9b97bb51ae2fc53e76443a235212a0f901d29f4a01dcda61e32b3153a9d59a4837824cc8f6df6298fbc352f29c962282907d6782443f989ca5db3f5fe46bb80a759efb916c3e8b173fd1c01df03e1edb77a8984e4cc3a8d3d1ea3e7557b599264bd775bfd8a95b57c9a8db115712bcdaf73aa8794d61d3c93e328b4c141c30ab877837d8dac20883e9920e63f99dce69f9a39b47cdc4fab37caecf1f004c70f949320d0ff1502b9c933d6c5c821aaf2e8451a2c84e2e3ba448960531a5cf0a74711f021e5dbb406144755bb01f8f8150ea4af9ed8459ebeaaff6e0c622710f1e5294df0eb77387e312e16de21a6eb4581d6a030b3a6500f4eba9eaff5ff987d824b1d544e6c19a102d8c1d987323de8923671e111aac7997632f702265622bdc77253ebe8a021e7fbd92445a3c3ec72af0013275625e5354cc8b2f1d5fe2d134714f23c6dcf89b2ec2ff2512ea30c847f4182a36d464370557a54c322957404eca9aa27bbf94c50fd2a017cfbde7175b96a6e7b1d9ddfa38773c4ece20005ded28ec04b2e36f8bdad2eef76b566122273f81adae4da7562221c198ef2e7718fe7b453fcaca3082dc7023d4fd9ca49af0597559a157d28d1af720de30c05aa6bd41a02ac0e2abe46146f4e244c1238e522197c3130187a89b3252d4463272479be53f195f5dc4ae7aaa2198ecaddc12999860317056fa2d40323c15f3d127a6e24d3882b40b54f7dffc2dc5c1a58e1e70215f9941f18150674a12c704cd3440330dbfdac013a5eae77f1f160c7c0df60b938dafc8abe82f0cbc9916183b9a014f8205af5d06b9deeb7e698979834dfdd9a93bb62a829c02533bcfc57e0f23f29ca7cefa2ffa34454816571c336bb50284b426078faee677f4ed67e5f67fb3eccaca9234e7071755447b91b786c694ff647f5a45f8802be1135d28bf851dabe3584dc499d4ad1f4e0053ce41186ff37693e46c0e218cf4f4e43754983e246213c24c2e64c48004dd2bb96d4f00e5bb937399f57a28ddeeec97fc5e104d3d0e50e7bc58c8dddef00bf90de90215c514a625ac308abb9053e1cd9189e37a52e03e0c06b981679ae07659a4e61492fc5e34ac51822ee927bbe3d660362d20b14feb6f452f3dfd1579faf884c51db2737f4ce64afe841069b23ac721a851f24ec37620fa96a493ac06842d9544f7f67c77fcf23f0483730fdb901248e6f589347b5d7634040ba889aa39fea76ab845e18d40273e9e7c3a5cea74c3cff610bfb14b79683d51b4de6cd888145c69f3bbf013667d7457b9f8065617c3de4acef80126d9c17a4f23fb96691d399bc152fc89d7f75a44b8b8854300ee28e02ac0a1fd77103caae47763268a92b437fef204728fbba0790f62bf345797f2686262b8c3e29af8ddbb76d908c8084e05f53893290308c9bdede17bb82d9bc4b43fce3ac7cd855825a1f0338d0ca28a047f8309f184823aff0690d9d34ee0ec0d25cb98f7de154f83dbcf2b1ce5af5876f6ca657717439812b6fbff35b5e5f5716dd31079a3104977a9aaab30ffb1bc9f655f65a48c882f86949c45d7fb39f7bfb14953a042ada8d9c0c5e50eb54f365fbc3ae91529697bcb8585dd490bf47a2f69270df66a9d5e3c9285a963554a16b4eae811051a2a80009de0b239b080f5aad76192d5c62209c07d3c56e7f432aa1782b82afaa0b38e8680fb33eaee7d762e7c28a21e30a02f3b0caf31f48f476c53d5ea179b16f211c5ec187a3c98fcbb511d764d99861c1727dee1e21fbcaf7c84227bf7731995e0a1ef9cbfd258c582a7ae19cb52a6ef046f035a54911591542125d1f6c4b2f5ec60442eec120ae41b37d02c075d891de1ad3b2e2cab012d685d566bd06cd06d36783e954e78e183c88945ccec4c6189364a66402c7a45f255e37e66292e18ea1186ba3d413fd7a01b8b42f6c952a5015341cad5df625e47225ff316637c3678106789fa1c3c49a2f3972b6534bdbd913756a20e25ea03b960408ff617fd5f4599dd53c63427236fcfebb6ac7805c8737d33c2b09f72ec2110e82791ea303c3b608b5b13eb15771c9051cd9da70ffd41cdc535681aecacfd88a1be42c04dfd3b2803387940e91b800275714c591d40055f26b3eb6b942bff7c347c49b51f565a9588ce6655480d621378214a1d1cd4a6567451ca003603d1217eba5a3be9376f48d7b1bc96eb21b18c326d56f802c45f52bffc7cd9a40adea9c94f8b795563c177f281b8ea13e453e84cf816fd31a96dc59b8dab3a0c1acff6e6e28be2b2c15c1c89d2dd3bb1a92593539d5279d881306720588f9eb73c9541b248a5e34b96b445f59d8f4e971b1c0d33949bbafeb991e157f57e233d24bd153ad167c2eda39901a1f19b00891218b808242203653dc6d204f81c2423a89ce2d05fa82cd302508f45006f0fc490dc255e74a4232530bc19ebf241764f68b8901c0944f7e141a643e9cfd1201946f96c5efd4a09b7fdbddce6a0a2869c1079fd447f4180c10b0161909047c4493338f3368f7f21cbadefb080fe3bb27ccc9d91509581a1e1ca5fc0fafdcafecbb69a93d40354d8925cb7a46767eed6bd1c277be8bc36ac6c9b79523db6cb834bf1852e3b0a35b3561e7eba16598c3e3fd9eab7abb2f39d8a4f564e17b54f483a305580a9e3f879c3792a685d7c62c923c932ef008c756c4342d467f29e5948ca51f6bac2331cfaa5a05ac94d077c53f0c95fbac8224fc90b5b8d6e011bd776a9f081e95f97db77d60b01741aedada47ff51b9c318e639db6c668dea90d1ba709c48471ce1470c931646fd1d64c6b59b175a6107144ae7193796f480327c9538f239896e4a475ec30a29a98d0c2c940284dbfd2801b4604c746bd9685a0ff9091184bfcd1872745f26264db828c9d705f26df8f733c58879e3b8fe128511668b6dca673983e377eab0f9e44036b8c16353ffde6baff9a148209cf0b86fb74d54cd613d89dcf375c70bf1ddabe97fe855fdd49a768703e20b84e1d15fbd85b221cffd6894cdbda6f21cc0ea6b72e2adbed8023286d1aba504677fb0ff3b1eadb6549aaa84c00285c62abb9f8bdfc0f69c169278c22885fc6bb6ee5c8805bbbeee11472a971317b3c51a27ffe13c87c38b880c166b6c10b856c4d406355f32f557c7b5ca2404cf665699930bac5c7850bd026616d7ae02cc65035e602abb4f40e0ef971f7c3e11b91791273974426cc13d2b981f213d3cd37923ef2f6d75249eaea1c8079bfc6212f4bdc9d5578dbbc1c38471f306c6c90a5803e65f090302aca9fa8826c786e9cd9c5bc78626ba51011c6d2a741ac307e4f9af332faa5c81aa4fff22b6215e85409091187e41dcb551c8d62ec6725f686857529af9a214853f069429cfc5ee0528bfa9faa710ceaf4c0933e83d1cb16354be246d5dd563960a1cf03b3603c24eec5d64649fbb69587903f06c9d99caca7ae5ccba4698417e6fd17bee08237cf8de87709acca4615f31d7c1455633c527cc25371d2997adc65584343de41053f4f23db27992fd00013f69c079874a9fc74307d9f25b863c4dc660a000b8750a875f61c7be16862d8e004c77302a03c292bec3f7e8cb904cbeee85f35ebfb998aed94b41910046c0a959b82719a1fa17bae366e60ccd76fb622ee089431e865d2efea277f170bb203f9e3dcc1de6999e6adc51b93ba9d6aa48102051f1acefecab1ca71b4419964b639c3d07c0f13fcb88a21ec6306d41a78161e24e8ffd910424a313f89224d6dcff75394b51711945bd5087239214c21dd8f22fda18a1d7189626b75a388b454a7ba8061854c44e824c30e45bc25e0e70e9e47d43d8fe594f333d254610d9781dbd4fc1366e7b28dbd1903e6f9de267c8aacb99d311d325e612918adb813c0a863ae8fa772f",
"spend_index": [
0,
1,
3276246661,
4294967295
],
"result": [
"827214062735032eccfb319cd4d6b28b02bcdd985d6396b5df909dfa96a81f21",
"6631ada9d609bcf0cd52644496784a814c9e6c79382ff72681d1cc48749f770a",
"b06d98da0a034ae6cb6e4525d057bfd85ef972c253713fd615dcd84e4bdc6cdb",
"cd150c050a63027a78fafad232300fd1e9fe894d46bd0dd41c8594399e032cf9"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 8,
"Witness": true,
"Version": 540583660,
"scriptSigs": true
},
"hex_tx": "eca6382000010a1b2959370000000000000000000000000000000000000000000000000000000058eb05befd5e017416f0a12365fa7a467985513ad60df24f5884a0c5eb5c40c0c006ddd6a7ef321ae6bec85275ef9a5157ddb8cd9b1c4bf1a918ecf553bf01542a3909e266cb4b223ce3f144d145f26da57bbe750253a496d74a60d184fccfb7301dc703a3d418550c50a31b9155a2d58071fb7b79a1ec9c20bf6d8007ab34697179069394ac08f42e30a3ea70f74579bfd7a183826971be9f7684a970368cffea328b678e9858486d41e8a9b5fadd2e3ee0f46a7da925992c345679e934f918a3d7818ca84790e9c0775f876dcf258935cf476fc7df4fc127380fe218b1d6fb0c91abf43a2b60269003c3da5358785b7a3f39b16a213b31040d68078c974c292b0fd3e597c18ef397e44d15962c7285fcc107987fb173e9de70304889bd6f7f0def8e99a93c949495e4e08b7435b424ce55ae705706dcbec5eff75ffb025a09586e28552f4ea2b5e581940bed77e82932f0af834d9544d8fa62787f64c3e06263cf9062f93381b20f6642af6200000000000000000000000000000000000000000000000000000000899dd342313c445d60085fdd920549a80fe1a8a076cf71f12fe9c2d8ec62de672955765ff1be6ceb495b7162687f718a4abf41b06c3ba73cb19378418ba90000000000000000000000000000000000000000000000000000000013708f5e701addb97535fda831e8ee5bb8e6ba211ccc496fdf34813b15159c09cbb57ecf39cf1f251dc1a95798957698f0432d3f4caa636cab418ce6f04bad622fe714a283e38e178a8be62c83f4e92dcc829b0695851c08eeb98990aa3ebff22eb59f9363468b8eb0036f7266d6a2018a0a82a1e419a47142189b9654000000000000000000000000000000000000000000000000000000001539f2b8e5148b502f3b0fd8500c36adc49725b119e1dd5ecb3ed6435473d648b66adaf502681169af50887e28a0c608218a832b2126c193e4739ee8174fb751b3c985fa10b8fcd8a795b73b1ddad338e7d47245c78113caf2e40985085b89a7ab7a6626d8b0c991b3307c4192fea89278ec121fa6959f9ce84f5ac16493564eb43b7422e6bcd30d6e3ed61da77453529014a8f169908a47c2389e0b8b238daa8c464dbbe2c18f05faf933157340eeeac36204b5890d6012d58d43246094616c475abbc006ca307cd29220606cfe258870a2ca4b80b711dd02c5913efeb24c7ce465f0d1c2bb67bfa42cac8bf3efa6b4504b00000000000000000000000000000000000000000000000000000000dfabed5f40a981079a2ef0b439503ba5c642b2292823242c3e42fde01e048262438c59e53a7f6840b34e3365fbdaadadc96129dd8d82fcc280a253b8998557259f4969949232a6ea5e37c310d700000000000000000000000000000000000000000000000000000000fe227dbd10923aa7ddaeec15337a8a025546993d83230bcce566316fc20000000000000000000000000000000000000000000000000000000014ba700f00f2bd0796adf9ad84000000000000000000000000000000000000000000000000000000002578775617c09ea50d01624ac11d4324cc923091e3749ec4d85050c5763877dd198398a50000000000000000000000000000000000000000000000000000000006f28e9e009bbda5a458555b77000000000000000000000000000000000000000000000000000000001a0878dbb130b621cc86fc6307746f66767524d3715b546bdaaebcb43c655a0463443213672fb137d4a269528037611000fb24aa0eeba1cef92a197bec1bde6170969688b3427e0c35715b97250fe3d7009606b39c730beb3b5b771aa3b1ec49fe6db398af5ef121e24328e9723fe2e673b91bf16be49a61ffda09c8192269355541e0306ded74620a80c54060ec16b38752be1b6e119ec9c6778bca4b9b8283481a22a67ce32f486790c1014eaa4328b6d6b95bc5ca4a4bab26085c8a8a9c89047b4bc8bea712a0530956d1c54a2acfc3004eece4887722ec632fd669c1e9a6de47a139b2c32bf4c0ae8a0fe867afed261adf40b2eaa67023b0e50bb099463a1903b5acc86e57908e72248744b11efb4e044f4bf12eba2c255335ad9e2f19719d21b340fb298eaa5c0529772f9fd3f03e2c9e831c2617f237597c3dcc19622c40b0cd80d4633671bb9cbaa53a29730c2a7c102d00fbbccfaf728462b5a361db72e9e837145e0113fb8ae94e62d66ab5c5b27eeef73b8d1ad5896520a8d7ebf63fc99eac362a465b38e43ebf1ed0b86bbaccbf16c829a5374ec8ffad944092058b857af89b79672f71d3420e0695e400857b6b25bcedc31e3efc5fa648d4e6026d6b184f90ca8d5a67d350e849d0da3fb8e4e205ed8b7aab2470a9415a7a4e89a15bce147d063c53f69b47ffa2527a4c4e4d5bf505589474a798b9d708d50bcd26ba315bcea192a97940704d4c13947262dbcef9a3546da9be116b990e93d32aed1049a1e66f62c28c70cf0a570e79fe8467178d7c6664ed39066cf263519321d73930a63d4f85e4cc7481685a12cdc90b77d21b22e49091d2eb33cce3ecc974c66a0b0b2ec88ea628e076980aa17a99d0abf941a9c4e980ed588ecede7a33659df5f9268c0954fd82c8451679c88ef6eb7f4a8ffb49796146560750b0cf58e6fd00dc917474447af20039283cc37b6a4f85fcae3553cb110d10c052367099a20e59d25a7f6e0f0f373158c458ee9282302c549c4c48f0c261b3b1114c279bc6912dd5bf91ccd05710abe7b80750bcf9482062cef48532aa866200d5c62bf93497e97cb978036de1f3e76098ccae2368b6f872702ddd3a852f6cd13917479cb9bd1c6312cc09855a7ad5b16c0682489dc1ec8317f146c8bb52533e9b04cedf3427db2961f25e9a5b0607426e68f5acea2a9f20d7416d89c1eba5467a7141962d4d8b168b7756774729993f5f4ce1bcfc06711141dfa5bd44884562759a4ba1741b3dc216fb937d945c30bfdea11569398c095669ca7206ca8c1aef50580fdf6453c3d30c2de20afa05de9aa82086631d8d7edf225a342c6caafc59efe071e6f24ea027299633b6edf0204d5cd6b59d32da9c8095239ef698917db2d56b06e5f8f8e3994cea95de12c2abfe5783d72104a1c6c581fce3b89bf6bc419ca607c1938bcd2462310672c8dcacb0b8d2cb4183854589a20e32f6e81dcba5303ab663e924fdac9f9d8b9fad9736cf24893a401a75b33db2ca045c329b8a17afe8205ba61d6d27935c15274497b4485fa5a7d6c348b2303649c4e3df992942fa416f1b883e6e704331e1cfaf08796cf4b33c2895499041b365f52d9ee1299a90811aa06c2797eb74691e5fd1b38470c4da04e5dfbf153b2a84cab6f34033af85aa8485d1155e005096bc599586471913c9c894c16b83c8dedf8de6e7c9be350302edb6d7bd3302794cdcf415b0afd5db683089530a4b23b47292ac2bc8b4c1ffc48096aeb92462b6c4066cd6b31cc03213dfccf1936d072877687866aead5366e3bf33afb28d954e168c0f0fd9feb0c569f97baffc260d6a82a50177e6569ab96208023c0005773c3c391680f3ea4a46627541a3d4564a59ace01e4a4e56cb62a5c057f15b4608ec83b71b375c6df25ca3d8c975313a7a5ca6cc942aacbf1c4fc52677f7ad28fe9792b7e60d83a9dc4dc26afc70cf6aebf12b5357d014ce0ea09bb5d8f658389a68f35c34a577450ff1a11916e5896090dcf0c7c83136d5bd2ae45f572fa29f717b87a2cec448c8e7e937cd20f625c350c8cced19594e84212a81ab3f9fee28df481022922b278a277e84011b6d178a3ac145789a017fb6bc5878286d37dd9763ba8526b3c0a90cd99a9c37b965ab39b7df931ecd8cd40c40e5595b3afbbcaf2f4e05232cf1767185fe6e9abae7737581a06a360b7d5f2067ad6766c304b5744ca283f5034407cb93167ceb875b4355cc352dd9f02289dd8463ddc1e2e1f31ac4e065fa3eb9f570019fc29a0b5584133710cff01560b484b7c99bb7104ce2dfea25e01fd0a2a41a5c9728caa92c497cf52d5bd04b509518c8090348aac975d2f4674edf90bdd3f5d923e40ebb3848b11c93eca74105874b80169b79406f04d33fcd625ec4119912f8108f40f0936fbc9600d6a669a3094a35f1ade8296624df65d4c94168887bf1c3c80eca6c70e68162f567856f5be14e0ab8dd80a534030e475b20a00cf157a69314b71706e8f40e6e1ccc1162d5a243ad37214ec186a6552e11853af4277bc8aa4a87532ba47163b690425072dc211693fba20ee91fae2100c85e4cdbf042ebba8fb560cb1b2853b74ac7d17f2b16a2f57c0e33c10d244a7101db2eb346c84419dcf70f7bad2fd7a5c6f6aebb45953fdd40d86e537189b591e42dce0ecf67c37b2f66e218d26c7f1756c28e914cc652f8f38f4bc96bb04985ed55713086d15d3bc67313edf497be1863d6455d998c7ba6710123af616b194f910fac6559650777058d3d85fbb828bf537bc1defd59bf50d21242116995421235049686b68a173cde85475835082b0a39dc515fa935c67876c233901d6967449c166b7251074671f706e3039e1f58877dc2049a9a0ccbbb5cf1934b6b0b18e22aa570254978bd8877c2ee99e758d1fe5bad4e60c2232c71556b6507d401fd990191a7f99349034b90cd3cc58bc4537b41d5231e14330a993c734ec8848d6907a0bc2acb7dea06ee8cee593e984b07451e29ff45b4685c0c71e84471ecd1da4f1d4065cf9fb5e8a755e07e701267e2b2acf361831f3c04d836369fc7dc8d75acabccb83bf78687da52a6fb91da04e6a66853b3995120664d74f5eccb64e739b1339ee0d6b898b415cfdf41edd5966c71d2d2fa910f4369301d874475aa535112277f2df606125b8b932da903f4d92d818f31591b48ba8d1e90cca8ea989ee563262c63e799a1f3f85f03cb82566f6474990282f39634a7df688664482e6a18e05d751e56b4874d90208b9d2fc07672fdb16b1eb8640fdf679096312da8603dbc68f1d9f705cbe156f503da93d2606ee80cff3befce1831d6bb7ad20408dc7f2dd634fff562c660711d8ea945ad551f5d667f225724141425bff0b550cd925e36869c989b205a41421b7752bd2ea8ed286f33224e701d6bced64dc97e660ed89eea434676f8749bfd428f30ee7c4dfd2d9dfff48761452418c4135cfcc2bc1c071693236c4b6c974591e76f48cd71651a7d9e6d91a99afd38e2e804fd6501403161f01b785885b809146a5594de87ebef0eedf391a9ca80828910b77d08f26f47cda7911b0814be41116670401ccc9a4c920a990fa00610ba84affc18a06b0ca3b2121c8db48c00b841ed858d113afcbb460e7c218dc579bc6854e86610983436e26952241a4b20d9c7b90ee1dabf1c5702eb46fbfa1b0070f3830066d8e9f1899def0cd7a5063c5c3f5ac3b5713d11a1c4c5df1514cae85844dc781d0708352da70e61df9d0e5076e5a6ccd42112f0b91b4599214952db80accd5d46e1796e3851c9e9cf9510e1f0fa273ac037a8ef7439546a763369c9e539f1e8193157ba9653daa58f99376b37f485915a6da91651768e94e3cb9fe8cc7b6a395c133c230b18d5d5e03fdf4230b06a5a8c73e012792152df55d84930855a4f7dead408e2ee2880fcab4a8805082f1ad8e085f4b5290db413fe63f6ea3c6404adf76f1bf44478ee83118af2a93b5f2a0de313157ffdfad9ca22e3dbaaf932c573a570a8d807b13807fd750102e0538f3001a0e78c73b4cd7d051213a868700134cccbedf1a2f642270d15dc890e6c043eda2d013cfbfd5a962480bd7ca757fea13d19a8a3fc14aef6ffcb326d7616426a5c6406f8bd8a760bc12509fa508a3592cbc82c729823d2f1cf0451c34026fe937e396ec41eeb93b2a656353d5492116acf5f29fd09c09f6edd9cccd15e731b990e611c323c6421226f6f1d3c4f2b234d217821646b02b8455b052048d65fa43201d7503f7905932696bb748798e6546ba9833e1a9441dc17b25a1acbdd9199f7ea0a80a9ea101124d47a0552ead5dfb30a6822245133f13ea992b04a34bd877c4dc5f2ae7a1ad26349dafc21bb37b5b9a6e273ede1eb7cb2b3901956f8aa25f289889c4e837f334d3c892535756baf9775ce67479f0d0114612e2910d2be874acb8ad30dfc4fce3c0f5093e7cf1815cff422452c16c2cc302d35ed0c3a90df9a39e3dd5dd42f3c7ebbf5bcc369b2a9da6c145f18b10128af116773cda9e4af067e2f5302c21c5daabf4b89bb02fcd2e5fd680198ca14acf5ed677ede8fbf224af0c26958fc93e90243aee7b8f678f029259bd89a6023d1be5c7aa4fe9a91030ba4aa78eac12ae36be61255145add8390dc901fa478ad9876e489900a7a2e6150927c32bc3161a8e7ea455b9e2d7279898d0c7b18349fe400ae7c481608f80d7c7c9d7f5341e41f16d1830f453dc07d951ca85ba4197f70e893bccaaa31c75a72c7bf5b0241c39910399c93ca6f1e8dcc95c41b5050ed7a5c89f2429315c181c672698e3b269aa894bd7f862107c76f0706593f2c403c53a6b22ce88caee9ae628d9a8f3efe59a6defeb93ca8cf40cb12a8586b8ece2fb625fa0d97c8ad742383c074f4d93c5dd489b27481f521f5b2fe7011588a71a1f0d43c9f128ca37396d31e65eeff3c612a5b210a1fc6bac607f56fe053ce5397647618ea8598c22ce4533f9b36ade39f520e0ce48c6fae61365873755303a3310d9292cd747e72609518f9b014161784c0502ffd9d198c1966c3fc95bc8443806b026cf2a6fd5001f6c7247dcdd6f46294ebe370717b4283802a01300e57f071dba14cf2bab2cbd55fc57798463ab50d0b411be5c675f02187e735ec8d759fb9cbf05e3a47d7e028ac70edb2c26c0b3b3e11742b23b4675e4a59c35c1fbbea3f9d10b8c4a92a06a071c6bc244e4ba2c246dba5a9d7bc54a2300df6c9b1b7ad188ad190140d86411b861812887000cebdcd995ccb93863371d3d8fafc77509c77335c5f91ee36da919c0e6e0ec564edc275cc5c63ec525cdc06a286c67a8f5993c8fc4feb87f3aeec61b4aaad5e6cf21ff1607b40bf0895e192c0e2e3fdffb5159b53ee2fbf64c0b2427f9fc2d468d289a78f4b52bb35eb98f385d9834a6331c8ea11fc37cdb9d6bb55701d0d52fb48d87e7d7bba0ffd17ddbcae4c8cdd7e3dc399030eba771d5136aa4d63aacf0df8978fc955b778252894e3e6c8c0214f89d4d64c8e5ed77603df7d0ac8608bd8cd7e0e9eecb51390c00a03eeda91417a187f916bb403fd91472f912c53d99c36dc217cec8fa487f7e758da52cf76266d4914bb3b098ce47b415b45a9c972607bb9286442a2de5b800db31c5985728dafa867c68e13f0d46881fb2c8f4776f369fc29b59d7e2b9a402b8ec63264ef6bab1798464814b377fd41ae85a4ad92ce7287eb57f2b9e5ff60b0dd2be159ce653e2f2359ad9c0ff0a606ca37da3ea43e8f5ae9c5347a385ff3379539a4abd6e4ad417eb18f73dd7c2be40170d3b92688280a28e3545f65c97440bebc4e7fb1e79fb2bb9ca666a62ce464e75552bd6b2273c7af7f4a8a1db6df2509fa555d48dc60eb3c332834ad23e62911bdacca0da95910db378c7f0231b6742c488d9cd986667f6b424cca40f646c778e7c0fdb3190609f0d6d2eb4c1d816f1bb244daeda4a109315b40d3bb41d297739e0c4abd41c518b8a6d8697a22b7d51be1b820bfe085e48eb71ac8fecb0f97cccce09bc4553c178568d1e08b8db653d35fd81ab3ad51854c8447e62c79f6a254ed65b61c9b677a37f674c40542a7a6347bd876db7e862c579789be482f2f63cfbc25cf7ade74351cac7eb49d6672556c4defa01fee9bc5abfb27956298c5fdec016ad62f9669de7650791af753320e7e4c2cbae887422c57826409263a7303977def46a0f93c766f8bba5bae9b78bfc44bcb331f4ce2c244b106c54667418bdb651d636ff6d4097e1dd4b9da01e9356ce4f9e8f5efbdd017b80a44ae7481be1482776d5e354e20e6b87034e85ceb2b60a4c036601e6b76f25170ed5cebd184d99d8f3b52016333ea5ec9ce2b11c984ade37ae1290ea48c105f64499fe5ced928a10ee54096ac29c9a46138b31fd7ebfb616cf9919e29d7958b635299817e2a6ba0ac4de2f68c358d01ebe2b00cf836c4925fa5b88bbac5e8521affcf2c8b0c4753c93fb23081e43aa162075db6e97ac327367b0967f30426efd6e11ccff6c9f10652489362a9261ab97603c52201d0c5ac75bfc7efeaf34a8044d22eae8efa46952baa6095acd3aa3ed8e93a82dcc2ad9ca16c68bc78d97fa7850607ddcf41b4ffe13a9361df48beb0cddd380457699ae1f30097167343378c01f739bb56547643671ea9e76058396e83b14970fb2df267a8dbad6cae5a5c4552c6276ca84ee93a221adc1de879014e2d5cf8d3e5d4c8859feff2967696ae0efcdb570fb2f2fea3460b3adc335d2ac666ab75bbace0570dc3aa0faec0de808df6b355ddc9e8b6a7e282dd09d47390e4deb7c3c5f6424c069567ade23e2f73335a3b4919704d14c0354a13e968f8c7c62e0dc23802fd3a018e66397d222b7ed9640899095ca33db4bd5f77b01ea123b78a2d2cd0839a2529e20faa40547f30ebd35d136bb470119914fcb9f2d67df668c4474cd290839379caa49a135556b1044fd92e5b190fdf870ed019e817bba3df8f442154fc0dc6ef6eca0c2a537a418703f68ae2ed9bf945ebe6228a4b2fb7cb4de379bcb0019e7e00c8f47fd83614f71ac3964f96dc505d549ce5099ecf519f394876012859a922d641cfb874b80cca867c51dc4a993ce3a41ec6eb77c4be3628f8b95a0d4850d2ead8ff37b2c8f65c4fd518d9db0050e56048021bbaf8841f0d1553a514114e39be9e635de258f2ab3d1cb4f4b03785f0be9bd3bb35a924a8b6a813c087a938faecf8d421e1a2eaa30dca1e1de99ea6fcef7eb7134dbbbffb43472f2391f35741cd16e2dd7bbef51989e2c827a997c763339cf6f7b68ccd5653c5fd2c01841752a81c856ad4f1d16a97877cd5bc22d9b92250bc741b255d71b6c802a6bb697a4cc303f274ff0136e613d72d20f0da7609a05e448315e15443eb95459d46d348a40a526d3b579d8e03beff7e4dbe07d729a69aa4736119d6f38f45cc64e487e2840a1e7ed1cdc26caa44d1822a80933d0f2586e92cc540444799fb2fff9c42b1b460dbde0c812569f4f9dd001f513a47fb2d4934e914283f37dd3ec40ac45f6c3c81700eb990296245e0a75d647824d46a4c747cb63a8a0d167a7edf292c44a90481a08a49cab2c7fefd413e7a95cf49798b23a2367b7a23f47945eb562fe373c6b3117500c6db2c557a16dbcf0e24f8ad2d5a75c005e14c2e8d420fd682c2867571d7142a7cd460c1339dbe6acef70f55fc70689c8b0b5d235c7d9619f3f8c98f871960786c2ecfc79b02fdb7016dc578fc7076681fc7dbdd54f3391e563af31515bd4097606460678dfe38bde0aee6fc74b7ce15a0d0cc6b1326d935b00279af62ccdec1c45cc1fb5f4cfdfef8e94354e391c47a00e160dc5fffe1eacdf728437a1c1f9837fb6abf1572b653464f1e7d13484c36bcd4131b5f46eff4d7d9ffebcb0ae4f95ca07de8d448649150273309ee4841293b3028bd7a41388bfe7a8b6e3750771f8977fb8a4a525799505ea70a40a8d04fc77a65d1a8b687dff1ae1e718273436fe07c01611437cc0da3a9d78ca631a2ea61e10261b2c328a714ebc2a6344449509c4bd30cdcad5b35c5ce431fffff438dea481bb623b6362758a25ead121d3f0189bbb2c0873c249a7e9d4790e8b67a7d02b4654cc495a6bf4e82e05d9aa40411b4b222d89a4ddd91d03c8259fbdb30700c7fccf71f8ee0a84b87c96b6130349a230b56cda052a118dcd25c97560111fb1a1923aae332307e29170f3e3f0f6f708758237caa52cf887ab6d868990e8efff3b193e58e32631a68927b44acfb5ef69e8f3f54a274b1b50a213bb911e32998e39fae27c6d8a21ed160eedc7996f000c182d3f9860764512c5cdac8158bc04f365fc83b3e8aad9ea5b29ffeed3a6426fd32014198cfc593a8fceb45f35d4522b1a40c35d1797d583ab683453b696169f51b7cc66010ec636141d3a079e5ba1e45d4dd927396262ad604c91226f1703f4fffcb5bbb6f9dd102cbfba053159c1d697d529cd3b135fb0c45b9bfa9d7a0d21f2a999c02111de9126921401ea2433c857810c587a6e6045eb3c585048c0d1017ac1ab316e73ab14c0fae2a90b8d0885371b25d2b4a4363780b73ac28f7303096c1a7a0b447695a49acd43916c41720016ba7c28b722b1b60b3801049c9d95fa2abb11961d532dc8afd1bdda644e45c08741e4729052200b2bb830f66fe0d2b5ac4ec7cbb1e74f06ec89e8a2d2790bb46051c66477bae3dfb3e78b486a26ee6bc120ab39bf162bb0cefc18b22b388308af39ead97a9c26224934d0805d5f0e4c89502076a5cc2b0cfa586823223dc2465f8fa946104fd35012432cf5a954253ee24d33d0711048d520d4d6049e1a2ef952ea5a45e892ae556561592fbc037569b56d9161bcef7855df6c4b61df9df42189b7337e8559b03bd0057a0271ba6cba36a93338d3a74df074b56c919415540cdf3e14ca306ec593b374ffdd54ec5c7b43081ff93ebf877df74d8c93951013b32a31036e3a2b2ca3ab313248ebeea7c63d03bddc7ac1b004026961da722a6ddae8f1385c6b0b070d2a728c6fc378cede984b2dc75521dad85f6e4f5e8ffeb854ab2ff2b185bae7fc034cf039c3be08c8e4a82eac1e776471daac51d3017147252512810a1c643f71a5fb170c7ab15ddcdcd7effa49e9fb51be624da65385ea8829016d97f2e32b833ca639f7b65a4913c85f51bc099e605006102d52c9a3318e997dd8c0d703d51f0dd0ac5204ffdf0af1cd506690552be501dc67d4f93b2b04c5a7b41852944773eb0dd368cfdc5348ac25807ce2ff6c369be85fbc80c34cefacd046055e8024b04b866d8c13512f0a32927d4ee1418715ee16fa271afebe484ae13cbc54b08c194a7f59672f097a54073edc26ad506df819494a3e2b8412bb553b430aee57ec5af7af3898b936054867a3b8858592b22edcd015f8c6e82789b3de3b43476aeb18a271006e55aa7bf9fade88ab41038d8d78501fdf474e9eeb6d8d4bfa7efe7c8378a33031b1911674935976e5975935b4894da051e38b239395f69d161dd13d9a2f20151f1a74c369243093e527b348cf6844a3d70bc7a7b5d4e4a1fed3fe05afc417bd1f7a69b955a087508e06495cc39e0052f90fd0e7ce08d1ad17cf47875f12accbe1c5437d32d914e4f5a00dfe4037c966b697387820e658392ab4fef9a4f16a7ce96c26c8a2653fa6c0c6dda5e9a9737cb01be70e99f1b04fd8501eec86a30165049082f9c7c0d2471f47af1b0f993543bdc3819bae2efe30b02e62cb4e808ca022696c85f3531d5bd869fc2d29e77415bc623026aaff0a590435b186a557ea26cf2325c4b78f381f8b3d9efcf900fb59a7d1a27f2461130ab30a651a3a80a3b75fe03ed2ccaed5ad089ad9b30a4fa8347e5aba26de02d86f6d78615e97079d8ee54b64ecd23f5d1dc899b3788a8ccdff2ba77600806c231051c16c0d8a4bdde4da2ff34ce6581887600665aae4a275b2d6a73b72f5fe71ef7a3c8479ee0964df412bc1d9cf1c51153371acad1a66cd75bfa0da9b787a10df89453e350a0bb6a5db94cc040e5ee878ee05c2e79620d0a7308472ecef9d695403c8a6ad6e7475aa1e1c3575ab6c2a058b080f3408831c5b7a748c2a6d38e82c2fa8119ebfd09722fcee42451d27a7989d84673e0ad119387425206fb536a1b40aa854a5f8ce70b453fdac63b49a855586b646720e29f7999bc65de20da89a7c4e33f0aa0c8d35bfbc96bdab180e55d8ee1445c0395f6dc3282244573acbb29b06abf19d13a01485aa07fc1d90b3e6256e75c91d77fe950f207dfc7841ffb261df8e8aa35ee38cc642cbdb1c6f4ca18a5085a81192fa4fddc857d2d24ecae4e8107392d8cef006900f67eda7200a0c01a1cee45ea0cc93d81b53e5159dcb87e7576daa90569297c73d4a75132871611c399adbed987383e9f45712f8f0b026d8241c0c810546fa81397449b3e930bf2c604d16fdab584b4a01062ab3b7e7d80d0d69dd6dc07c9255650666083d57aa8b99ae2be43641f6ec6d0371e6a65c6bae641ef43e228e6bc010d171cbae9a951237b17b75e2851777cf8ce40a18c0abc114dde6733b9ed4e15eaa6a7fa65f5872f97909986c887cbd7b8b21df66b5b76b5c11a9d79d572127d9f77b87c589be1234d00932d91e05f36a87f5f6b105001b83a2d3f9f2ca6697a4798aa0bffcdad22f553c2b71ed186a249fd77df788b51bd1da5bce6591110fa5ad953dd24596c7a111b044d7150d27755f0935145e239113e7c71304600004d519da8",
"spend_index": [
0,
1,
2308355850,
4294967295
],
"result": [
"241962a137765351217d9ef8c911be846612adf3f60c4e6abe9e516f9368efa4",
"902f0a031bc46def0bb073cf755834f92bd3cc883e79a3081d5f1499058d2945",
"fc9b00664a458bcc4e9d3c915f076f6fda75e00bf928bcacf7f1970d8f236068",
"914a0b3690fd8c9e420babebd7f72782bcadd114292b323871e9c909039a046f"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 2,
"Witness": true,
"Version": 512812821,
"scriptSigs": false
},
"hex_tx": "15e7901e0001024a0793a800000000000000000000000000000000000000000000000000000000e46dfcf20003395607149b029e0000000000000000000000000000000000000000000000000000000070a5d5fa00352252f8023ad76c595589ba51c8def3f6fa9b8e0fc3116656d3059d39b7bd8de921d39fa1fd4bb67d447eb67325b5790855dfcdba5d4bc505ff9e793422a619d4561c30313625fb687f6e66ae2d8cd9f79f9232a660db6e4235973e74a0c71d6762709f55255a9771abecdf909a0bbec7ac4dce3e30116e2b0597f56a2749237ae4be0c7264d1d7e2519e799d4147e1056cc9ff602bb174e576dfa07922a33bcce25ad81528004776abe7601891a8133cbc67513b74d4ee4ca8f2a8b8f474ea5a081d62f40b29a385884633e500455b2fa0a445b3afeb390ac9ccbd0b6fc869ad7a66189972db43728f269ee1f60c08fcb15dcc77c95595598f09c187d53586a2342e1c2296988a4ecc0e7bc9899de252a960a8e0f0f6d0cd3e4dd64d63fc80a7dcd2c218786496b42f5cb9b06cc42f0dc9fe99656b83e0e1851446d481864e3d5ad0c4f9a506e58be09ef02c5152c80497d7656b5b878ea523d58dbdbbf526001279d339cd868b1386560c9b3caf22f09037d6e3005c0e0f89850b11e71253e6d69b5a9f8157bf5c6ebe32ddbb7f3592c2fc4dc2cec13670faac1516f1f61f9b83f97fa634b701fd2901af28d0d6af102ccb678e7091497ff5df19db99f80545e839597da96f2d45d0044c09fe069bc9d6b3187a4b566fd7adb1194d7a1a38dcd310e1abbed51a0393bfc4cbd2f2f50fef07b684bd6724d974c9ef13622b8c92a37c78c4c73c991f041daed55c6b579779233937cbf07c8c71af8e467079a91cc8eebdeba802ced5c3f07d8c5bd49a1ed9b7060032e2b8344d8d11b1ef57702bf61a3a0a90c0051c55e1002531ad86cbbfa73dd029fb0a378c452e5979059400b5a254e73585c46073ba570cddab3c945186183b69993cdad1efe8c8c5b6e0f5495ac446185a669afa53466c3cec852703ee14530d493104aa2cd46d28347789a64321bda4869d77f42a72b213c9d8bc478f41f7b826f98180b5d3d0bf5a0138961adbee8de726a18652b90693afa5e70e330e015f4715c2700eec9759586d17bfe29115ed0b4f1d985b55fc70433ce410ddddbbe851f7b9ab0a700c881eddd74fd9b535debf7044ab164876ac2b0752da7f798c6b5a906b814ea3a87354b1bca9d57e864caf4cb4e05a957e09b825ae1456a9e9607b49e6",
"spend_index": [
0,
1,
2378452061,
4294967295
],
"result": [
"f3e2c3e73cee226c724bcfeafe2e180f662a29f7b2e546aad385f4464aa90075",
"4baea604d850efc9d770ef491e5c32b0eeb260c1f869c91c3f9ea955db773cde",
"eab6991e813e0da4acd7ee0b43034b85111c9525fde3d76e8f5a88c45c443fae",
"f775ddaa1ff9358095533c708e1fb1d4b59a62c4a4408f8da20a8c1e35474f3f"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 4,
"Witness": true,
"Version": -34418595,
"scriptSigs": true
},
"hex_tx": "5dd0f2fd000105dea0b0b400000000000000000000000000000000000000000000000000000000d7b8be27aa0467d1c01b3e20179df275af2b2be933d594b3f1ee3012b531f19fba4b8206c2c4831f55cbc3056ded051abdb0951bb3bf86434780a6641286ed94c0fe40b0bfe008644bdf90526e0acfd68ea6dba7157712a29e9333aac123338f5c0e42d8c7e35bc1023a2c38374b251de13d77da8c6084ef2baaf0e41fcc000a2e2c2eb4ad7f0643b5905d0dbc8244cb35939068eca8fa3032e3589e88303f65bf21fe992673b1ae1df292b397bf0db1eacfa09d65cc0000000000000000000000000000000000000000000000000000000000631b7567fd75011fb4b9126b828c61a96b5fb508b52800529ecfbae4d802020d68194fa39bfa732e996d430004f87c18ac56575f6bb65f50cec46a7c545719d4c52aa4e7bc9ae5c97b1abe8d8f4934d846b5ba81f8a1ddf643bca6f695f8eafbdd1f844fe03ce4ac8aafdba6433895f7af87f297c1e75892f48e44bfbbe69874379ed157ea5e4ac63a21b6f5d054a44273f3ebbe4d8ffc69883cf7cbb70d3cc91a60660e6dbef32068b3ef11c09824d4b6502da46f3c0e26d48a6df4c94209729691dbd3a42fccba99755f076301cd3855cd2f5944fa43536c56935a4681a6437a6ae7816752986e280b215fbd37a020c1f1486cc217b89a60d71f9b92c79e7a254711f70190dde6465b2d9b7b513988af7d982afb5ecfac13eaf75a7207121e4445b7453347761d44d5d8f351519a0a36c9b3a54f8ea8df077c3e1c49ce6d382e45f8b7fb99832cc531727d6e22ea4c47cdbba7b4621e00bb7095d23417fb0a26f9126ff5d15dd1c9ac15f00bd92739d86f9e2585abe9d2b9f6b45ae79f4a27b323dc1b000000000000000000000000000000000000000000000000000000002bc0d170fd5001bf3b7ae454bd083802e76cff30780326bdc6315708705027731894c62789c6ed32e6b63a2ee135e0da4790f3dd6e314c1f422db3d62c34a40c3c92b8e9434782e01f6550bd48e63de7f410bfe49264e8dabebd9022a9870b99f1c9409724388896e14de887a475a1fd2e6f8f44a9df2b5383a3b771d5ecc8a912f2f6ac8991fbf70ee0a3e9730d93bb65ac9eba4ede14f10aaf5334fb3a8bebf5d749168d2b3505aa629a32f09085ae05662e3be6b40ca9692b6c298febd38185e3fa40ac227a2687687f99324f5af277f5b8b6aced53036fd6db237ff1940360c2a6a6390f30c230d0071124ecf0021058b3743c3ce19bee9479dbb3b93af8573a05d6f470798c967b741c77215d1804b45c85961b3da943a6716c0f2d26e92998d848a94e04c77896d39e38ddf4192e0205683d1a15b20361302099c36e04325073459e9e10741dba07b5b8a1d441e667cbc4a8cbff1eb456f1ba401bd000000000000000000000000000000000000000000000000000000000118e4304fd0001a0492948a31ca464437f8b51dd653e5a8d27b3a3cae80ce3a237b0b08664120a8d0054f7284c27e2e09ee5f29f2098d83a1974e07867446f436446c99381a2f8b671e2836c64ab761dc907f4fd6a6031cd9e8deed2103ef187e94a3e52e6fe8584dd0a1fabfe13d164d2969172029336bb9117cba93fb531d0a6149ede0a1c230c389e71b1a0e3d4210d57abb36dd43245c8938a413d6849dfbfcb23518aea00eccf19bc491043684094ba550ca3571ac254d951ee7fc9189bbf64c4e05389326110de944837cb6016682aa23becc69e523418600f2fe4df6f1a84c5dd836032aa8e18b15f2603aac0f243a4768a8a53901dd9027985a6b14077f036712b13b1a61f44fb31eca4d0000000000000000000000000000000000000000000000000000000003b2e502c00ff64cd4c04673bb7df80bf5560c8d0b6f3d54862ae8092b5897be0c7cbbe4cbf1ce9fc0748f41108429cd61f8758bd1ddf191f967200d5c381e6a4acb3cf174dda433be118f9c5a4cde60970b7645a2b1cbe9db9b25980c5f80583d79f3a13bcb05adf6fc22dbc5e005cf57190b75230146f43e78653c41d0206abb9119c1c4f54943e161204cf71088176778286d9827a438f322c86581c3a6db004e1b5bcedfe48fd1a8da4442284a44c5cfb436b624c008e95633c4d36220f0959f31c037cd2ec3e70c70e1dc82779ccd2cfcff99fc40cb26451aac681606667757255c8ee0950071f736d4957b49d3e03b3ab6a65e136cf117bbb081d7678a4465e66a5c3fcdbcad3fe98d32d21c68c97400190ba19320e0f8154bb9a9d98b577973cb2b97f83a26f4f86ff82634c544d9854da78508a158ef6937a7a1bb80081365e7e18005c786a84bc69028aaef5cbc0f7b0a3af1aaef8c296e1e246f4e46c15780f51fe90d85e02db41ecd99e4c4b17950998f9d498552f006409c67d475627adda71ee723e1b9bc7d31a08c609ac8199cd2797d0f71134fec05c4518cbedeca0438fbb4374c57580218a0f50daa487bc2dc80bb9c1eb6c80bce8a9cef47409d6e3452b06c34901b1bc4f804abb3b4f0be46ea6514649696dbbbc481f949e688c81ae5317f70d3fe56166784b124714a1c4dc07a1202478c9ebadfee8a00e8e0891a954ee20d284838b5b8c3b26759a752704912bda1815748492dd7f706448cc744a89206fedacf7ef1b447a89a62f2cc944694d2e11513cceea6c66f973c320a6deeeeb85322113f45cba56eedd5acd67596d2e68c26ccb3073b896ce0f51b068b061b29bc9bdd1af51e967de89654884060b5c79ea98464ea137dbdf33a8223e7cc89dcb64ec22aea7e3ba608cdf4a0384351ae4da6b53dc1a6f8b1a1e15b27c8badb706540299c41a6bdd45a568519bc794d169a4008123da165c0eb7b40cf8bf96b1a3f9c025d73da7711b450ea122f480895a66552be9bd8832dd6f4e90676f5ff8da0735b2fd2a04954422c93fe2f25654b353951be53ee09378e1c0c9e157a126b727da271ed2fe66c5f00ab2c073494e0856eb6d2467fb4dfadaf1cea808a0fb6305ae498d1f935482acb505e369f81a6d0832fdfdef02a18df3b753668ec450835e7a90c7c45b03e293eb0f3fee544af59b1e641e588de3c7f44c03a15ed347d45dfc9045ebaa72859eb6a2195db9d6c8784941df9086ab7744571552dcd4bd1a401ba0db2a89d69ca1c0338597fc7fb4723f6e001729f65306a7a96214a4cb3a78c4071221d8fe75d6544d63bfb34c6f6555399f5be39945ddaf7898537f79b73b51b2e6378de128223a99ebe3784606150134f8c1d2c06c274ffde7a3e0dd53088160a7868332d628e319577699738a9303d71c552603b78478400daa3399d7024ce23a910857da0da88d0b43ed425b8adb81f478ebca71c9c1aad7483a2605df1f38a61bf627f66b81e914f02d66fe31df7fa86e7e5f0871214c4fbfe12e60b9eeb9651a84403ee77b326df29ecfe15af0cf8ea6b4efa286373d95c5dd33d7f9dc5dab83382a10545e4309af493ec64b2493db4ad7fd38d6e7e4a47a15cc775bf3bc473bd23730809aa8f6b2432537b19d60379e64baef1975e763b41c2e8e2b1bc333e07380703410ec08c907af0913e1e1f6dfb3ff95d1ccab1e00d0f97cf04532faeb62b8aad7df53fe0d03bc21d9718f1c0e57203b789f49182c50199b6a4919683c4e6974b7e0c09cf3112f483991a5622653b2852de7546e81078b54c104065443c33a76c09e95c1dc1617b97249020cfd2e01a02a27775cd019c4d21eebccf3738d066749a4cb2b6fc08347f7758d9e3a9c7ae3a6e12b963cf83b1fd672c129719211c3fc7a8f2ba62f1adc20cf4b18c53423f002d5f59cd3bd723eb49a2372aaa32a9cf8f12220c8ccd090dd85f9813862306e5a21e47392832fb6cd969ccabcd940e8891500e8f576c235bfba2df8f7b7b089a77e9eaba55f0ef696f7db6d5cde3be41a7a9c72053db92f57b29eaa77724b2525b6255c833e668fee16af35a57cc0da04070d63f2ce39bef0d42311628ab1f43ee4aca178783246182890d4c4215aa34ba506f6c941ea938b956da76a66536baeda46a86de0150b6b7862df3e3e214b00af8f1354ac5c8eb6a21c3e7619203219e698ba3e728764a1736e242a84f93062039732f3625b557fc97ebca48cc21c721de585cf5f998967e421567b04fd9a01614adde856ae46ca685ba073ce97551a4ed879c3982bb8a0c4c4c19758cc2164831a346639d34906771e573954500700c925b2f6a51298d79e789d6480d798fb7c853652937ce105d5c3a49d26934839955210780e919ef4774f96cee6980d407b0fd44b3f13b9ee4f5bd6db93de9587db2c15f0273d95a10d7840295cf4141d08f018fa727a75134929ae41fced1955f654d1bbc29469e3618bfeaf2e1745fe3925e3e1271e3940d67c96f03b21befbc20d1714dddf0c2ab5626645da21bdc47befe70ea38b4f804a9fcfa42be3120ab1ee9c94b2dbd40b651115d5f3357db7ac3cddb0b6397a6e4c86af2118674b0a284f29a95e7d2a51be7f51518550e6ba6a24634a69ff7892c00e0b605df08087c6404ff450b54158d4400989db051cb2f581e5166554cbf9480f9c26701ab4ede8339fba5eac8d41ebabdafe80bcf4aa9a4b474706a6ff39c994bf02286c6b4c1d22ea790aaaee2e5117ae58b34065c3cefe32a8d8c35fc44a52ee602bbaa28f681d04de9a824186080b078596fb0c8e1eabb7c01cf5f8ac9281c4c2a9bf5242f72cafda2c807788c702fdf301d976807e557699b6504139779edeac170108ea49bdd01365da1f0dd02ad17bad83ad390a598af18a5742eec870192009541cc4c740ce87f434c853fed03530ffa2c0fe254091469cad1ad0d3bf64485ba651f8f3395d75394a6b6e3d18a7b349869c68296154dbfb63adcf5a78d4e5ba7fe5fd04b7f3e8df84dbcd1ebe242d93e95a91a628410f42a1da12890ca5724e9d02a290ef2b4a132173f7961eba3653889e9a77c231291c34504a2b41f4eba0dcd7be74c8cf01101bf8edbf1d35a3cbbb964ec39b6c450b662aa056310397518737d28bd7b8f2ea919bfb1191df5bd7b7debda7789b51fb106fe52ef13a1199021407615d04c6e5ec748f930d24abe34e056cbbfe3d0644923cb114325207a72db54fd1da854d13330b58994ec176f0a22295893976258cf18b267ab3f0901783ccef446a50d8b1d579e5a9a2230d774c859bca4beca090a8a80f633833f82545acf797756e171337b9dfc938a4ebe6555bf3eacd84c3735e9b5b1fbaf4ed99d2d689ec0215ea5d9789a25d1a3d59473f9a3abd1aaf652bb5439c98331383cc0fe88ad63ac15d38ba5de539dddff619490ea1835503dd292a3f5d6439de6920c9f5b2e6cfcfa29beddd6f2725dd51e0f454ece859f783db160effcea252e14f6c5c05653e5b5425cd66643afef1df2bce5da42d1a2a68bb57fa1f9e11cbb2a8a89a96a4b6f22a0f93b417e0f211a77343a385378534923a783820d6f0df5513e0d3d25631fa3a827d3b2386a861f03d6589991c5104360511b5fa70ff8ed3af7621eb33a0e164d26a91c4833b2671c09db0da7c6485ba895601fed6b5a12379db12a4b85380fe047ab5bbae82c1c95810fd2bcc0669846b173824ac5df7b032f4fdff539939f9be2bb4be31c61dde7fabd7527178eee36cde414eb21b1df81ce8df8012388b7a08fd7101655a6d4bb9beb590b9055a7a39ac3980d19e8d0508f17fafc121ddc590971577988389f980b6794514f6d376276ecc41de2d1d22550596f044e1e094f32b5928bc045072b62547c5715ec3f5d3de18ef8a28232b98653e3a170154e90307b0f672cc23c678c4346cf270c4c31f1be14980b013a8fabb17570b18dddef48d28ddbaea98ff2421bef9ad0ef3b0b63265a65dfef5ee7bdce736fa61306ce38c969071983d5a7c0a7930e1c0776a52bae2caa03939e322ecef0fcf10e2edd26c92178fcbcac25db90bb33ac0f9ded141c753e46ef02876d50548cc3bcd03dae3ef6e5139df0e95b38c2ebe69751ff2b87e098903cd9921348bf7db8408b7a4e3989f3714a1bb4d88dba4dcf868813db4fb367f3c89bcd7131fc857b2fe7b745dce2b334a27e85d329aa0ba0ec710f6786e1341b7cecfcb0feaef3f974edc80f45bd08a8c1c23a6dc28f59390696f4baeeff9b4fb11ada633dcfd7fd2d00e7f2a8b09eaa2695b66e91e9e015be81cbaddcd5fae04fdea01957892707e0dd5b1dcec761df13fc5689d4a3a1c88c4a532aee371f11373257bc0e5340e0eec96e3c9ea5838da777edbccf467f043bec8d5206511511bfb9894a2fd731dfd5865b0db1f44577000da3a138eae24b5f9f8cbd0f68b88c22f8163ac44ff4bf60358d91cb985b90342316b372696a993cfe91d7cda2f3d1e86c9dec095ca4c2d85e5ff3fbeffb0ab82f0412980175a46b5a7acf773868762d61a614991cefd7d066aeba33d5e2f980912b3fb7d6a609757beeb5a6c2b8690a21449796103d21d20722312e75aaaa02d0b78f2a61147f853c28a7eccab5908c0578d0837d4f72720eb67d0fa9b26fd614ce56f69f574aa5c21d63de4d18384c0812c94b4d4d31d4f7262166bb8b602e400d4ce7d97505f44b0cc387c913e76cfd07c4d301a5f9a9c8491f3094e72e96cb682b914f767a83994f329e45b101a3a09446d8d6eccadb46d2bbadc5520cb0b8daba7c147ca18b65183da689dad812d1e3a19b853129de72d0937f95163ecfc32d5d0dfe99d9b9b5a70883c80db0a15caeb7990d58942391b4e516410e4436eae55b7b21c982c61413e5c14f3fb674fcc78c5997f0d84f962d597784d4d5727dd67031a80b6cc6535a9179040a0b4cec004a82bb0301589f22f158cbcd696eee7620679a5dee4c7b1fb19f94088d563bae0cf3c91cc8ce4cd7cd3ba654220a8125a46d72481a80298792386c1358973672a8fa065ac8a9db4c12a11d50995f69cfe5d09c4b7b1aab94d176c6f1fc6fa4c8d7213dd9c480ec3c485939d0cb623aa615849e2b5098fe561a4dfdf72dcfedfd93b2eb83f597242a707b52543c74f24c5fde9012aefece7564f60f70653e47a8afb3dfeb5e59d917b10be274ab0679da1d0efb01bca06e7467d59b759b9097deb74d92a3fda1e344855f09cd781c34ae1678201e45128d3f61c4cbcfa7a6b0b73961e65c8d7d7d6135d7eab3d9887d153a1866a62fe31063ccae983615d585853825d9b699325f167f150afe9f180182efb7fefd203beb9912812f787b73732791128f2b989e6a0a97d8b16c0caac0deeec65aa3c67efada1e3ea75a72baf5433e8e306e1c21d6c88556d23e4439d25aae69355aec9c990bf4b3d6763dfec018fa206b82ef2a42acc7cdab33da1977053dc6461901b8f4c6751f949e9a5bd38ad97ec95a2907c879226b0d7259dd9a215c092633a85d97034efde15a55c671b3439831a0a364601fc636d81c0c8cc8472fe916d47138577e373d2407527ff4b969cc24505da541a17adf94c1c87d21a6f3e96192fa1148561297c8d7046a88608b15549c0049512622983fbff9c605fd61d0ac016b124315e6303963ad5068283ece43573a27a31b5a76e227230801cb9c1d313d1c512e6d9c8422b367708818e6de2606540c3427921eaa51a15035e5b2c0d468bfbbdb11ebafeffd5f9f71e6cf78d4b24f6c82d8cbd83d81a145e666c4eda94a6fe8250cb7e76fff2669282ae0fe912fe6288eac3edd39af98ce67503d5cd159fc6cba2d1e5b8a698fd4b01ff61b99a491a17f05299167c6feb67f18c2832fe3265719cbc746e4ee8e81a7b41926bf00bf2cd53c50b55f332e19f957af790c83cdddbf46679e9b0c5ee2b3edc15ee209954e968bdf1d89ffb00332552de9a0c9ba40bebdeb96dad7d259dd833d76db01cad7644d661063bd8acc07135a829b91193fe9cf57e19d5694d89a976ed58dd81e5468dc44172ce77ca5383984f63a2e01cfb03069909510b604fea16df0f85e9ae6fb5253fa26bf95d8c362e3f5a8a63f89b89a4f343c08a49a626177c330af5e6dd57efde3b8a48b79a510df3f884fa74f5b0c567ac044ee3549c204f7cbda420d326eb408d3463a0beaf65a43c7c463cd6a5410632e0b00b483fc24f005e9abdb38e2292f08bcf55679e9e2e249aff0829c85bdb15386ffc98bcf62872f8da83d5a998de9d0d5c415b8f628ced24f3c6d4b35f4e01de471eb6ed449900de544dad8450b6930001fdf301f19627e2e6ba4611cd1160cd88212ade6eb28e59ddb0006797e189c7dc0ec2a532fe25f9b94fc5a7499cee0c17df82e13b5feca55e7d2906b21f72f10bbb38d846cbd3e546a7c0e8deda3ab0cb7e66c4c4ca17c2c94bac37b0df07adf949709a84c053eb30e67a2fe40a68e7195431dd7b05f78442652d219dc6e24aa3812e25829b5243b4cef9ca45d17d125f2ac2ccf9d1a48f65e1e116bb0f3bc94687d7b7722edd8db62fe28def0eb98918bdb4adda6954f62bd0ad3171f775f34a083a987c2e155633b6b5e1c2aad0c7983cba44879f024ea1c9518fd0a87182cf6bf2cbc2998f9d44446a0c20b640cab5027e70cf3a2824f217c9bdf5646b62286ffbf3bc97862a997fd105682085b7e6dc5a9059a060449e323719fe2961513ffbe08cf7dc043fbd1d1379839d7af98114b2c8d4841f00091a3aea14198e12d2eb551c049138e8a90f9298e22f4fcfc205460adf412228814288e47e54ecb30bd4bb82ec50d04dded7755888343fad7e0e105711ea1be72cf304f592fc4d5269dfeb4599d10a5ad38413cd9e522b5cd2fc139a59dddad0a95bbb6e41ad759aeafd9301e06e551bca8eb12985cb65a7df8a279ca6571a7e3598fe4823c7fcba8fe50e42f4f9723e678cc9ac04fd6086939b1b438c188bb3e9e716e6b66b3b1b1196aad184ea9dc926b26d5b654cb6363c5d8123cf5991546fe711",
"spend_index": [
0,
1,
1543102608,
4294967295
],
"result": [
"5b2b6e29a48f11326cad1fc011abeee3774099b11784271eaccc608924846a64",
"b9ae761287f0265fa9c7ec44ad48613bfaa37d60ab947f7221319b40359bf38c",
"6b37a42dfdd073178aaf1edff909c6fd6480841fa506127c46bd89b5f45d2d00",
"32b1edbd1a8238185d53ff008f0cba145afd7ee4361191ee9dbe4a72ec5cb56d"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 4,
"Witness": true,
"Version": 93911642,
"scriptSigs": false
},
"hex_tx": "5afa9805000105e269c23f00000000000000000000000000000000000000000000000000000000ccb851b3003ea045578f9bb2ab0000000000000000000000000000000000000000000000000000000036af826a005f3048a22f7bea790000000000000000000000000000000000000000000000000000000062d6b1bc00100e8501cad609ab000000000000000000000000000000000000000000000000000000001bbfd9b90074538b74935bf13e00000000000000000000000000000000000000000000000000000000e49985d400b3f878a004504771dfe41d9601c86ae4ccb7cfb7170446c8d7bc7142c0a69726e6f4f9f06c296bf0046dabe419538b539ca518332da907925bcc504a40c2bde6d685bed6013f46eb7419a4ba2528e4160396ada59aba43dac62ff7aa7be8cbd88451fdd2bd461bdf48d220065db522399cd7e0e9d74a60a2fb2df85ea8669f5642f00c9d916689aff0cafe0839209a5d9921f332178a31bc13ba7d25f35b36f1754bf35809a1a724e21f34e2d630ae8d3331b59963e18ff39208aae9d1e03908dc28e10e29c0f7199701d9adf990955ee722429611a408dc6ba1e46f2a14c80eb28e7d1b6dac273d9b34d6223c39e27fa92dd0b8cb032f9dab9081aaf84be41e51f43ebef13312c5765fce0b2aa69da06fb557c2ef30cc1b0325c73c91aaaa9137e46f5b70a857aadc94569480bb08a2ae7a1edbad52e5c2ab4a78d6904481dd661864e8d4b0a95cf41aaa52d952ac6bcdab61883a4ff31d31166ed91716ea0589982f0393c3ec484d9ccc714feac5038ac6a19bd38f0239bffa61b73074ee8ad53576ba9411e2cbac7c5bee4e7e02d9fffc8123e2446627888949f09df9ccc831ba1892f2cd2db67412f14920cb61c86aee7a7441dc81daba76e6f0ee845f044c349184a4f8a2fd88d4f8654c35ae3795f03e581653ee61a0a02b9e7148b48a39faa2c9f7330f77d56c4fa36974aa5d8e1be5c3868dfbdaae17ebb6b3cde463c2af6ace5dc7018b5d131bfeb359477e0a5b6b31200568ca848ebec938bb931aabc8ee98c926c9b5e444c1ef84e3eb9786479f0144c46c7b155007256e0702ce07f1d74fe6c9aec817d34ce162ab03bbed13e03c8368ee6b25b42a295412d94c1b6dfdce8a4afb0c56f1126a3c9cab1d94e7a7916aac0a896813e3d2edf41245c8ac7cf83beee8a6c7abf3a179a62ab5f8fd89a05653052d0e3ee3e1b71dddefc8ec41b4bff07038943d5c0d9fef44a56d2ad7878c9d48a05e61d5ce5d619fd2a267e8a21d5bc88ca910c19c272ff5468835fcf10d866191a95095c9a14985903fd9e761a8a18fccfecaa0fe9182b0abc84ab4b355d22b47e49333f4d8ce8021eecc07cf84b27bfd0255c1c68b76d646de5a9c7da90d17386532e7a592d62713386154b5333a7ea6ff3ca08cebd203d125a0d42471eed75babd4e194f763bf19fdc5df9373eb00480a033521035e94c36c0a13a0d3a2316ea4261fb4bf3a34dc2f2139fdce8822b088943f4f8130b16a1f727ce9a2c179a877770b315e9ab587fdd501fa396128de67602e34d9a1334abfa3aae0e3eec17e123a98f26bb0b7e24823166459ce44b1f654ba4e7c45c0cb60aa4bdff01adf81a3d56b04988fc48760d676ddd3899d4f56827562252f939951f658b05c9cad596af9f17d75d58a2d5f1a34c60402757566353bfb45c6bb31582d07f411b6ec725a6ed47fda76be854ffe12a604ef251b5697d545f4a3fae379e2dda1a9e296d7204bddaf801b6069eeacb02d744b1406342821c164dd8b1edce60111160a08a85ace46d8bf6c5759473b3503b029b9eb0349cf56ccec33355729915f39b17a62f75781f586aa18b1036ca53c34804a3fa2ae5de9ad699fb9507381f7d0aa78a4cfd637394a7e6d6da6ef5bf03e1a7fd4ac1eb848e563d50b03fec50e82db44729a4e0564140552623f84dbc64e59f70fa37cbfb0f1430ecd2a3a730edfad8c3aaa11d97256e48c845de4a696f4be2d8ad0d513588defc78145e5394e20e78aaffe1443c2b7778a281fee4ea351aa6cb304149c7c776849e46bc0937388fa22e6d09e03f69d4e9441c67acd816557da4b61029c132b4b90a38e714ba0111c0c6296f7c8ca1a93cdf62e15ccc7d8a572aa5ce40a5e1c4f927ee4cb1096bff11d031a01c37ce0129c9a53eed44b6bf2d509142e512d429701b2fe83838a149359e8fd9301f3c6766880deda87f1997feb38d28c3c097077b5e5eb9743e6e36b9a04cba38c5095665ca77c3785cc4b682c62006b8c192d696a6961423770a79446669d9b87dbc6f3fb299369e7d3886283fad9a338126dad2826e1a3db01ab27d0dc6554111618f94970583acb30de6a37c38c34dd19c86d4f42a0947f01989be98e8d5d3fc533367d394076f02155803ca7bb8b654ec7badba872b747a043a3ee2391dd1d0147a56130bef21366048570022ff120441dd753392a10d4fa83cff9501346bdc815b4ee57ed8c08f04195857727763db23fe9a4e2212c3358143122691a98fe48e7744edcfe24a3183b4bd1fa3f20fcf880ebc9c942013d741078e29195f063777542ccaeb9737bb4a5ca1f6c7fe137b20dda3c292b4332140ce4892ff2c8c2060c932e7ec1864a4e1709201ec364055cae57ad9f47b69667c564998e89378cc2dc09369e9a9221a4975314b5a79e9709aadeb39af5344081659a73a03176c72ea9e42cfb60e16c904e474ceb5aa92959f2d5b75950217c9df9045aabddc2a1b0b0d21cba4d3d372805cf7a5e1a939a98f77101fdce01bad33e99f5b7beeef3c4833bc10ea933feb47782bd340b3cf6d3c21bf590415bc51530b7e132d661d9d7dcd6af66612d9b4157cc9023149a2fb948cfcd0ec74a5ca914f5dafa335984ca628f17bb46855ccdccdd058c611e9b6d926c6063f326a00bafe8cecfad1fdd2d42bb125e6c4e6bae218dcff59d33db4dd97c73e7e2179487fc04ff5c84886c645056495e64957aee87202c23c5e8228466291294dc6fd231b71c667bb83209b054e7eec4fd1091cf27698d7c45f7c4b5f57f6eb5378b4f85e051dcd800a71b69d0901b59efcef0036615bc1d2041cad428c4210c1108d2d616c94b3a34c950952e40a8cf6543c4b083cab9186e921317530d13efd18fcbef67448103bfb76674338d72269bff3977b5a65dc5f65455db12ceca39ec4019da9726e959fee6fd8a6ae79c76fe0583e54ba349b378e37436a0f66ffd09760caf056ef37e5fc4c1d86f64cb964cffea5c58b6bd2c019d4bdf7ac0658877e6f8cdbc2a48650b9857fbf1bed33f77ee9b8b3d7af95425db12b7f9ff35181a4425958313722c1a75a86feef228ee2649abbdc3e643179b212d14c381fcb29883e179e8e41826e06af3faa9fb13aa6b647f9ef16ccb6a734a536fcee05b881bfe35113291922f2e87f3ba6e4b76a0023aad951851d10807c12089223cf326736357ba6b28dbaee80b1a45d1b50a149c2627d37da01cc740ace6f287cd114b4720a7acadfb64c3fdc50645fdd1018db5d8b39f86de6e35d42fca912d865eaad758e6dcfa45ec03578424aaa39e998fe11ae3f2684be3fc2cc0d6dc4753f3e3661bae67f3fcd6b1812716f207edd2803c5a9ab742e062dafa9d31704175873cc24e2a1c6248f3b62e5b234a11a0de984d64c47557d866b006bac7793fbcd62d8fc6f0a007a70bf8ec9c82228906a9e42ef23634454ef7c0171cdbef163a98c6a748d669db1c3097c703a4119ac4a38c2279f1406a134660967ddf88be127f7c0f8f777914d12967c9e1ebd0597efcf415652cf19a04b889dcbb4551d47b225a36c082654de9f7687a5ddb8ec614c0ec204c4f58c9c969a2195b97eb97f2b4376dce0d0d3ab0d7ea5f82324ca45fb82b488a2920dbc408589150acf31f5cf7afa6ae6c9691e828ea391670582ce68e05bd2043be3b1774710188c7ec657c799f6e4c782ef995c23cdded2cc438679e580133d438cabde6a7f00462a7cfc8600f516d39910c616e495d1c93794c6c1bba2594f325c1c3d8e94ede812cd6add68cd84846dd2e6ab8c2274a882789fbf578eccc830057d51bc900c3efb36f3bdc9b0840290c4ab1f3661e734410a56183a5a96813ae98324ee5febeb8a071209bf87c78188e753dabf641ebd692154656f9ad51d6c4f7755f673f17725768e967dc01fdae012ec92ec285a8d6e7e81bc5e6c1fe449eaa227926d57ae47ebe8ca4f27751ec5311069c2e66ea19f1b5d98bc35f35cd4e259a85ca38bf578d3620e04361bc8e44e1c5b5d6c8c5c786adf6727cd8fac29d8077feb49b402e846796cda828b06cf91e19e9f4bbf4b0365f0ba055f96ad4add4363bd290dc759fbf7c8889294d5580816a7baa01aa7e7c2d6ad71a7c8776d0c906c4dc06dbeed18f133e20c22505676446db35764cf518814dc0cdb9fa2756e44f9e25598a3792882c7281da949315b1f651e9f615867b6c516c5942a4e147ba2e0c06a21dd9fff4d1e224c8750b75544234d6d189b0c7f5fa270d0e7f35c8b736f430e0d5293898f9bb5d388fbd1cc1fef5fbe5c276b113ab8b436ebcf4ae9c6832119504ce5cd8d5b504bca91c10ec512cfe0c9b0b5da04fe9ce7a9fae1609023cfb571143bf95dff1becc292ce2d895ac19df295806c466b96944bc602be9574bf29b13e5e65d2852a1a61e75b80baf53ddeb95cdc8668ad9a28e7a2896e28e5d0231f1c7bcb1ca11bb2e0d091766ee47a0a7352cfaf4303ba2503bdb4a4e8fdcf608d38d6b29571aa8dddb7f02cede4272e29fd8f9cea210d968c503fd32015a7d38417c57ce3b1d4fdfc328ac96b67af3381e526d38e6c502b045cebea35272bda912cef033ebb8642f93de209de673feda40822d4f24edc8b79bbb29e68b989e3b0b27021039126abc5e6cf8451fa8b367fb290f4eb2917fdc27f2cd931db0f19e963bfb17303b9bed8e91164700614afc164a02e8bc3ef5583929fd9995dee226f28445eeb189b0c25ee6f8c23e52549fb7f3fb3662d89955158ce25eb6d650f58ca5b66e851d9bae53a8b3cc6f5c8bc40fe177774bbf4d0da3b17ee74f616756de54cd9c7481916e8279b9b68ed50a6083bc08ec5b4abf994839997b233e989c7d594bdb4ce15b19f4323d8b0fa750bc1711cfe2e4acedd1939a0c5e8a4ecae95fcd791b7f2a74503898a67f4b27da167d83d09c41aeb0a68404166714858899a8bc35d72e7c6ee98a6928f3a585ee8ca67b3c937b020cd49fe029ebda9e21bc57b4a29258bfb611ee44b1b217387e5d3adbb4a8c86fe1ad935e9277e762f0dd74e90f6357152e28ac243e5d2f43afa52e923ff5a9966fdbe2d4092e803644f90864206bfecb96c99fd7cbb16e6a0aa84be2a33660b869ffd470fc21764f9d8f38f26eb348eafff5ce13685b98380d1423dee4b5809ab8693d9a3dfcd70b4cc42fdf37e4abca5db00ad3cf61418a656b09e4a0c8c3fea0dd41091834f22430033f4cf1379c7ace6966eeb165e0347a9cd3aed5810d532fdd736eee8b4f4c87cee2e87530cf708262c6ad4225669dee6ce02968fb7f03c860f0f0ed946c605360bbc4e65a7cab2c134bc15bfd65d1023fa7e1f27cbd32a7147787e770bf5282a68b111c10631e1abf4381fc1211731a4c6b6bf54b3fefe4792f17e6a7d3438fa7dff58dbafaade9c34b2ac5c10c536a2f4b438eb9ee1d801433949cfb44d12ff8ed14264448b814cfd89b2cb0a39336e1558276243fea9fc3",
"spend_index": [
0,
1,
2559694887,
4294967295
],
"result": [
"96fb3611b3f78e908f7d83ad1b1c1bb715a7df79eac25c4cd26bf6b3d86ac5cf",
"6ff033d5539ae2d14bfd8fea0e0fb6a7e93cd08986b6e1e280b41355fe17e447",
"e9f5a3b36f423710c6a5129175c3833f12833f58465514a72e1248e085ae2537",
"e256c842b390333db3bce1ffaf711d4da880566e07d174797c25ab5a4224784f"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 6,
"Witness": true,
"Version": -2006323668,
"scriptSigs": true
},
"hex_tx": "2cee6988000101e90702690000000000000000000000000000000000000000000000000000000088d88eb3fd430138ed6055729b96a415fc37d0c94dbb2dabd050a388700764d5d5018466a45455ac5bc5173ccc9300ba1b4ec66e713b27dd9eb7055465dced488ab83dfc762a9871338e0eb2ebc2cef93de3626e52ad88db0774afb632e51b71bdab859dbc740887e1a9d3fdce12cb18854505db1bf7f4ee153f21acfa6c305c421893374908263fb3e7c6f5297b36b8a7684d2ac49196d32e9dd484eafb6f45d02ed13d5d30b2c48b03c0658ea25af364447dbf7c2c76f28f650f220d2f859d2279416d2661434b75b834b5bd09829ce8748dd6b7233f30d5cb064fdc420fe48217669ef48160586a19ecc3ad97d6e9de4f5f80c9aec4b60d10fcfbb08778f69a978c3768a5c3771b82960c733cbcf6b09eee9e793a5c9eea0c57cff7157e0232c26719a9045697fd9f25d81f9b31d803fcc9857e57ad9e55cca9f71204ba39d651a796a8737e7711eb0bef9fc90657c472509a7d4531c81328efeae5f22623e3aada3a7b6eec583b25f88c219f51168c59b1836824155ab2c159b3c97237a9ae12351db57fb562dd838ad79fe49ffccc55aa2031398a903dad86b0feaaf3f412e7031ca99b29a1d9bae48be733f54259eb121ab374c79e4fcc7c39bdacaf8104b555edaa420dc28b4fe802e10f364e62232f0150b209b5d2482a8971bd4e422440f77658e77535e77a8d0f51a6303e5650115bf02afbe0e620aa148b00e37db3514763a854eb2bacc8379572a0b9aaa8f77d1ac80be0e192fbc9310bbb3c852b01f593fed5fc1dc8ed44137e8d50f34fc88f4de5026fc9ad62c7ad7b92460fa74eba35071f3e93173df1d66ada44dedfdef4bbda06b746b7169b2682e5e556f9781a87c5d878b9ac6b79009f10d6af63f85c3c6e88d2b96408751ca1d5de40f5de149c362528b6deff838052dc627189ff5a9626f795e2f7c0b99927fa1c714e7150390ca2bdf64998812576e822e02865855558d004da9e17c35daa41f998054fc529097d591dafc255bd1328f0557fd3b53dd7fb35a728f47a24cde169bba46f35fa4c162aa8b7799d5a1f857516efdf7ef5db967f263ac897089877f0f96d5846026feaacad0022ffb69d5225c66d6181e336cbee778d5f20cc161092d6c28594096bd1acece57916f6abd1941befaf44835f0e63d59ec1d9321158885738c7f0eca5a969f7ed43d593207627b6b9ce623a57b68a4fc2fb27d8291232b9ae3afb98f8f94a4d5b721632ce4dd762a9402cf8a911c46f73ed804717c4bc31b99e7c48f1d6c4b3c08fa8e54ac68676b110df189fe931e0b05943ab0edfdf3dbf2a4e649a8e3f76bad327e22eef49403719fe07ec40f5c95abaff404fc3db21baf2c7455e7bfc369e26c87ae646dbb033b2b1fa657aa3cb8352b3bf46835f44a03529e92439e3d5069141f44dd98bea9cc8234d64f0ad0b321d4c4960fc269d1dcb9135d7ebb2205f5e33ee33b6b2bb201410b3e38992a00a4f9ce5e06d065769779ec2bd47558bf9b7689fac920d0ff1b1824c1edda6d3b28ef8ae00c42f1a67531d713eab9a1bc44412c8a3cd9c521a44060133ae80b863243621bcc7217dcefcc28267c4d0698823bb61a0fec8f468a87266b57677129117da7c5e662a8140c142dc45aae2683094a033fb8c140990a28aaaf03d7a47f93410c82b2d036c2b272df21215a172010b819362ed6b220292d8d8ebf707571a022e2704350dd68eabc833a7b666c99709874a3312843321d632f047f8d411873a3019205cd749824ab6cefa0cdb5cdd537e978cec566d3e1539ac2cb35799b2c4f29b127f3d4e58deb5942353731b3c730dc86ad91b074bb27cfcccc3f5da1c78ca28dfd15e83410e23f5aa08ad4976bd478328e61534fbe3eca40c73d484e2317c596ac5e6d503314ef76a7d1845035c84683f557e59e8ec80167caadf608d7aa21e0c2434fce3f525f69253760c66536e05c8ea5153002c90a8eec3872fa5f9369881d3fd0d212fb0e3d18ce3fa726cdaafa261db618faa8aa8478a3c3f8070fe033778641bf86240df7062263142151b7dc4c662954775d83d673129dc54d4b229f4b9ea84c32b6d4b296d461126625b8639641da1da91e66f9ff08ce6d1f8980325d67ca57088e96b57a9859954a9afb39f4b6354c4ccb96ab2f72d2a744c9dba822cc3595cad1bfb685683a76adea64a472f37f1a7a998570aecebf629b60197571b6224343f60eee90e27220e08eff57172d0870e4ac72a6a03fd2b01dbb959a12d229e8fcc06a9b36214bacd96a0e06bdb208533a23dc4b90f2c7f92c0e5adc6c8901ec64d6639905c6aa38544f0b1371702f490678b6ad225a977ee7f6059fc6049c5780c99fde6837d4468f242da97a5a1f780d28f39d05e72249f6a8ced5a3ef41ad22780e1785c8988465c0e0b65bde6a873008b112f98fec76f5219845360ee6cd41c1e01458bf073513c6d09dcb7ea09d52fe2773f1dd7ed12bbf00e76bf6c96f68266d2d98181c55da440c1dd2af58fc5ce9ad78a2aed3dfb055da9ac4a8893b232b334e8963800059ae80a18bb082d69b4a50228281d36c9a22ea2488e9467de7d53eedc659e4715ea994433e4e1e858cb567211132bdf6dec0983cc5b24e41e09932333bf393ed818932e7093679804aac34a2c8e97d4bd445671c58c2c786c862e09fdc601703aa3eeefc83e891d93b698d865cb00b2e82ad852780b2ab1c0203aca2cb158c4701a0c9c29015efabe1d06ff17f52fb193c93cadeb1d1ec01a229c61aad2904338844ee7b469a2187adea212c4b4fd277ebaafa572d490bea72d2b0f27cff9075fded06c6750e3c030d5614d37d9b2b8b48811779ec1e281cbc7905c26ce112ed38d4090fa48979df1ff4d3adb5c38019127ae6e5366ead7d2fbac722f08546f82582d56a9f79407962031446250efe088bef4538e43d5586a3e92f4239d8a425e2d476c9e67f9d949517ba6eb0f603bbc78f4b36eda40a68015b7f206aabf0e05a6be5c3d63cbe07d08a89fad2edf17372aa4fc5dede966bed7947f481d6655a273e9e22d145bfbb21f7177bff75a7a5748440b1b7d848c06eaa584806c3ff5c999563924c4c5cf2512f320d4a918915139ee87cb2f77289dba349a1a3194ffbad6ba06947e0d6afbd8c419a9621653809853365c3a8ae25a7483b13a593f801d689245918fead3ab6668c4a6fbc3a2b9c0e6983c0d25700ab09384d04c58f645678f05aa2ec4ff4b153d9cc20e06e44d14706633528ca00a878aebc7ae7daddf529447b383c0ad84c925ecbaeacda6e374dffb3b20edf4e93f885741948453b78f0a32cdcfc7b01117d111be926b368cad8186ae2c3061ca912fe930615b28aac118c70bc3e611aaedde8ac79de5df508d45d9faa0b16e7c6207555cf0edf12e1b26076343003e8377d90ba1f08c1c4c35e114c0307ccb7b75d13c4bc79dbe644eb500e1e7490bbe0a2767c3fc537f184852ece9189b61cdc65f14d0cd90c9d02f4d5a7abef11de334295c6321a4d6cb8d61f8c7e5716e5725d53e1588a2bc36d33ab76d4c10afede9177bc08be113fd45e489b4ab47953aa7e8866cdb4000f3e3e640dca4aa8f7a977b647baa8d08848e1d14f8bec90526",
"spend_index": [
0,
1,
3336449762,
4294967295
],
"result": [
"35b7d911fc9f0b8597b8b0d671719a4dfd381320bd593d5d8db01af2d4e5681e",
"f283f9f2988a5ae806dc1a41450b96939fa6e9c953fb6e7398945abb8c3ad93a",
"f8bfb30a4d452ff4950e0d9bcfbd5f767e1c035b58105647a6b7ce7e79a0b092",
"03e42937a554a7413e4d69a1c9853d185ba04541fc2cb0d14f47d51e694cefbb"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 8,
"Witness": true,
"Version": 927470719,
"scriptSigs": false
},
"hex_tx": "7f1448370001058533c2c300000000000000000000000000000000000000000000000000000000cce1c49d000090f653125d362700000000000000000000000000000000000000000000000000000000a074705f0011270d74f05bb42c000000000000000000000000000000000000000000000000000000001c7d646400a560da53d34cae8f0000000000000000000000000000000000000000000000000000000007add3e500a6a2e2c6830165e1000000000000000000000000000000000000000000000000000000009f76a13e00272a2e5b087418670bde018a03c84ae2138e6bebb37de8e931ec0b26447cd365cfa52fda169fb098488d761b3c84e6fe2b0a1f2cb7b87ad7e7ee98c5c90e7cd22aa53d0aec01eedacd85ee7a40c56dc76b302075eb52f5a165010ac54e9ce47e64741ccfd6adab3706b71abd4400a863b6f34f23ac10e3e0ac3ab3a063e9ff98e1cbd59a5ac7b35a7bfa3bff1a4fe56421cd655d75a09c567d09d072a1a4a60211ea931ea1b6e99a56ca238131ce6d662c41c678e1f2ab2d21b017ab9ca65056a392ab60919a5dc5c2c5add0ff4b0985690bf53b92aac4a62b10f4b3de1bc8f9995db1f08935c9663bf3b2c27cf50ec9dc7876e1d53f8a33f01c714cbce776ec7aaaa692885854534e8041e923f0789449d7ae7d1e526619c4472e5796babea68819e6199418c57b3ff8b2168c55c4752f86e0cc35b44d9fbbbb851b769f7a1df5f25968fb9f1c293e28b6501bf6688dc6d9724a75c16f699297f3cc92d762cc9eb4dedd0c846afd1aeeed92c31eb03270d796df29d5cd480787b71038099345e71d8e8dc702732c5c6b06cecb48f170f8003f4d8857334d4f35ace0be136172fa465952ee318b230f3f39f1f2207ac889100e86c9e553a938162e02790ba30d4ef79a77b25a6aa35c3eb55a9f6dbd1c96e78bf4bddd0b450b9890efa7440a6d279ce2aa3d2c504b5811391b3157cc30c1a1f889621d9df320a2e3a145feaf15207c92410fdb82fca580e0833379e330e1b883e01757ccb99b89db7af2e8a783e20327a2b83c73ce13e5e209bedee8deef0fd64125f3aedb486e1f7f75d156fad00dd73f88880ff72f383bf208f569c84982914fc3c7afd69ce611a3e13be66601eabed2690b2ed2bf3a1715517a33b2d55d55ded6aa283438a8b956fb471020c88ac547992874716043d1deb19bb61c618f7cd13439e0bca823d82da3566cd0192c36cd509dd5235f4d612524a6238776b8936e80bbb1664657a00a1f0ed2a5175615d00ec2515467bbcbd0fd32f7db1760acd45e55634054d7229924a19a198285030d3090d41f33b11b99e684823275313c3e86af60b567bcddf7e60af4f0fb8a8c83aa1d4611b032fcaa5a8a902bec0cef342eeb67887f575e2334022843435bd27a4f26a808ff7b6382605aa64abfede133f96268878592f26a7d0bfb9b2dd7cec681d03257d96ff08d3d2812c459c8e6d4ebca99080c3b44b73666589606cd70ece1ac29c921f4acdb0aeb6ac827d3d1d72cc675d63a3db5ade28b405f9eee7e43692f825e77b018c30ab2c42fbf303cfbcc717301cf10f474e02fa9e71f68f1b1a6b600724dde7bd02090f6f70900470c0f5c18dfe9b5ef91561c946449f9f0eb4f2d3fdfbb4dba6d56a0ccc7fb77fd26797b7ff958cda25a2fa435ca25678ec0c97512fb5a171212ad545c00dd63a9e134a23f168981bd3a6e744d1ac6ca36d5ddf401b27601fef6bd524dce6164a375380fcf67cf5302c27f412c35554ac854fe2eb1617669c5d379220cfdc36fa7e77985aca7a9baddccefcff50e2953527dad07a7aef5ec37518762f21361971f35d06934b4a6cfa965eb9daa32bf7a02d3cbe71da5b02f4ecd1e002b708d4accd13bc5ddd27a84d792159464259d6775714f34cbf09ab20458c95505865acdde8fc6aa6ef30dae6b60cbcb0a07d2a7e0b13cf035062f590b1f35bdb5ef9a552d07e1c5b3dd757deabe23b44158ad1ed72b860fee4f25d71938efd0b0ecf89542b6d50d656c6e918b8a6746c3501ffb725a08ef51d0eca4c563eadf395da17342c832e3adfcb3a3c272625a2fd7ad37b75e194b9d068e41f5e90e89be73e1fa1d47237ca78ba1072e7781ea45836626d08221ad3d14959b4eb4bd5829b9515b5540b2de3181c83f15924faa547b75c86a079c592ff1cc73e12c46271df825a340455a74fc4319df941f7e342e9501e87f9c52d71719353787c0888b451ebfea884e7b9f7e1e08336220e8ee987c09ae264bc727bbeedeb88fc9da6b10b36ab191a3e559fafd351f3405016c098f4429ee97c1734d347b547ca90821938551a870b7f4315a31b7e1c64d15c787daf61a452ac87bce0cee9daf0fc3ba011ff3319e57417ec77756bd178f9dbdcd9179333e4e3a49918918f1859ab4aa6100322ebaa879cee92ac17559547c9ece339ba495a2e54a392674a0f01e596df37b92ad5319ac6268fa4e34be837aabf20c5aee8eb7faa9daca9ccbf498c9ca9f10df74937e0c87c87c20d73385da74ebf6b5873ff01e420984dcca17a688a021bc5d4f4a82e43e80bc215a9ebe502f03f9aa92698b848426876fadb90491e4d22354c42be6873f5a3099b840726f59f2262ba1275e50821f871c411e7850016324ea2332a0f611ca730f8389f0912bd647445a182e9a18065575727d2150d6e83b80c683824921cef65022b057429adfe0484e2e3c7ce8e4779671877f9ea1999295e1f9a8a01598a4485f369023ab24dda1e175310f6ce707b976bec4fa7e2ffc876a03fddc0152d77caecea97bbd0bdc11c92955051f1295684fd8f0e1443d55eabe1cdd098ee45fbf672d4b19285da0bd404eec4d6b88bd4ba5b88709ddad97d1868a517b7ade6e5ef74343e5d4f2fd4e49c3f16126543f96ed93c1bed35b8d73da03e8641110c36d46954cf5827dda61c54c7382d7cde2597f4d589477cfdde573fb3c94e3a83dd500851484cf0ac41e7d267ffc58b5f842b644ea36bb60ae97f13e6db7f1c4bae4548d86373e1bb61609da84b9e8562046959f23365fc98f663e646f1b6df6a17a5e0643324aeedd6c96829881196784d99b67f194039f76aaa0cc082fe83c5c425d9daecfb5ae2044f44b958babd9adda321fd329f2d0dc85c1a8045d03c1fbbb4a59c8f892d9965eaba3e2b26e521371b13d027bb89290346d6de1f4dc098b82f99740f2c688dee5fddd02818ecb850ce85bbed1c74a7147989143aeb0e78faaf3426510b0f57be10767fd9a7e764856255f897bcb2b02583b06de695907336f6018b9bf48b912b2354b359563895dbe6b292f2efe5d96d8c7494d57bb41971df50c0e4c3492be67539236d9bfd261783718b961ed7af3c1bb66b92e882687d90916fdaa989ecfce4df21d419b6025ac3d7a0b8df5e986d5245e09165d4c042e0ed373bf2c2de094b6a98ebb64a31affa752f226066b76d3a1818af06411d78a0e8f6712cbf41e77fd0d491332cbcfe03ac2a42875a2afb3f3602de6cf540d11f9117c5040508c77c2e8de0645750eb713f9c2daa86f70367950c2beb38d08dc8c62e4775258741fae09728590997e7e7254cabf3bcce7b53eacc8687a68e83fb64b4f60c6031d4558a41fbe0685a011360ae175ef58123ea07a6bfd6801330a7b938bbc46e900c34c0c6283bf727aa4c5a7b6ebc956a2a73a34600ed7ffc492d822e3e6799c1d218840c8749647a7a3e32beb0de784d44f97ea4bc89d30fb6aa60c202bdb52dd103e0c92106e731b7a32cb927b31bcd658eba282514223db9e132e71b42655b1f13a58c9cee6fcdfe3cb74ca8b20866a2dbe86712ab0fe2f5d83b368c734709fcd071aa109d500f465e30d31275ff725d66d61d6389de4288b7f16b9596a80c8a0070ad17aaeb2585cf30868e98480021e02f9ab582b04f775c289b228eaa0797a4aaacec3607b9de993d5e5428649883d8dadf36c570d531dcede705106fd78f8f73fae85e96ee23df325101bf5b5f5362f8287029f56102366575e8ae261d3c5bdb4010d69f2f554438851fbcf53bd4e3d5e5b410f36bac7d4a9a8fbfc7599e85e5461835e0788b6eb082604107a385290828e56fa4538e21c42e8b2d2d461ec4c15f1d34b8e76feccbab6e7832e24304dd0691f363019c70649e84a7afa02fd00018a6afa7ad8bc2deda6d7a77a392ae19e63663ca2866a5ff3d5d26df8092d1909c5c546d29a0cb2977c49fcffdcec848fcb064b0fec10012506d87227274328f0fb1357ee9645ab7610464f2ebde2f70de3695f80999fb005326f581b839e29c17b30bb24025881bec2763283fb5cf247ad5e2ca72a25b4aa16a7106221cf224f2519ceae0cf8c617a49c36ff0ecc2b847a05cd8f7cbf2f10e1b41774d7151b5d18a25b6f626a6495eab19cd432b4ea9ac757a586c3f3a68cf756d5eef3ceb5d92834c9e7ac0d43d20a6af1eec12b095e3fccd960203a06318c4f8261c576247dc24dc742e3a2e839d88f02addb1660133de1ccd693473919b0a1efe680ad1ef4fd89017e43180811b13f0690e4da19472e0aa0bbd502c0b5c17063d8f4d49434c261704baebc47c8f0415ec33c5f44a0eb189e864a5b72f31f1b9189f4e2ca6a0fb5f02e7aeca67c32076bc312e5c6c38e55ae959746540a4da5958b459638e6008376c4f02c48a6585e942508110c7d7f085c953a25d25d15190fd396185b06e8d6593363815a68a33971f9f6c80f0d5ce251def60037c16d49ac0b1e106a48be2f320fd29b7f78349aa64a7e3d922661543fd4ba4e3e2acd70e8a04a22e2676713dcf60795af6bbe0b62343d5806ca4e7bfd00dad24636cbb16b7e3eb9d08bb38d67d18719b5dbc19486d4a0de9b36748c472914e223402b8f31c647bdd02a840d471af6d3e021726fa7028d6caa14d164797cb9a30fefea445c35cebde590a337228e5fdd1bdd6c720b21b9539e64d0a9a0cb9d5c9274c2d549d48f9df1c471fee0de8852a0cbe1cb7ece1dc5dbab18c80f1bb8e5d57c1c381fcb6459caa475849652787bdcf81b745751423a1caef82a5066ef7732f39de3725aab74d2cb5891518e0514a0bc76058b8e02fd8d01ad79f66e18d236c9c1beaad88887a2d25d2b7127e907c5444ce7e4c16e852c08c5025c9c37897f0804ef9687f6e15efc12d191a6fd6ef49d2fac14552261668c959d37a1680264e19a9b301b88fa4e5757afe371149d592f97005ab7b5e1c5acec9faebab1f93d27d9dd5868c76fd004a5ba01c2db2735791411d029f86131e77f11b2df1998396676c5f0fd71327a681929095f84d9d7751b45d12298a84799c77ceb3c20ee3bd5fff4c31c81d6888565880518fad5561a799b2fd52774624c9c5a370bcd495c9cd8a589d4d83cdc77f5e807882c5d9a869f5bef7bbd778a9606f4670f9e21d587d3d4e106a1035c562ba276f2828160d92a095b932245545c15c9ba57bc5e3139b700a83d3d8f4edaf4aa80bc4aa1583169ba1833a716838ab855b146c05cb96773d1d23a26a86859aa3adeb213af7b95117530729c756b052d7b485f8d8cfd9d524e3353cec87a3d617d3f75f52b81525c1347c492710456fc19f437b89ce4837d29f44fba6df0ca58efa9f8cdea2a8cae2484ecfd7d099519a0279d21b55f4f5086dad7bb6ef3771ffe062186f2b9ea918706928d020a75da0948623fc34eeff53e2371e9495b2e25713960dd0b7328682c0f74282b700ec8af7985b10fe49014a70c6e715180fde1d533676b68bde54acf0eaffbfac407dac2d5431c1c10608ef4cabbeb83390a136776e041cc509bccce8eee0025c80156",
"spend_index": [
0,
1,
2627771845,
4294967295
],
"result": [
"d7b1add885c3702cec9a2b0b84eefd49a406fe71ab6945d4de040f27e09bf6e0",
"eb8e5adfb2d19bbb1a6d37356313d462d192e088510459099bbfa85d604733b7",
"270111c35d939a116777e92815053d91a95027ca6a0971d7d0ef5b6f534666cf",
"d9431013d0ab2f6f324386e5532e812d599b582ac7716191d1d5e589ce688210"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 6,
"Witness": true,
"Version": -1061043830,
"scriptSigs": true
},
"hex_tx": "8ac1c1c0000103448bcf3000000000000000000000000000000000000000000000000000000000c0ef03f8d5d292809d1df6f8069d0392f54a00171e068db96ae04cb26a4782a005f5313a171539b47fa54553d56bcdf1f29f642c7e299c871f46da2ccdc11ab0c48fd89d3fc7dbb647312408f733e01af1812c95617b107eeea28450549d27b1c6815fce518d1ee46d7380dd9467262581740df0ff8997e8293bbfe51631635210f246f3b9756986a0f2427f7a735a7cbf47a71f160866ed8b4c0f19134ee263c4865449ffa1b797893bfe0171e3be1d7652b23c6e146763e942516e93720a964996e753fb5c51f133631e725099c8d23b4a0fb439293973677b69f6ed85963808c30000000000000000000000000000000000000000000000000000000093bdaf16fd4801aac47b52ac01c9d563cec02c54ae175e6d2a354d206485791b02de510f39a5885824db12577fa6e142a3d46393dba53ef60b115b0bfdac85c82d26458716d4e58c7e2da2a6dbf621e4664183950e637cb68b6f23ae65ba6996b843b49a0d9874de0c9e8d5e6f99322699db90a9ce8377b5abee3b724cf26982ce9b7acc2753b64478d493b4b1e1a7ea5703445d0dd8386e33bee708145268af68b2c7f34d4586bfc83ee582ad0d345dde3685ee04edb8c36560d0f87aa8aef0f2e5d9f6c1fef355b92e01fdd8d1ac72006834ccea7c4355ad13dbcf929a58052dc69efc1856598eb10d9bc1a80b4f72ff45b2ac3e3c8430983cd19a72da5f098639cd8a01f30d54e34bf88e74d8aa9805b17b720257b10c13b61f80e63768a071dbef4a2b423ee4a34c28cd70f6032243a2259c11d3ebfc37f0e7e9ce7af6dfc768fdae78c0e4b4567c93ffb082b5817b5e44601af8ed000000000000000000000000000000000000000000000000000000009bc7ead5000ea2166d06aaead9f88b7ab147c87caced45785892c612353aeb80b8ef429fdd44b4b1b8fd9f699d480b51c3ccdf6e94bd947e78a3b5921330acd805ccd5156cdd6744729030b63241cb7a31caea3e59ab65d23172c5c7a52c6db5fad2131063f5cb1418e1f406592a04b4338b418748218f0c6120e9d6ae55c6ff064569b03eb32ac3f8343d6ac1a3c6e95d442d36e237ebb5fa185ac9ca050da73830c70646782d4f15ea97ff7ec047464e015e5837d80df308118abe91629e1593f4e6d422ba6accbb70a680969f4bd00ace22013fb3c886c2fcc49776aa044ab8d261c8feee059dc6304f6d71e23d4b0194bab447e01ac84700c12f119d0500d9bf867eb3180972322af8e2fb4d3119edc5bafcf5525ad5dc5d6de140dae4da6ac0a452b7f0900a2b30bb5e909c4c40aa395d765873af357305ac2f940b4e1d6422eca4e9e2097977a305837efa1946b6752ee25720b2211cb6cb38c058336713980bf15ff2197b545d1d05fb2dd5163096506b1e1c3a9ceca0e41590920d1cb179bfd197423fc383bbdf2a2ed624a04d6729f0b33f2faa1ce8bc6b3b8d5f8c7050ab7ae43fdc84ba6a8ad61cfd8e3e93d6ca1bc8cf701743ff16bfa5a8e7d14a662d01f0283e32bfe1eb420b73d85e69b34c3a935cef5922f8d581878f15bbc63f9546f1c2f0baa102652c94058b4e5e92b5ab4121d374b1f1625edb0d0856a89eb0809c9e6bf77fa52257d98c500221c733ba0ea9b79a83abeca65b50e398b91d4222c0e2c842488650c68d9df4a799484f009520f57be7e3b490c7c92f021a4b686e527031d9e67c6739d40d1c3105be206427670afba6ee9e61d10db44481032618492bde0200ce0451a5c17a9315159f0e47b5ea9c32aa13c12dcb53b36d37f06875c89dca149fce846a233e49d9e018182e2cb662d90db0b2da6b76e846ce2b969c67a699c86008ccd53111720529ff22a7ec867a746a28f18029164c6c1df506a2c3d2b042fead11e8c9b38acad93580b960818f705d836b2c15a069451f24317742465bc0df71b6e96cc46fd36e906780838436d8ce5ed1bc6eed9f6155367075be6a93abe1c62423dc07835ece0030a813b7abda518b1a2047e1b834cda8020e17609985beac3919bb5d6b5a072fd0301780de28352207ad660434f74e3f86114cc25421d1451b2d059b0878b0fed5c130c8c3a9377c862f7f357b0cdc727950394e91e7a75c89aec17847ee500ccbb857c8317647a24e424fbf410e484d72f2766366cacfb7767b24d17b1124d3608c9c8efa56b6db0a8c4dc77d3effd330d46c465b529a419213cf6efb463c8b23c846985fec32d3d15d84aa3ce129b507b34c0e7a5fea8afb00ead26e9e1be1d126a46865fe7ff979943b106de6def68c3371e36024999cbfc81eee23320d67fe4741a12ecbaf5ddd1573ceb71ba30dbaccc4fe7c19caa33a5c0de007236164e0b96a75c07e00c08b556265400c6c7c9cbf8e2dc8b91403cd843652c20b35512e7853f3eb7b86601e1cffb21e933dc10a4c214633c92bf0378a09d5860db7e941a401be298202e1d148384e4a5c9777a37df4e56bbb7ae071b5577dc3f90a4a4d5dac281ec8a4bfb241c8c8764ffcc0276046162c7cda5934a2090c6c089848fd77b5c8c79a197006740944d6d3ee06b0b963f81a7ee90ade804724fc8062e789e0743864e841a37bbaec96dcdbd4e651472964480f504ef7e36be6b9864c9cd3093e436cceac2dc2fd5bbdb156622c9d6a23687b56c8d6b9352db6eb03fdea01e0758de3a88a4cdfed10b4f2c7edb91b36f5069597a16dae55a582fea4ed1a875d79d031f9aed1834c37e16cd3a6185d1b8f49d9ffdf99adb3f425fe6777c9c71da677fe16c1edcda8e40a68b3893d850c8189087212d9d66dca4a7e4bdfe04b7aeeff979673a16e630a981e89352b11646dacc8add3564d49669b0368f2873d8423f1f14c338a23b004863c42ce2d465d939ae92b9d83adb98003a7b89418a26ac848801b05211381b20e4f91aa1cc3387d41dff60712b4c73db66205ef36638bfb7022fe6966d43ab01e93ef66ebe56e95fee5e5f2200fbf530a048c692d5ca73b4ffeb799b8cc8f9c0863d53fdf35dd8fc9da6bc7c70060bb079d34e0dd2f6b90c5f8446cfcf2cd2367a7f67d699d769580a432b1b0e4a0dd7d57e26afe2055468819ed536307ad1fce6c5de4415595aa499cf351b8f7fcf319801cfb479f371e9a04290e5f3d1909bae740ad61784fb136ee99828b126a0e9a7cfb7a9ba11a2f26457afb3d50666e763b0c50db6541ec85f0cc5ee9ff610bc98a5d4b0d45a85bbeb4519cbb78067212e54b70f08ed1bfec143410fbff00c552f071a09087df2a3c4f7a475a66981203d766a7ce6ca1ce48c98522ed302274030a2e3b56d3f4f8a16c5c776c4662e0f3b00899b279bec631cd0b128ed2748056a30b6d3d2a743eda14265a56c87590fdcb0181899a035d41f080150a233392c57f886a1e8f56e86ce186f50c0fcc002ea90cbba51ee9e3f11c4cc49c4f352efe788954ff4dd1096d67c65fe02fe5aa34e3409049264a43b905812139dbb3bd7ea2097e3564ee96ca3be71ca7922565fc8eb5ebcd387e53478fe6431ad88a9f2ba3017e6e793167c379d60fb6c470fc215f3fed6cec1309bd54d5d869a19c0273942090b5ed0c9c80fb00da664dc7cd6207a6725ea080d0fa59d14faa064050c9fae9cb377d6676b925815f075d3b074bafbf75b0f5c8c80823e634db6cfef5c88c0b5eee2c09dbde344233c6bae1d909296131ebb902f70df34f67f13adb90d006dda45bd482c931547c1db41f63637afde5345e2276dd2daab4b40e77c472c1ae4f9c035a8eccc870625bc5dd415ca3f1ae488b820928579fca63fee3dae4e8d01e8e95a8c3422e854f022799096538cd55a03113254e869c3e6cf7ab566daace700aaf5478770f5f0c3a95770e04380c1f01d76a7b1dfcadd5322c082b0e2fb53b42a42b06552dd5349702a8ab7dbb7f20814357d388905ac03c56e5d0f475636fdd04b74820f76c742660dde2bf4985869d05a06fc1b6810df3711dd2060d74b6cf4c28dc60a5cbdc2c033490e20d344434c8de3a30a831e6be4a5885a44f58c74fdf64b0a2cae80c9b96d24bc555fb40d8f47a349749a89b45cfaddece78617740448ea61e8aca5b62490d863596ab6c2022c84fdfe6ccfa7e3330155d9abb1d5c43e259c7d860b88f7916da09959e51f3ce858e4824d031d1d9bc514100a4c60935aeec2524fb3fbbd8823b64968f5e6ada316fd9b0d76cf2ff7f1730728ed8a500007619d1bd",
"spend_index": [
0,
1,
1560890374,
4294967295
],
"result": [
"07f23b994884bcf10b13b63dabe7c1f388d86ca7539fc22f8952992b123f124e",
"dcbefa0f06775ce907448903dd0dfbe3f754fb64909fae87115a0558a412ba8e",
"1d0b4bd141ae344c8cb6943699dd2c9c480aa343d4a27343c73fa002d7d3920c",
"5a7c44ae6d5f5b3494cc1180f843fbe60275377ac73334f35830c78e7931e9bb"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 4,
"Witness": true,
"Version": -1889566180,
"scriptSigs": false
},
"hex_tx": "1c825f8f00010274e974590000000000000000000000000000000000000000000000000000000049412be4000f1fb9d3fb797df600000000000000000000000000000000000000000000000000000000690b0daa0032f54fb904adbedffff142db4ec8a3b25bc516a8bcc908becc67d7cf8c699500b29c7d29dca0d3a87cb678c9dd16f77913c5ade4f21431402f9110201efbc57b65ce926fc2b2be7de3291e53715efdf70323931cb2e43e86ef1d3669bdbd9a9084a9b6a3b6a4db8e4d7fb26f69b68ecf3f09970abd3a4c8e1f89a50aebbeb9bcede426234d385d0d2757ec18f740adb8117b7f685d57291edb424e3bb190f991325fcf2f8212da9aae593bb625ec558fc14cd57d23523b9c2a7ada70c7549c628fdfb5ebe897b7b5ccfecf6337f1a29aca0300f9bf48a84d6ae862cd0c30c808be134107352f98ff57a0b45c42a1a64ad9adc2d7109663e61e3d1881ebd359d54c67d42e1e7b85c9d3b76256cdebbe619c4a3a51bb5d953087254e8223c37a7a65795fe131177faf2e900b2cdfc0a406c734f8cd89e087bf87cd57e47e173f307246f25b4be62eb85822b55bbcd6c043b913b486acc7701f6b56c69491451364c458bb65633a3df4175b63c37881fbed88f27dea76303d92ccdf710855d483c50c69e09284a9c24857a4995f613d9dd348a2e003c602c7b46e6f85d0cc0731143bf5041f5ec6282823600d27020e65c83d8b659d8706e407f465463e77b32709a0b07668fafac94ce436612e38be1e80c7d190e58a2bb132c88e0ee9722e89e26f5dc3bb573e2624aa5b2ffb736ef1ef2798bec4870e2d347f8db9a859c8efb4980ff744070a25030c33095443e1d068acb2c38d9e4d279b176f0629fbea92da1beabceb7c9d184de51dd13571929320fd80ed0ff06e75ff4f326b140c0e8243246961874c0ef5c8b2bd5c1d859935fa66f563f9f15e6d532f6e1a21c10e34a409edea41750baa3e347fcc7c4f39fb4f08cdc6ad6cc947a33925c64dbc373419c8c70a730062688e6566998919976125adf06642bf69696ef0b0c4b5a445507a1761c37ab63f5ebaa8b2585424b1f687b105a5674e862b25666a54d32f5eea68f404cc6cdc2925c40a4d78fbf4d7f8f903b35ed422dc854cf60257d5dd9cc55652a3725bf7f4be21ace11932676d4e7947de73aee3af5d18dacaf4b497fe5604d005540dbb639610911bc0d5eb0017b8e592c8f2253744c4be6bb9cd786b8afe2d2db7badce4648546188af776f0c0f65b569e43501a891046c13910466ea05a6d3af1e56f8e9fffa301fd8c01cd406e0f988ebebc8c4b8003fddcfc481f00cacd6136c7118eb05bd797789cbe4d0228467aa539b4e3b37eb3641aabe38cc824d801519ec4faec0b2f11d8d1e78b76ec89d916ebf908b51232b703c39ba302e47cf8f890cc26fe29b52784157fd1b72242eb1b22d28bc6322e97148dbfaefe659924ef185ec61bb98328932109b56abc50a5e365e2e9df712c20864ab3cb57eb20609ba488973f8bac01ac558617b978f5de900bbe77f4cf3db5f18ce820d374e36f8fd6e7f0d98c600bb407889587f758fa1d8ac0679b5e97521a9daf3891dfd9e7fc23773bec088338d940f8b873a5d4fa1780cc14d0bc0e938feb740ac086e471ea2c9788fb9ba6a7e2614d52d07ec1438cf1a2ae252f0e82239478b82216279fc94e7840f05912e29f9bde5a1aa02960294080ac8f96ebf0254e8ee9dd9468685e4f82354b4530c0140d9975479a0fad3b69007c606fcdb8c8a9837c05b07e3cbcc8d2e50fea37984c31bf5dc7f42ebd9bef800480d86b75666aba8f507143570555a77d4e1afd103cca0a840fbfc90d84806b4789396700cf1ad61f",
"spend_index": [
0,
1,
4209932444,
4294967295
],
"result": [
"18e34b4d95056dba2f50ae05129bde6f55805557e483834bb948cd362e922b0f",
"46eae96e40720a47888c2495a3e5eba41962ca54047c14e2b7e77da87059da6d",
"36b23377c481f92b265cfce6102e8c24e113332d45994a569b38653a649953e5",
"0f87b0636a601f0cc0adfedef7f48e0a957350e643ef946650a35f36fb4b3af9"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 1,
"Witness": true,
"Version": 1968100721,
"scriptSigs": true
},
"hex_tx": "71d54e75000107b6d84e5d00000000000000000000000000000000000000000000000000000000209c3bb100ef9f0118e299bcd400000000000000000000000000000000000000000000000000000000b3848eecb8c909ede6d119103ccca4dfbc2e85234c5d655a21345b43e7419c65abe63d4f4d80d60ccacf0cae717b9c9ed7142a8f406bf33d77e9098954946bbd05afc7759657661308bc4f793995fb6bc453cedb1e45d6b6a52412c8ba703166d83aa614ed3d2f7360a89fcfa21293d18852e4ee471195a07c53c0e0907cc4e352decf2f75d6b2e7624e83e1afd8e3f8854403cdb106b9552f76564a9f75e007f66750b32ca3ea9347780941d94597e3e34de11353bc021198f6940679967ba1bc42ae387e000000000000000000000000000000000000000000000000000000003857dac3fd4d01174cbaf6782b012d2b56725020929cce9952ce0475c67ea056287e85d95780e79327050683fcd1bf105d7468c584e61dd086c2783a09c3f8aaaf94164c3bdae3d88659612edc5fba6800e38ba824715b6237dc96ea8dd84b8c317c84563ee3a44295d902921a92c626459ed528fb26c7b13926b6941450866a4d98ed32a33eb4beca80fcff508a93c5769f62cfda1b4ead917353e22cae84425d60ac61e89f48b7d3e1ed8548f8383c8eb0e64cc2c3d85d4d52d5ad94f8c2f2b275166cec72fa62df15a1753fd0e3a39ecfe1945ca72d967512455ad1b872d6ae7d0c905b0d27b77d321c30292fee3126853fd7d0921db9123c8e98b9daa62436bceb851f4f1542328c830588cd7de028d7dc91ea0a302002dccbc3ac900c9eef3763b3f6967a539655cf86d78a89ef7022382bcadb2a51fa64e62a5c8b66bef088aea6b9d686e0aa4568e29e28ddb2c0e3bfa768d02b4990c3afe30000000000000000000000000000000000000000000000000000000018de6ec1fd15019812e1c2b3e36f611e30deedb5a60d62a2800a5e21b293e85f6dcf66e3cdbe6210b3470fd0ec3ad1feb250b087f1fe97a4a36da4f55e5bfda3feffd9c9a87e9adcdeceb26086b802d7109ccc4abedcdb334263b93646c22e87c7ba0c412600dc5fb55db472c21b594509e9ef110a0f10fe0d8a7276cb192495e8177ec228055dd1bbad401e14b981a3bfda547441d67498a492571d301c7c592b8a05b2d5aad3251cf3fc0f0b6ca396ad39cdec1fca93ad87bcf0c4cb1e074d18bc2f8d64f6dcef9335427ddf3073f2511a1e6e322ce4ab9578f90827601e436226a725c99412e93d8b4f4c96cc421fe766924cf82e5c639bfdb80a826a448edfd9281c3e8d99638458b5d0b0efbc9abe15c1a83f0d92a181d19cff190f12be38c67555000000000000000000000000000000000000000000000000000000005d1ca4d6fd3d0109d0107054af948a2f7f1ab85d80206c2d111e52a02fdc52bc6f438f18ad58fe4979ace46950f8cb12459b60d0cbfca39bffbce5f016c5c6916c63d21e2987a76dc6b291bf2cc1362b37eb1cc81bb066b77302eb73839943173b983b1fafcfbef5587433847eb10cb06c2a55d2d23e3b92930d27552e8fef6690b73d1db5e3f06795775f0a07a776e404114616c470ae67e6f074845500f044ce63b531365edd47802a86e0406069506fd8b01927ce03ae3ca0b8b1e19606d82f0d0979131a40514a3b3304bf50eb6896473e087370e6813abf68d67ab84042f3612f94152f1f4c8065d4c5d8350f9386a592c50df9f5bce6010e291ea2cdc86f391b1c5992f87ce11c8c03f8ede96e1dabdaca44c23e89da04e7ca924e59028b5a2a18b001b0535a4edb3e7485bd053d54370601315f7a0519eec10b9ef02eaba51f597020b5733cba26e10000000000000000000000000000000000000000000000000000000042b02f849b850a2f4938d7b56d85d6afc0db9ec0c0c23a6e0b9321a37c333de904dc8e2e88d40327af86f64d7221baa92a580c8fbdec96581bbbee9733f09c1c623dfb4ef2cb4b26c0bb42f4e3cf3320465aca67be99e48754866956d86433ccfbced928967204531aa3090ee7f588e11a458a4dddaf9ee7f5193d56ae95cbba955d4dc8e22d6ab098c0153f050fcd795faa8ed9a17a56fb4d065c36a09f11275d1e9ecda8f24d4700000000000000000000000000000000000000000000000000000000aec8e2a300001fceba016321f30650e0a147c8dfc6de4f7d2bb7b3e8e0d40a5f92c8aa747d8df1670c83411cdfd311acf234e3a9c56ebe4b214d0c9b99ef0cb3381c5f318fabf034c92f8ec6cd2cf6f4509850a584d131d38a6ec629bd10bfaaf58f8290a74f29f8d490e62f4ddcfae07b59967c7962ace83dc4fb4506e16441507e7c8ea92c9a91af6be770aa3649f2c1891e07e5e73fcded3ec6b6762274d6c8eab55a019c0d930a8c70329a424f51cb8ac41210aae262f3d5b2ae273110e2e8f6389a43a9f783bd2896a56c4ca72081a8c3a954d0cb897c2e4a0173888ca3630787723110096993f898c03a0d51ef7da9abace3c182dfeccbfc542750c4142bba5a161ccd0a93b5b693c9754000b917a05bd5b79270a7c96c2a9a4d0d12fef9b8c930a7ac6308532eabac983d07650d15b91fe358b96aa7b7d7f1a3aad08f2755baf4d0e02c791fcbcf8bd936583204fdae0116c24d8d9e5017d8dae77bb97c3b7e073c66096981277f18fe865a7270b8a636fb0a32ffa86eab5ef18cb0280fe6542a5ce9f944411ce8eece59a01f73134524ca062dfdc004d7e783e84628276816240a245fb038084c33265d9782061a5dc964e4a43e1ad418bacb19bff83724379d5a0df45b2b17d5a3dd8a6b434f7a4950f125ba58e8fe492ebc89a35f5fb80e0d587c148959a897df99a87de1da079a15e811da711b4e96e56d75f97ebb9b13e45002a6667618573a5b8fa35291736a7d9e8f2578d596aabf95f08c0c0fdfe8a3d31a89e734c692d0498b7051d5d373bf74a4d804ae34eef159eda2dd568b179c82aaccd864854b8c98388957ea73075ce6c68c681e3d9b40b2a86c224903a886084cd7fcbcde506247f8db1b4c5656c02c54d37f9d3ef31d1ad980de35a692b5134d456a1741a30c6cb121d2df7b1f78157739a631e8e583903537b1e103f567c2cb8d4072b04b1a0ba7bd5fd1e4e96b938c863b660569ad4b061cf292dd308074897300b23d2f7729fcf027e780b89fae832b5dcc236ebc64d878159f9fdc4e6592c5ae07a43777be86daecbc6643326b58dd9e83481dbf74d42a36a90fe9b2a4b2a5abbe6045e9e2076ddf37276c614d371c7f1c9a0ef95292ebe0457971fd0dc4e3f37c850f587164eebd76ebdc0786e29ffd52c12b6db9388bde3831f631f2b3afbb0650cf643cce5f05ffcfb789960ba6e4012fe598b092ec018b34e8171a6a1de3df81ccc979cad55893761e7ec70d89706d5660a8fd3192f86039a3f20708d44d6dd7b726f247e834aa5648231ecaee97d15baf9ba09f333195a587354e168d305358ee7185b16a10cd3f2b651ddfa83b65f632046aeae8e022468a098a353a995cf6cb69527914396f63fdfef1059e939d6c1f241ec1d1ab4f90f61d253defbae9090bf5fd1e01c4c70b19ee49f7fa40d03b5b93645f249475af6729c1117698c52fa2fda6c8a89083bc3ce83b788a4e5c67b92682556f1138261dadcf568a0e03ed9d7305e1b5b0cc8c6b18bdc677299ae62c4c6906a92530bd8ebc6060015cc3cbb36ade11d9c98b27e7a551cc83e5246e08a624325a7a5a8b9cca454e94cae68a20f10ea4b63648adf6aeea74ad764199c2ceb3a4d6cd2836a8e8782d304e5b5d44cde8fada642fc49a18bc5d7e78d1e6113f9f9a6c0b5cecda95d0d7e0f0026ac8f3a7d136701e3670ed036d8570d5108d517b291ec1779e49d123f416dc3855cc609641c6ef4f9b218d01e09c2ddde5f35e8146713bb2bf637e50357d6d954545671571bf02368d464f3a80d7703b3bc45a7e518c8bd23fe7b31b14a1933e68617b7a268f63cdfc0615cb046799338b2a8937369532885130f728d83472d17bb7a9a2e0e7f025473d6a04fdb7011b43ceda5924a8c04138707b2e813e05b977d30d4e38a7d95927ca232bbb5ea1a023f3e046eaeb230c247a51f22a0789d1f67dc92fa2dc0f783c8ace067fef686615396fd2c27a177f20ed4bb4c88355c8d83e0f51a9b31406f84c4a2a5ca668e86b4d2e64f46568473aff4e33ca21b7d31ae24c9509151331cb3e1ce348bec717db172bd4010f2e536c9d7fbc48a6960379a37c75fff53cddc5308deccdf38288b2f0245244b0ba1b45f0bd802870575b38dd1a8c9346ff2ad47eedd54115454579e6053b42cf38de9722fef7180b580cf13dd100681ddff75e8fdb262af179f2f11fcbcc8eed0fdaad2e6642c877fe19d22ceeef8aedbd460e2cda20afdc2faa27aa3463b2ca1006cba996cf5883b9b780a45606553d51a7050d512a06828ea9d8c97e5c7c3154e1fee1306a7ef6c82e344e334e652819253c6718265b15d83cee6770d585c313278d25e78928c83c6c45ad32ad8de1bd665a762db5f032088a3dc3b300a574ecabe3d872f4f77d4c1a758bedb646114ceb8730c7d58eee477c1038d3dc2dc405282f677e26903cb42b1ade7d55fa1ed54aef58c2886b8940924165ce863c80e99beee053072ed50a997edebac7bd30fd4b013f6b503a0891e7c112040930a235d3b311dd8cf81c71a6cc1df44120974a40521d685762d42260137a332a9b35004c729f5b2a2233ea6bd122ae8868b96b57d8d537a78420217b12371e6a41d53570ad2ce6a29bee8ae4b7852844c3885869ebe29f08db97658f2fb1e8f522fc64d2392cec4dd554bd4c69c7210dccb7d386953f742d63797370ec2821d1fadda679e30c42b30ebca43cb8634b2ae9d5f647acbe30d2c7de434695e9e0f9e939c8cf6428dc1fbe94a08707158216d326855b47de19704c0e1e868d575668d4a37f8bdf3037e81a676759a68327c801b292b42868af3301d66c6a53aeff11c8edd5c3030d9e9d27cc9a4c4850837aba26514ed5b35f3a76d6402bf54e10735a6877feaa47c74a65cdc4ea487f46ba65f4adf01800f5217949c9093835734fbc79479fb19a522d67566d42c19ec8089559b1f77068809edbf1affc4a57dfacfd4f0129353c77435bcda2d01d01f9d07e489c31c81c3138d95142be2b4a501f84231efb13db822f0b85bb5d46e055505f74ab2e016245f61d2a036ff83acd8e74a7bb5b0f299db3f0024b0755ed4151584c283452d67727403c39ea1f68ebddf84ee0eec2557b6a05dcfb5412c71dc94ec8e03eb393378ae853337465caf98903edd34ecbb34022902eddb1d125378f4e8d6d61e785a80e71d6ea6c5add25b19264befea329757a3948da8ad27c50e742d8a01bdb3c7175e04c8b8919ae46a930372c38c95dcc533ec2b02968592d31de64089385401725ff042e979fdd3783d54dff6ef9b4ea1bc210a8dab8ca449d0e205288850a0c44af79c50cf7e1b8bd36b4ce864d70b965eed7219214c324b7e378d7430cd9fa7b69cb462547e0ddabc889cb767d83d03153df7c405cf1bfc6d1789376bc542a5448a17568f1736da8ca895eccf15c094a62448966470fb9773edbfb7db4303b6d72ebfd018d6b590cdf7ed40c7abc80df6801a5e0a56e006cdcdbc6da5bcecf8005a3c6013645e49d33cdf10948fdb88a972ceba920a72e82ac0f3d0124fe55588137604eb4f2ebefdd57aeaed44f1f0328e90526644a848b548b16947366473b628431d8a80b661f5d538a9c15ed288cf7d40e144efc89f7509297533d3e0032c7b99ef1929956272ca693f76a40a9f76ab7002f11f549128380cc7204b80989822529dd9307153da4ab5712eccec3e4b2b8ccb425ae599cdbd7accd00355af6f190490f9d1551be069b7e6ec9d77fea777ea86ef74d61e19ca22bbed8489bb74b47ad8b453c173c6699e14b66b3f7775e0a859a020701d3c4ea36b04c74691c563f7e427c755571563d47b80f008e6e8ae96bf6355599f455ea68201e9cdda8289f48e516ab90dc8050691c2874b64110bd4e899169e7e153c9c54e775833f1b09fa70d026259f607aed8f35a844b3843afd49294cab5cddbd20e88411e17b3594cb350cad5cfd68ca304c6b1cf3d9fc9ddc714328e53ee6e2d0d20aaf604662535335303b33a3d9b60cf4be9c82758a09bf4ef8c90e9cac028d32317c51eac0690beca785c7c4b96d817f01fcf7ea184a2481edcf910bc098c82ed52f491e666d55f59142943cb667a35013ec0077a17c1e519a7022d00afbffb18ae0f6230b06049515c90846f8dee5e8de56080a4c2d4d053f8f0924000b34546ff0929693b484ef7fa326d096b905401aad28231b3cb5dc411fa5401b04f6add2268955ac986392b825185f5652007aaa3530291a768fd508ce9cf934819c50cf6bdae2435a5d09e323f714d83e6cedf4c22f2d3a040b89551a27153fbb967eaba61b2c3fc37278a6853f25c392f16c607e945abbc173cc0047165666e4ed2fa981c85cf61237e4a614ef09e84acf4158f581a1238ab4693aae877f1c969113c549275f12ea797f2119cee1ac1d73e63b81e2552063569a8e76e95006bba2f31",
"spend_index": [
0,
1,
3326047036,
4294967295
],
"result": [
"63c91fe826d7cda1eda1c7ec22e086a161351c0fedfab39a5f0511820aea00ce",
"265f82de40725e29612043afb653e7ce4632d49214912d25dd976906cb8a8072",
"54f9ed49686c92db01923931ae8ee4459cae5ec800a04471f91b3c8d6447428d",
"4bd7c3490cef1ad26a759ead29d2be88f64523010433ce1ff13c1558d6f96a4b"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 6,
"Witness": true,
"Version": -316499655,
"scriptSigs": false
},
"hex_tx": "399922ed000105c1709b2a000000000000000000000000000000000000000000000000000000005181be300054c54e0220c16d9f00000000000000000000000000000000000000000000000000000000828b1c03008cd19e08b34c333f00000000000000000000000000000000000000000000000000000000930509150028efa61a5dec5a4000000000000000000000000000000000000000000000000000000000f5e853680099eaabf38cc2679f00000000000000000000000000000000000000000000000000000000e486812700ad935dd906ff2a3db5382ef145c8bd658166ddf1306a4d978cd229a096de55e63bf66f42e852fb94f37c68996efeba07923138ec6ec460e3f0d6f44693aaa89ed4b1b6527d84abc0bb4f275dba2758ccc4c6d7be64a6915e951cbc26c95a299dcc30a6651870d8f188e93a863410cdf0b66f8dd46c5a8f3dc08a0b0aa84a7b20919b2fe0f2a374e7c405cf24ecec3d00faacb82b9c72c7fae68c417c0cd6ab1b8c73a56d5e5609e3e1833ea4740ecda2c16866c7ce70abecfce5c12adb99944ead985c78ad2dc548740c64f4bb24d2539726cf4b4409e4caf865d1c8df26c8d01d6bd79c32ce0f8424238d740a04cc9ac3e261a41c780ca438343fc633935f44106a580f85209317b135aa84c12789d4b960d00cc57e041f580d557a993ddf4070bba3bff4b1279664338acb6790d3f038ec6cf1fb6ac921180cb6254074cc0ba05ba08f18b24668bf44afd9117df1c97553e606b418ba519db256dcfa6d48f47912e12d4eb471d480ff7dfb3f4bfb296d1099636ecb2d9387ddb131967bd86e3e5a090a90e24c0b10e7b2cac7fb1bb8b2e2e148b83f09bd837354f374ef840bc56edbb73e8c438bb26d2acf56f329c8cb1061e5d98898ca7d9b7259cb51de0fe913db80b314f79a7ad456543b03fd2b4d136f4232db804ba492d4f8a6fd9bc3a615971dba48eabfdda968e7eabf52caca7c0ad845d88ba3336afe1c3bff6a95afa5b65987b25a0b1c4f76bd336ed2ac16bf4cc7e8842363031a611f2781f679fd6d7dd92e804ac3bec96bfb9ce27a5c1cbfb2a03e478cb1c9ce4f8be188744468ac7b70c5076df6a4584a657c7d89c776ca662b6e42a48536f8f6dcca708c8620a5b900eebaed0f18bd8276e1122e926f26f8caf693b95849d257abcdbb204fc8832eaff01c6550fcd560e9766ee226def7b551c900385c586d24f3f98b733a24f2bf2d90fbefd5af2ad4f4abc72efeb4c73d287296952c068258a22f8d7e406f90cea5343096cd9b45db89de96273a991e881147b3d673c380b7a92b2784bf7fb90947fac99cd32b9eed14943a270b62e846a3c6cbdbaffb572b62cd613e3d34fda404ebbd70d6491e6e75547b5ccf7a2a13b411c67761b875b938730500c3827542e6ca4960ab78d91ca5b2cf8cf00f1d517601f1c96443bbea4abc2b9dd1ea6ab7dd2231965fdca577c6f1cc79492dc815ddee4a7e2fc5c96c8372dd3a24f84033d166a62c9becbfe4024aec470ab9fb9488a86e7d0885bc3777712ce0e3e4a26068fd57d0efe01c04712a9397f4f02e096368f9491ae381c063dcda252595d37cdedd3005589d09a4f3ff41682b2853696f83b534fb0760f4f5b46baf4cbfe9155c866b1f7690299f1ef2622af2c24718d36386ce690c8bbdb72fb292561c601a863cfa71d0a7563ccdebafd34bb41168cf46c230141345e8e8fffe1b2b19e7c13f0623957e89a0c9cdae2b16dc336bd13089f40330222282ef009cfca60d26c8523419558bcdea5af03b7c5e5035e6a1b4f98691a8b531fec14a794c60679baefc4c2424908877afae1142293bd03f4f6c0c79d6a7cd2c5034737ee3e407cf3c170294c18c3bc71a295dd2a23fd4de738547574940229a974c86ad8e30030cc9bd3c0016629bc83f579bd2519d3241f034d558e2997e20fd4070fedb4541af8f4feb5c9506765539e06efbff3b85940bf62f837ad4a425e6ecc67d35d15aa9dc7b2cf0072216e87294f49bd7da547b27648cb1e124c83521db271d9fdc6f1d0f0e416402ec6049e404fdde01aa5b1137253480a4f3cd4c1c7b46a72b0babceeda57b63ed0ceac604ec313ec117a0b69759d96e5e81ce048b5a684f7e2cc3170cfdf3470064e110a3948d4ef132fff97a9437d6cc8797502dc05f412ba792b048d620ea7b4353610619db1e6b8eea6ba305c6da1fadc46a7698a4027bd56ff96a7e3d0e34266b9d1552e51cbdde5d1fb3cf8ee93120f2eb68b8ebac2ecec6a5b7380641dfac005ec21547b994508a71b5a0e871d091a6dae6565fc79aabd13b18594617c3c30959a1de1835e4ca8403c8c3dc4beedae8303a149a12e49f0ce4cfe64dbcc90047157ff5a03061ee1b6d6cdc1ef27f1e75b67aa2d0d08449c16bdeb6b42c793b26c3bf9b3462b62cdcb29db21f720a0eb4669cf69d345c0da6d25ab70a989f2b2144991bb1d8231cd04e3c351332da12ccfad35363e1fcc1c1cc4551be2ee3322d07c6475cc6b793be7cf463733811cd88b487d9bd88a1cdf235594bf2db268e8d033d2d39e1ca2f77fa9bd27a2aed1a76a0e85138a685062b88bd50a0d2873d33559ac12fada26e98299d487583491a251d53a1e0906883f0ec513d3991e9b9086154b12ecca1e2866090f59d464571ef6d6cc8b11731eaf20e82e8ef563a0ba77f6c8f564ff1828b90179e83fc41e1b9979a42f0282c328adb5ea63d49da65964eb02100fdaa01a45962b4510a581eae99064fc0273ac5a1498e9d59dedf4688b37b0fecea4c50024c8a702de7dc9d473aa223b268f2a61ba19fcda6c51fb46d8d3fad2c0315d9d315af8cdc31b4c3d2dd7289d15a4f646fc93b7010ec188820ffac7403a0cef0767068a58d8a9ebfa47eab5135b622350445656cd880391e34c1d77a6137219e5455d222ba1e8e3f1c6361445c57a7834da401a616604de44e95f9f5c6b5bcf9cb9d88e7df9f2ea03372faa4e0a2df812295b44e719d0d39e90c047cc0d1044b1b55bfae0e9ead6479cce7eb189b538657e8355fef4f16a27ed44d57c0d86f957279096696b1a2e31ae1c61e1b743e434e8fb5855e7edd756e05787c016547f9cf658e2b7f4e0eb80a170bdab8dfa9eb756f4d6cab3a316ab97e6ac56816449640c0358eaf4c9ac033805b53f110669f1e6692db13c326e12fae93d0b4f00f843f129ba8d16484e7e61d57b3f10981c7fbfac811ab8cf27fa0f98e665a4020f665d5b66c8daec19e5b1a2e22b8cbacf66a708860d8f97997c5d14b0e2061426df76dbeee273199fedfbc4f2d194f08f47d9332a3c6d6798b27afcef2dfa669a76e8833917da247ec1c83fd4d01caabfac6dec16afb8842e9a6cb034173972133bdd7c2280a4cb0f7518fdfff9c4a32b413684c65a6852a5690c040f549916c1e7cb775484bffc5a35917d5505201b3f21e009285d99c71637732b24862f3c3b73e3e6fff9061719c72c5f7e932a0925748e10c81292f30bd8657d078edf359e55706cbc850495173ae199aacdb07bd0462fe32f9c9b7523024742c4da7ae42d67b7a699d9fd4fcfa4d430756525fd4dc78fac49c9dfd34085bdb4c8bb32b8ecf7fe144368e55110c18f65e42fc85c80035c61374f5c17681ae01c42fc16b926f6964052676e8919e124e4992c7da4af8473603487115e9d9a4924bcf7a0719e1f62c8f730d9d7306804a236f4cc476a7e4041944892ff1c8dab2cea3e8ebc13ce450d9b0a9927d11f63e62bec62fac208b5a35a43837486b8bbc4388fde307ba17feac696d2dd932fb39d8f78c8a112f03928a818a7cbeaaf875fd33011f77269619cd185e58c514df8c688eb1caf658bfdf1b47cd08caa126c278591eb34353e85a2130d75de2f482ba1beb21ab3a33021dc68a9930d169dba4046879da7b6497edf3bc48f436d64de75367e86588c057e399448ed5944bd8acf59b900acad0e79b293221213963eeedc3cda833e014be2097228d668650e9b9eb76767af829cda02d298a2bcc1af6bdfd742d1bf5b09b071393f3d18b461c0df9f468207c7a96f5d3fc08aa2707eb82569166870bee193cb8b9a460167f292bbda2cdaaebe3a0b42332ee228452b843f0a83f45dd6baa70e193288fdb15585eba9f8d54068e28b4acb6f7b07edd9ff589ff3c30e51e2dcd311de6343c27e2a8993334ce4def6e55c5f439131ebc913025bb77608d2d3c19abcc0304717ecceb47fcaf64947e6e37e076c20a2649c0de4216a3133d1802fd3601e4824f69db342e4ccb2913e45059653413ba911971b243090c175c06579038971e8dd31e1159655bab2329bb0155ec5ddb4680a2d886d503f3a893148202fd1ad1365fdbd4813b8a25ea87de955f027cec21cd203a78ff4ee9d905197b8d5cb6550ab0df4ce595a80690f28b832b2ecf305e6b7ac47a511fd3c60c9033d050b750655b62a87d133a57cc2f2b0804516de42daeb6a37f23b294a4eacfd6a368af7221dcb556a9ea0962419e636e87ea7bc58617cf1db6bcf567c80c0d07fb6282c175507397c9e513923ed8f799f91399cefae4d6e27f83270970eddcd8638b085a411d6b449c8c9adc49245dd5b6fec2f96f9ba406924086e8f2bbf228ef9f805e1a4f86a3740b2a80ec1168bd1d58a695f3a3655f1549b63f3e06944981c188f2978e71d4f98a16e1d0f63a4ef46b5a27fb40d04abefd480112f3aa9bb4e3db53c86500b150aee6e7dd4760a0745715baabea6746ff7d77936f95afba776d79ec0bb1e240df2481d13d96f51e1250e9b2c9cedc700359edc703cdcb7c14de860f18ea9d7cc78a94f73824e0bed25d4c9ab367c2cf8c240c3c9693e87f2f564fe03d5b9ddb8a8852babc1d52dc5934056e1fea8ae5c9c979a296a2dadea00c70c67e692e44d4552974116a3ce9fb6152990fa99ae3cf15bd3871684073f869c4834f1acd4c8b66c81b480fad93f92aa56ffe2d182f6d04d09205b06679d5bcd5f8ee6f3c32a613f2fcb3ffa17b94a521f69415568fbf5f8db20a61c8a768fc6730159fe88f634012316b568d4d4c720c9c5d67fa336151bba71a1f58818eece6ac3ccb3438c05a5a2fea8ea5b1663df1698389d4b5c92646c1dcf0c21bb35ab469ea47cb0e1ae0f03f6cfe14ba4f9fe7ece7571c2429d161f23054fdaea9bdc71c0395b07ead43163412336701b0e795654d21ac24d58ca14e0506f1a5ff07837881a89ab01b6fa6d51b2bf76fd292ceefca1bd9785e908f14322ed8affd8221ceef519edc243d7465d99d97b9962caa3e6fac0fc2432126995e55aa52c461619f5e1f58a936a53030b30e5841fdb1ba3cfe0d77c98d781273cce1912b44ec99e61b087dc0cdd75006997910ca92019d0d4690b5ce4bbbbdfdf0019c2c8e2ae8a5f4b9c4656f226eca67bfe0d3777f8e90d4cc092bbd0e7f32d287b3825c37baeddc7204cf2d9070335f07b3c22e0951d52794c47c4022d94d098b38d607288468369199b7840b3a121b3a1c66d52fc7380908170c96b2bbfbaddd4e88e1b3d3ce77f1cf7505b12319fb0eed5ea013ff55692534280c22ac9c0d9f827b4ec72475f1299834e1105ac0a01e98121f1693d14f5e27d10ce2730b8975feaab47a75dcbfd57ac432fd7f0eabda353410504dd77349b4e184d8f6c5aba889a1a2d932a0f0b2afc0d58d410d1a841c160f6eea0681660b462e9b7bcab5e302af4342edb17f7d444aeab6ae741441acbd3f5cf555ac96d6350e812b1fab75054819c97ac77e74f384e2a05ffd9de2adc28d5c13637a44082f75287914ec12062674af016e348ef34ef0d2ef4b4d5fd8e5244a7cd028e011b98e9150ba8d426d0fabc998e3a596be06f3fe2d7c3af46bdf26ed1fd37b793886040621e7bf57fce0154a4d194a157c8a6af3f302a260879c591a28b6273c65504b7a54506fbdaa97b89a23c88203acf07c62c36731a93c478391167d2c057142030b2d575d8cdafee3113b545c2ab83df742914bf86942c96bd942276d6d6ca884c811d5edfb80c83c2138f1561ff30fb713d3854683c7cb60f07d29376407c63c5a5ec7ba3a9ba700e7b7cbe0f3701ed8ddd849c254fdeb0112362c0b589764687212493c7bf438e05ec0903b77fade1db4512ef3bb1196d4124dac4f1e4657f52def9e872b0c31aa4bdc08fb9d1df950a00bb3b250cc73439f2955d6d35c1d54bd27d8d7c777cb16681862c39b894d142dea8dc41a15f591b378583761356ba4f039b37fe819b487fd932356e59cdd66634f6ee2f3629080c755caf495f5f3091be1c2602a663ed195ae3d7a77ccc56d9411477e4b2f57e218438bd0e2987407f982246835170f6cc6159b14e35c41178b57537bd24c9bf8db2b7da8267b9b10a4e82f62c07e689a059cff0d773d9f4c5ad78f8e4849feb772df2f357943c654e845e1f3af28cc79d5d6207acbb26325cbe9647688c0f127c5e0e8031da75923677e7e9c931875e036d416d05e2832cfe91e00f1de8615f279ae6182cf188ee75a7f605d87f9e0b6d6ebab35e0aa34788c38b5b7b128fd7119c569add2c3347d83300a86b2ec15e2c817519595fe560669811e172fc338de2ea61d3f774b9fc9d9965321d001845bcd773bd258aed2dd57c0dce66f6ae6cf42991a6eb9ae223fb6c50ad06815d6bbe7219231264377272719a286439893ddefd2ed180d21f3990ad58bddd9ccedfb5b6966fba304f0c42cdebc7e9c0994eb685ee7db79f3553470cc93c0d0f611df7195f9770758eb6b2309ecc6387ca7e62fd9b220c6ab39f657032803fd2a015634abd73829d0058c9960bf3a0f788a642ef098ec627f15b58ca5d6bb965251c2f1e3829c83ba3f8fea57aae92a4500dfff3c73d0d0a11ced732816261396ddfe85772454594276a4beaaa36e2164bcfa787b7493f40af404263d1c6a4d2cf9fa12713b46e9a496f4dca85f6800c4da90718942838c64bce8b370211023af5f494bad465ac916f728c79d379deb8ba09f6afcaa781bdcafc17b029907fbdc79d5d03925e5ccc4bb9c4c2ec79d4e514268f9a984b97882a8dbba4e865d7c44f89507320afa670b2a43851502a686891844b87cf65fe3d407a3d2bfb8bfee82b7400dd77d4dc427e16e71713af0b583212a27570479a1aa6461e66efa0eef33c6a4c3ac05f5249385a5ce0a4c2b50da420b77c1d30b37b5883b4f3ea0ef59d87b45a4a6acf5e6316207f1fd0a019488f32a6f3a8517dd3ba49619143f57f62b7bb1cfec8dfe18d5dfaf678b7d13670f49d65ff53f50f2dafddf1f858bcd7667b9ade86cf064058dfdedf7d472ed56365c819512fece143419daf7ccfbdb403835a7cfe0d3bb2718163e0d7046bbd53bce3edde7534fddd4cdea5786060d94ebab4b33bb74a833da438046ec6d787b3c7e88a24c670234b743ce69dba5aae453d5d2182692084cc0b238633feeb80fc684c863364797314e344d0c9bc4dade506574bbe6829c2dbc7429c6da5df2260a2c5306b0aedd6d2c830f872c9c100bccc5001598843ae5fcc26da830177e59a63d48fbeab5daf2b7ac66ef31469e9f9001da671b0c1eb2336df53628a081947f7d9fe63adcc8bddafdeb019edb952ddd6e0ad6fbef677caa99b000f96167fd13b2324adfa1d3c78ed5188159f5619b29604abc8e8d0ee8e8b888353a07aaa0bc6a3cf914fe737f3bbb0a70a142b16e52aa55975d383011327018d2110cefebecd8882058c19d4a4aa7f080fe4fcc781f43ee67c4eaa948156bfeaee7cbfa277816db60fa5deba4bd9978a7ff5e0566f3def8c0919cc250e304a3965279417010664596649f7b1ac400934ca6f8c9d1ce1d63c3086c9730bf9cb762414fad35019f0f2041ba5468c3eac7dfb1e8083014affda6ead6b2013c29495c6d35a5400bf544774e301eed5465ec3e12bc31046593ae3eb9d282deaafc83c0d8cf885d557f30be463e7e0330cfba4d6a69984ac978a6b5c391d6d1d28f2115a0ecf4d7cbea55153e3e9f0b0c219379d2c59aad5c83e952124f475ccba0fdb03e3ba62844a823777d513e481fd69bcba19dc62b014af2f9c8e482c163e061d5578c5aad292d254de96b191ba88c36a4ebce818d9d61d4933aad15be9aa63eeba2de6026e3b36c6249ea5c8c2699da5e75f4fe56cc157169f0a78cc9d3d6b12f985583a4d6e28de5e5b30c70b3826342bf8c6ace75639cc08fa4f7562702a307060004b18d07423d94d0e658c9a9e7141b625d85f1605942fb9e510c971c87193e72e3930e79c8008b948ff93c672733027c94febf341d293541ee003eab19ae",
"spend_index": [
0,
1,
1446282621,
4294967295
],
"result": [
"401b491b439289d26a2f389d10fd79ce500b93e9a9354a07ca063de47bd21fc1",
"30dd1c57097fd956c04e75a7d3a8ea6768ff13a9dd990804926664203c1b2b88",
"0b2095f09814fef07bbb58e07069524af34c0416e4e20d5766ce5b682e5a31bb",
"7d175fb5b55e2d6ed61a7f183854e7fb48b822d5e2a5d62eb15963c716b22daa"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 1,
"Witness": true,
"Version": -943280664,
"scriptSigs": true
},
"hex_tx": "e8adc6c70001061d608d8e000000000000000000000000000000000000000000000000000000008dad378df19b99cdefcc47348448fb0e3f7b537987dcfaf7a09f1dbe4688f88b41f1a63f06aa3824f4c59baf3d47fe01fe38f012be213c6279ab131549f362e2eaddd1d5cb79d622ddcfd738f2588879ad7b3a54dca6c89e2c848b0a94461a2a279a85f4e40023820f7f8bccbeb059890be4596c919573b508f2b48396c00f101e79c3a8e8389ae4cb5b7a604254de0c8ecca3c7066cd90a0f83bd9b86e6723d6e2cf7e483abcdf7be88b41ac337cfdc2e4e4115ad7dd2ddc28b53a2d8b2c8f70c67cd1c2926760c680fd6441945a84b23cf1d1186230694ccc8661ad71e60f2610dbaf2bf6187ee5600e56ab30867abf7a3bf143b6b3eafb9afb71ed72600000000000000000000000000000000000000000000000000000000a3427510f5c0f85a2961730984b8f0628679eca08db731d39468e7422df04e9cde3757123e7b3af9ad0cad2d420ed16cd64869ae758c82ddf9a712d43fc35995419d22da479ad41714a059a2b6222bc2c7e2076f83c250488b245e9c229bef2dc1dc87fc0867a4f74267317ffa8281f7c81d70acb00f5751683ceed72c042b90a736394113c91fa6fc865c1fde963f14b3a98a67a8b555c516d2e5693cc7249787ffe875e9f2264b3daeea6fe84827627614ad35d49a74133fb63527de79de4dee0d7bfc3530431a7e699b7d3ed229c8a10cd05c1172ce249b6944b80513fe8fb66070fe9e3d24d94711943da3d044a11523395a11a8bf983da4a0eddea8629e315b00000000000000000000000000000000000000000000000000000000d0f1d3145df7dda966acd462152fd9d689cf4984fcaf790de587b8f511c329b7f9e077c7c0cc7ae556b0b3bfb93b5e66d4b4e23b30354785db6c1a59ca9f3b022aeeae09a307fcf75e16b0c85089ab0c910f76b3ee60e7db3cd8f2ac2daec2e91a6276cc189eaadf445c0000000000000000000000000000000000000000000000000000000029d9f470fd7f0116992fdb68d299e30b142a324bc40cc9552ab0f16fc59056f9e41b50231c0ebfa05b69c4807762552b67c35b7dc616112fc9bc34ff7afada3f00979fd82d40d70dde7a12a7865f2835819bdcd8088abd36f2b04bed21aa3d58a407ebd7d307de842c4c870fa4f3e265e5ffde33378d4c4e3e4b70c68b9c581e548adac0a497ad3e0cfd07e72c5a20c0ff6253544a570cdb65dfaac0df69d7710700234c5940d953bc84ad41f7a6142ef1ebb37c025dd9ecf6a61425cdb34a3667c2ced06c0dc226bb43a7815a079caa0dacfce9c7e88df6e4c55f46d2bb71687a49418a9661534b7afe10d7f767c2fab5cc3890c88941c61de50e5550d4f27c084aa75b698dc45cfae43c12c4ce5fcaeb56e6da34ad1b61c4f22a9c91a452d174d240d8a52e346ba86a4db16ceecc6d339c83dc551c63d03ac50c9bbc40d907ee35dba1a208d71476c072265cab4d34a6697db0ebf01ea4f69d152ff02282dc340f252c5067054d8b99642048ec672fb4e4bf6240a736d89757569fd3e694cedea8eefb8f6b284aa482a2c5ea1d00000000000000000000000000000000000000000000000000000000231ff2bd76521251147acc8b898b5bca7fdf71b404423f284e51e708785f70293019045937097898cd23a89f6df62557340e778107d77aa11f22a905376c41a29db9b0d7b42b0c9c5870f6d9d927c32baa13509b8907e47adb6e79718d36e6f01312644ab586d754d6d6e1a6445267abcb21a9d24549dd25fe79af4535fa8248c1271600000000000000000000000000000000000000000000000000000000fa14b3fbfd4101ebba470ffaa34deaf30a9658dd643d425380bc1e4dbaa7e56f7924748431a86440485dc60be0a1c9ea308535ee6bb2cd8c70cfb950a2ab7008929e4c9c845a77c3da89f7c80df45fa72f40ffd32ce5a145b3e6652a9d98d4ad5c03c90571977bc5086fab8d88fb700e3788ac099381b590ddcccbbb8c2fd7a417d5284cd75cb963b168f3a33787c7b7a56ba021c4f09fcf21ce81a0834ccd2839e920003882e7dafd4170b12c6c0ca3747e54651cd336e8122d11640cf99e20d0928886a79cfb391ac295ce06fb8b7ebef3eb34f995380be42830297091255cfc0d37bf92faefc9ca61e1dbb7e85d37d190c86929459375fd9d4b8a5c3cb4a80e2ba5a815b07f6749052579fbd6fe597920814490091239677f9fbd8ce69e6352d9508be69758b310cc6024b45cf9d2b047b969295339c633dd9cf008e02966dcefa60f647293844ff91af801182ec639fcf3f41cc8fe887bcf61222c015e771b7d6c6bebe509a563c88a5f936960292dcfa603cdd428c7e1e97fd1939929ae7028f665d2aa55cef4596afae6419d5eb36654f793cdc3162a8cf9bfec8c7a9c9abe89215a78289e259c8250fac22db88e10643bba30065fd53bfd8617cefffddd6ed8a1fcb637f193f387c191bf2456fd6cda456b1c359f521d3a329be8e64a8fb6ae43bd1cc0883d5a18b07e999497cbca30ae93ef079e55f96c2d01480a3e513c1808674a110cffc6c143c6c6ddae11cfd8080b6e72b1ab01e476779b01fd72014bc379e636939751a8547d44e16a7344b57221e4e59477c8325b6b3201a7f02f4a9b5c1c280bfb0746f011d84c1ff9c79b9b791cca1f64e93986eb3aa42c81fb319ac173dba4bea727984c55251841466e5e757c67be24f623433f1a5784c3bd1240af7afdcd5dabfc5945e85c7e33c797746896ff56cf2ffb1daa689cc45dc093cd3cd16974a7702580d0fc57881fe24d837c28d9b2bcaccf417f938180d67e83dee41d9a4b42f828f53cd9313e8b8e75fcf64537cb4264c411b8043bd81316c5f883dad2fd38fe41c160efb8d30e71db64a311ad87c1730322f48a77d5bbe57416ac51bfd60c5bab3011018e6d25ed68f271fcfd73f4bd2be810c8e3da310f71192b65deda9d79b069168ffe05cf444f2dea1fe6cf4faef2c1d55a9a0998f4ddb6f5c9bb6cf1bbac59e7455649e0613459f4da3c5c5fab2b78a1b93c6f36dbd32c92c91104fc46c3dff48df58abc159639512c88be297b8b735d6153eefa8c85b34fb17d7622dd9e6578d4ad4fb80c616a02fd3201be2e969368307f65045c67e44ccc3ebb559892831e75cad0ba0e1d3ab1a02e4cba46cabcb94a8418c7cace3b5f5696923977e85b43daf8e5ac7849628b2d97abf5bad07b1e7a114cba65499e0cbfb7dbd50b14fbfc98c234ceaa28a27152fded1407e7cd99cad33cc298fb9d32f03af05749ce022d73cbc0cfdb1342ad19bef4e5d1f97a99ede2678812c93d773f62f9a81bebaf56b075f18b8a3a6b3c1b91c94233e102317a8c6c88b0833d1e852f5a8c8af1c86b887043ff8157ce76ddbcb1ca113d5c284e7894b27578c7490ff4f2baa51e35f6ff4873568e15a3106c33ad73dd586b4a12d812677cfec3b42df0e943cd085654cb031e588a50eabfbb945efc96152cbc8bea48255fc1596dfa7ed107107d07a608dfcd58f5be49d255523bb23bba79c22f582fdadd25134c56050ef730fd0c010c902d0afde16b125a722b5212b9337a413eadc157a2737330fa0a8565d7c1ede5c6502e4918414f80842e71a7a6048543a9e61e49b67d7de21333479fe43ef30843c28897d1d53948a5d92c87b2de62bb076147b4de04ede2f8669731116fe95b975e5bca64f032fa0627fb2cc3fba548f23247b4632f0d457961d982f5b8717b2150f0e9dadf0e8942ff8196d813490d28c0b28387507943753c7919c4cb3a4dabb5943bea03c844e010972bbbdf86f2db7579c2b2ab8788b614b17be6fb721978ffdd3f3a51811780162161614aa6351e7f1e890a7f13ef7dc28eb4cb25231b92a000cad8ef265577f48ed9be5ffd58486f0b0efff88115e23b2a5050a07b58676c115cabb15a2c103f5801a4c286bbcad5deb72ff2325e45add15edcf421b11ead72dd7e86981af5c0d37331483b69284344c43ccef6e120db1b47c5648d6175aba7fff3341ab364dfd109ace8bbd54448e424b8bb80a940dd1b8865428c23955cba9bee9ba83ab4cb067ac3d706d95eb36fb87e67c47444aa6cb76112bf213341ddc255acd11834672c8630daaa764ba9750832faba54daa93c20dcd3f188c3641d30f719bbf3d1883b4634d9e055e002e30df8f436e1480ac7fe3ce8a845a46414d09684023555e62f56f5d2aeeccc3af82ea4993c02d30fd1e7d5fa5bee40cde77b5d91b2e4d1641ece2c79e9629c13d90c7ae29fb57366ef1a8098ee92f6f515d3bd9f052e3b23aedcb79feeae5135129d88a29fa1338f5b73adb26bc5e1f5f5892e34fad015e54945c187fe6e3abcc3852dc42a599b527135ba4dda1776f05c5f3bae5773fc99b281ecd3b5ed92adbff9dc54e3853a172c745a99113812eae3bb9fef5014d3e25dc41005851edc093cad4ce886bea68004ceae5a6787e8cd81eb855888f72efb2c59c9f78210db7e0f130b3d7c5352549e0aaf4092cd174be428c78ba235f8dbb9cd9cf0b06f26fad9bab87dcd08aabdd40bd005f756218017e02cdb3e99df25ced8e60d7ba0af9bf039903134e0cb761be0fff9a8e80fac094612023fa0b001df37f1b867f0c97303b89d89ec9101740ed03ab27dd3874b8d251caa12331e1a84d935fc60490d51d1032766cd641cd50351e4f8a913dd4042db831181eb2338d99b19bdfb37e114e9c1e7a5c9fb62533f73aace0d2b6950ef0b36729ad3aa4cf6e916116de2b227187d8547ea666878e19b82076027cefda2e0671972854dc81b9854587bcd1dc7e8e6e6ece36a6a1f612d58a8542412204a09ca7b91e57e4ffbd886f4802fef20f531e4a99faaa01589bc4f7ff9755d3c6e8e838ae56c7eb01c52c418f9501a4596b6e219727fd0e955fa322a5b8f96786477a77e26adfaf664b380e0b62b12649ed4e7f343e7a53f5953734b2db89f3ff0480ead74fdf201a333fdec92e56685ac2531974e0c32f6b38ce525b01657fa77badc73932cd701efe8fecd96a6f90f1f738097abae2b681bc43a0daf92622e990e9424a36ae01ce280ff2f6da76d533f8968416c5357ad40cbdb39ee41d7081f2e755a2b6a7116a294cedea31d186f4dc0b40e9b383b9cdeaf99b7b26cc727b1496b56444fdd815115ce80604f22f881b68a6927bcf36f34557e99f7ad11fefc93b2cce465a63a15a4ded07faf9e351286b317bcbbb7b57b739c34c85237b054e3a423674e64203706fe1d24a9f3d071988b7b3ac847020352448817d7c4d90cd619b8d4fb8c025fe05104b746acaffcb96f0f85a9aaff62fc44cc9b811eea896a22d68bbbbf9e54221efdbd0a7408fc0487d13528eeb66bda0256b0ea15ece241693618daf3de2165d08376c51542453bae70e711b861327cb6fe5e05b606af2a2357e9c5aaf3319c51f87da4cd390cd9715ac09232d1009e3d070a1170993f0b41066c1be85e5a72a044bee1087218a3e740170dd0c3de5e6c6be127243ac490baac1e54476a6f622a80b7e7ddf89624ce4d589b76c66c8bd7ecd3a1a6add51b38d9f2ac2c2c348210719b2af5a521315d689b2e2b5464455c7e9aa528c0cf2d0a3ef337600d271adae8a5aaf1a856a7cca627c81408ca36323b4484aabbe0fcf6c716ccd1070a3a00399a2056f96a0058b4bcb3ec49d6c303ae96fc340c21e3bef62a1db8d77ca8012ee5b5bf96f9fa05eb08e8f5616b52406f3aa5895de4e2ac980b21cce62bedd6d3ed04cc46bc272988b9bb4d6750d914156aed123e08aed4a68df2077c6f8198143697fcc8e8ed79d63dd462d18d627124803041599e2833123b85cade4c1bad3503e9b6e791c0e5a8b26577d4fa748b4e51ae75b9e77ae7d17862b2e12ad3eba748d5cbdb0704a9caa6fb102c12a42e8ed2d02866459ee51daf7b439e6b13f41b92f305ed41319e9e33869fc7f1940ebd985f01ff330dd17a07bb1c84fed2b4d12ec630d9f460e6faf8a1e74e10aa9f2a400da251377968bad097897e5fcc847cda591b7fbdd93fd8377daf174ca0aab86ec900bc02d49d6e7ad08aca6c88454aa351c42b2790b28a50b1311079d11b4ba02f259902dde2aae253e93213b51a018c1580da57b0f49a111534df9219ab944ab36629231f6ebd5322684526d95ea1eb4d562916601b622171097cdceb43a839990803ae71517ac15150285e54c809b713720c4ed4de61a9427f4f4ff3a03486505278088291538ddfa8e792112a6e65f13c57ca7c7767825445f5c4d43a5aeac806b82bae6b61b9077a459c92e5341e1f172f86156d536662dfdc7ba2198675b1fcad23488cf16d32d06aef40b8ae280dfe7015df1f431befbe1c05e23344072789d61a12930e1c56d5d9eff7ff8783366e4abeed891cb95dda9c70a50a472145d7733514b9ae2ba8ac9a2cc482a4c96f8ffb54ea75916e87b1206209cb273df9819b2a5ad66553d9b5e5fb148957528809accefebe7115fdc5a9ad6e65af7b1c6aac46b5fe8c7ea585aebdae333eb9b18500c2f22e60ed67544e1bd30fe3",
"spend_index": [
0,
1,
2131649645,
4294967295
],
"result": [
"33c4ca61245d3f6ca36c99250cd3dd0cd41727253d849c858da5ede5ecde4a67",
"90779500f5ce8db89a47c08c7a057517d6f62c814093153107a03d98b30c05c2",
"6b7033b441fafa098659364a02ac2e95cbbee6a8bbdaf5ca2991bb731765a54e",
"bdd72df524ab04c74d98acbc06ec195bf33bc4b93ddf74bb650a317717f73391"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 1,
"Witness": true,
"Version": 485614025,
"scriptSigs": false
},
"hex_tx": "c9e1f11c00010948414d3e00000000000000000000000000000000000000000000000000000000e59e1ab8006cb08fcf73f1dc8200000000000000000000000000000000000000000000000000000000f1f6ce6d0097953b6a9fc38036000000000000000000000000000000000000000000000000000000007d1a45230031f6dc8c10dcbca800000000000000000000000000000000000000000000000000000000e31a9fae0065cefbeda6a6c30800000000000000000000000000000000000000000000000000000000c63fc07400097d994d032b7145000000000000000000000000000000000000000000000000000000002141dbb7002a68b86cabae3bc700000000000000000000000000000000000000000000000000000000a095934200235da408b25b2dfb00000000000000000000000000000000000000000000000000000000ac56b6a800e963231257a8f62400000000000000000000000000000000000000000000000000000000475e475600e2b549f601179a5db6314ea84bc865df5c0f6ac5eae793d0616fbc788219e8db4e5466b3db1f294fa29aee18da2c58e1dae9d4efa0c413ae6be6cd6f149d4a0a192bc213cfd6e3e56fc062ae231a497a940d6b3e165046fd39b129f478896ed9098df5036fa6f5dfa2af494d2cccfa14bd765aaac1b2ffcda4e686823586e5d9146af0aa81c1c61d46dd8ef11951516d957e841d8df0a7a537011ea5d2c0da275de77871b6921204b77215a9a7ed5232e5cbe6d2c4faec4f053d4839b8a84bbc02b0d3af82d46d6732eae896f7361a538717f4e8d77301267031b7effc2b58c3308b6c07d17b8d7b5f9d8f4fdd97d22b6fa13bedc72148d09e92384e2ac103c9fdd8287f24c8d8769f8ab7e78570a7303771be40b89ef19cab7419b5f67f2f31d4905e2140fd4346daff639d07ba1a730376dcf680ccd919cdb712190ad9a797519d4595eef77ad41f7129b577a174badeef18f6bad0e74b508eab661098e25c88eb6c3ee7de43aa205de5e3ae1ea914e13b5af00a29b9530dc2a4d7350957438411c6cb1d89a7ccc1f7797d450cbfe75476df523c14cd39020e84d8ef3116582e6786555c096e8c5e51f89daac206ed996f059f20037de043ce41e87fae26248d1ca0ecd53e8ec63cfdd7017b48051db5e7b9a5ba62f239b27794b4785103934e1e549d92801727ef659e0565278110d7ed2f974be8bcb91b4bcd6fb9c0423edab23f1252dee60ab55117942ab25c4228b0ae285188ab9a5947656f611a8e23ec3609cf6e1f3e1410af559839d6ac367e3eabf1828c86a6ca7a2eb9d8e7ddeeb2fa53ee197e8e0d35f998258053f17d6b478265842f583a5e8e05f11d4e20456b0c63056f8b7b43c6f3587850471dd7ab986b644dc7d99b1d3ab438673be36d2482cef1ece0dc3f167913d4a5b7f0a6a859b6cd70fc817849e06494a3878f812ff52099db85a0bebc8e86b0928628bcc0fd50ce1083ae2c669299551f9e6b953959d01262ff1bbe7e5f084a93950807fef84b0c450ebb5b8d889d4049be3140257d64e4be8f0d837e268093298d0bd0318b5a02bd5ff7fec1d30467609230dbf7df931ac8c80cf914785191f8395676fbcdc3f825c1d3e76e1559ec51afce8675a06f98a6fff56ac96c298deca324c40e60dbdac1ddbd91475ad9d4a48ebcc7508356e0cce22a37f25edb5217694dafa19a58b174f5f78b9b09ce2a6f45110b2ad518e9f4db533f4f492a6a01e14b5dffb188eb4c55518f07ddd1cf2eb2b83e854a897d30e4680e7b054a9476d5ef83052fa42adcc810acbc65cd6022fb6da2b84125fdac01a342a1dae23caaad4d16b3469f44e9a7b36f45a12e3411af6253a2b072912c899d363f2d9ae0f5e21ee8538298edb140f3cdd2593b8004de075afb13387b7d17320300d1c27d6c4ac8b8165bc2b6357b73169aaebe9a17820e991ba02340f388fc9fe622913183eb87e543004a1a67140892503b2ac532cd80b73521d85db5c582b97ff4a628f96627777b0d83b3b5ecc7f056e06db37d29efbba8de3f7569c55d79000aa24ff70858384db9d6e9eee1b02034dc0f5ab67888e5dc9d4de12f28049e79eb21613136c1fa69a09b9d74de7b94839a5ff916545318769be4180e5ff5c15766f29c552f181d88dbefddc5756d4ada904895b4e2cb9d7506165c40a6403e9f467ff22e98f11cd9097c83394e37090f3fe8ef0761bc9ca96bd1491f7886654e931ebffe8cd072b772369c3a7a37030c9a75fe950db98972920af52f6e119c477d58659f06e50c088f43218e34e5db754ddeff7789b7d955ac856645a445d2a19b4fdec8963ac9bbdc2af4e8aaf810eaaaf457e2a7caa6dd48e5a879457704a6967d7316791169598cfb3fcb258e3acf2e667c020b03126f3216a38bf20983d902f3accc14a73e48cd04fa304393a6d6ba343e96e6d4eeba2dc6ee41451570b1f78c1e70ee5b63115698f21f52fecb014ddd5acad48b3c71c7e1c73633a21ff89fa707e294a1094c0848da8662d18317fb7bf2f166e37d77073306e91158b161f840d2ab01c7f728f33890b329000a6829eb41311443c75e29d4bbf56fc5620a2d1cfdee67947ab3962423e00a60115e4af2ca2409cdffac3f5dc54ed09c5eff44e2860afbc0c2010f525e4071474ae65c075f5fb38725941cc99c1772ce3903b772a073e2436ac084fc0248f24b7e9bf1f6b12c316d0ef74ab4b3dbe410c00b42acf1e164feb59e28345e18e3406bd69ead142e75cf9a104295858a86b2caf14f4285e5a0fdda01618005338892559a941bbe08e44b7176ac88dbdfac6999dfc42287896d81f83f0550f1aad3db2c8e9ffcc4829a0e0f398d1b71498356e95e5941ff47f1e98775fa0dbba5392a3e85c4d187c8093580cfb671d3c3934c7c68479968c6d62ebe3d87867729cc6d9d57edd4c4da9ec3f62abc81423681f4a270b84985bb0d3a7a49532ccf5cf0d59d715945acba916c95389039d7c2efab83bd37bbcbce1b54cc39b11565b7a17334947e9c61efde89db023f9b23583371f6fa02d094ba8ee91426155c8651d22959d145ec9c77bf47a013e6497667fe9c2c12a667fb0b1b26ec18853a2a01a0d5c5251b4a0d1cb74d6f05423954872cceb8eee7ad47d802cd528eb0f1a4ad7ca489aa55ca7a676c9007c75162407640d4b2551503ea5c71ca58c600800c10c42128d24c25853077184f111ff3682578563f8b0c2a336644f2f1efbce8d2aeb15313f8ca7e92229cda2b5c628c3a0b3fd723647e816ff5787f43ee4c4c8afa0afaf15e45a71e3e9cc035e4398e8e7e25a5a9ef15aa1a5c8d54b2acf5db6f612afd773c156572bf2eaec9e7007c3bfd481508a35e950d596c266b836eacf4b2fdeb01efdcc3989ff3ac37eff5c0ccccae94c05eea3242b896f0a7037bca4682f56978175f2bf8dc7d6b1903374a28e71ca4702febbdfdf1015dab9d79165783a3324ad5a624a941ebd4e126e4909f35057cd46e3e2c2811e9d2925d27f9e4612e4c61853223e026d8f3398e5ff89d037f724d2908a7fac7c992980fb8716722e632ceaa451c141273625b761bce8add10eae32e310af7d05bab2552e70c5c9109273a3a2b4d408acdab7a68c9c00611e4616a29e80ecf6d3abaab07903570609dd943f8431f3701b3f5d65a957089335f73c7bf3338976337e804eff75f6fcca8679b6cfabedccd7d0201e292113d6fe20a8eadfbf23f56fbad98296879bc2083d1e6caf3faa26842605ab771251705e1263189dbc5b90c4b94b7ec1b7660e79882cf93fda08b62edea32947299b59ae61bd888d83559de50883c0e905cb8294500d60df4a613a62f34b00ca7069649a28ed88800e9cb148556fa28e45f50ee797da5b83afaad49e48449ab392875e4b6a80d2396a188c2a9bf47ff04dc7a05b604d5d044417fbe3de08f8b7048ac651c6acbd911036c16eed7baae9f5a6f19450b2b8f5f5b34b30a2ed28b6a1d51a89af31cba4d446a9ff18098dfb93a440a20d22cb06adb2916b2b8f79cff5fe916930b1ebdd42e12a3917b3fc7452af7c0d559bd00582851e3c34277c9bdcb50cc376ee6bec35f424aa2a9204f70b144edf20969a2cfcd209e2d7049ca419bbb0009a4c8d3ae67f795f7eb28d4bbb0303a7c4e71c9918f065468fb0cff6aa15ab497073b24b889680001fd1901894a4b3923c046b76fcd3d6acb61f8926c3c28b479b7c5386b017d8cdc6a4982d02a5b1a62e57bfe2bf15058cd9539146173bab291389f395e216e669d1831d6b0f70e7352573ce1166ed134b68253090d841d9503ff58d0d6d62bd9be62105a56a05738caed763f3066731ae907a033300e3da84c2c091bed0fbec57d034a0254627c52d9b8f28d87ddad29bf3ee2a709feaf4d914117629104bd0a60d7c34b91d52b0cbe008dc28d0fd3aedd81ea71fd8965c9be2e8bab0b015511671ad05e5bd8dc9c806a041018887dc0cf2c27ef80cf1aac1d1b345c1d8783e53702ca40d0328ee5f7b4118cc35a9608fb793d224495630c8fae050aa9fa4c6f25b367033d98714fa0e85a9155b084fc9fa7f6766713189f75dcb91246027fc00ac4644ed36c0cac7345bfb24f7462cf2f62fafece0ebfbe5a92ad3f2a7cb377e5bd64c5d785f7bb41447cfcbe163d0e79ba2ecf37f09c44209adda4fee988e56f0cfaa23191c0092c86393b044bf35c22857b69ff858a5b22aac5312c82f308debf2d5416014850d3302636feb72965d73c4c44d98ba2833bf5817e8321bd7d80dcd8762a5db570eb1e3168997f1d2a92554bfa3d8dd33d6111ce44eacaec37e1206b165c45d2e497e5c28b770181b52309a5a2ae28c0e19e33609b4a99c39239b80327ba0954d4a19a1c1325175f597e7ef5e4b4243d66e2b74e6438ac8db31d010903f131dfbfc0972bb0b4df68e4709eb0757072f4a7be1c6082cc91b85b411b20912d7245e7915767f7f0f0edf381de2ed411203cf323adfb5ef46f9abfefdcc70031f6f57cee8b6423c179286d16f72c69140adf47ecc8007e01fdae01bc9def0c121a1918904ad846f2db2dd97862b172e285cbe7018ac93cc5347a63bf8bf1a18cf43896a2c0c32b9eb96508dd4e52afca94e2d4949e238cb913de37fbfc8757de6d7f1622e1f80a9fab03de82f5201269c234e43f7e7c77e2fafa82196a5cf93700081a5629d1c1591aaf0dcc533e7aad89f11e195ae106d9164d83bc117d330b0625ae7ab914cba3f5e9efa4f0cad23f6b96af65834973e023387e1d5168dd25e42c20efaf1fe6f6540c04c698be4a372e26aae68e57b264aa8b21e35e124c89e72481a32bd69e298386d8dbd2f837ed5b325a6dcf245049bfb304fb580eb9ed2c0e12a70610676741389a241b0cfb07a2df412d5b124b7dab5381805f0c3822cbd4554cbccb27c2e42f8275e3636c0629494c5f592f256e3c026a193c3bdff6b78c5aa503dfe2e15561f0c06292e1e3b176e4b581972c957d2451aa8407a6566b4af1e4799d9b8a83de5041619cf662bfd50e7a36ba531a48d190bb2fe007b93d5de397fcaf2e6164480d3bd6577d4b6a63be31b3e0be6eb785a00648ec9deed2d1e7ede249ad0eb2d6635b507feca5e54be1786a04eb882197d71c38c0d11317526d8220047e27b8000005e515bd",
"spend_index": [
0,
1,
2773995730,
4294967295
],
"result": [
"17a26c6ac5835fea6a4d6768276d43c6d364e7d4f8640d81d9b75ef1a1f38919",
"9c69c5727e1b331a00f51c90399781644cdac61b5e6e50468364558f29f922f2",
"70ba670c7645b244ac7116bfac53c066f9aa483f5805181e601b3a0453e6c506",
"3063e65347d8252812789922643a202cb5851f8de9506b1fd6b22feb389edb75"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 1,
"Witness": true,
"Version": 879929405,
"scriptSigs": true
},
"hex_tx": "3da87234000107e3d9f699000000000000000000000000000000000000000000000000000000000e02a8e129f17bbd3a719e5c419f786ad2cb5934b82905ee6d9773b0a2c224c9e61b43ced03d3f387560038684aed8dbc02b8d7e12960000000000000000000000000000000000000000000000000000000050e6e834156282c8744573de6a676668c7d6cf7deeed37cdc6df31d0964d339f715c00000000000000000000000000000000000000000000000000000000066de206008ae386ae69c9456c00000000000000000000000000000000000000000000000000000000a4e18cd8aaa758a30ff2ceef19b9fca18f10f62ea82e3b20af78e1406107eaa1eb772f4c1e92809bc9a0c10ebfe2dd6ab865d81936b53cc74d00ea45139f61d1057d3e8dde146a1a4f9b4dbbf5fc794e43ec5db10abf1d8ce61abf55e3eb5b3d9c1e48aae2a8791cd00e36c44e36d2a7292d79d2c6846d4d68d326dca8ea48675a7a4072621357ffcd99bb738b16a4ec35d8309e2c3b52393801c9396032a8e7a18705356a44372fbbd014d1aab2f255ec7b5712e2281b000000000000000000000000000000000000000000000000000000003d0b52060024eff817d8b6370800000000000000000000000000000000000000000000000000000000146f8940fd09017154e0794010287c09ea7938690c178360b6fc93b4e491958a1f54135372238c5afe7d176efcd03ba54df6ca8b09a675d776975d060899c8764216c8a10b7687b368c3e05608800c12d8e69a26262a1a9ac5a975cbcd0f399ebbd649bcb0352e2e45390d2e653eaa5d4fcba293df4107f0d994b7cb28517e8937cd728697a7f1960d408f1030a02001d7abf627634eb02d28b91f5fc6053f937e5ff9d520d9cc90fa669ed70e308560abe1463127e47f2c00d42a5e5a9129e5e70761ccc83908be832b4c4087e3cbb8e81c5e6b8f41816055c2e857db3e5ef3339e03df7b29ef4593cbed65d6b386844de7884fdc01126b1a2ffecda1905c827140f566c5fa97533a6b7fac4712e6d27840f83247dca51100000000000000000000000000000000000000000000000000000000e033ae24fd5801a6c7e03f06d046f97b11ffbe34f85874413f50c63972e2ec801988a6586084d9345ecb81b2e539d96fd52f52395d6e52dd0f1a958362f7311280c8eb6475b74b1381a3fc3b8c7be041c01517e5c1e9c55d10b46033670794e09ecdf1d22b256ffb5b949dd130d680dc2bebf175b3382b97884fa21a1cecd329361ea6850537f5a40463dd36ef90985f1f0d73fa53a84dc48ffeecefafb64f7ba63b8d10e3030a6a1e7ca3ad386d88435f236a5e0669b64c045ea22472dc2ca1fe2d6345aa26c3723952181538b3c9f4f821ad14669035168ec12a6349a25a5caab4056ff3a12651ac3612e1a7accfe16ce6f8a4633ed214145dc0a1ea425d2b57f0c7af659fbd47093e065cfcddb2646cb4396496026832448f9eb20ddc25025a1b24eacec73a56bf8d953bef2a4feb6ec7005d9557be1c9bb1ba9f2f7782bd2162fe9011a37cf058edb76796fe293eea928c207ef3962d2e5a6e1182156885b2e4e50199a51e28b8f42f38c8dcf65496688bfabab447460b3b8c03605e1caed09ec1933b59d7e80d55d7d375614a5d809082b5506072df28ebeff035c7b4e443fcb6aea5238fac882999851e13322a80b56333c13aee8d46e659751a435de60191d7ff6a84fa3b4b99ea066c9ed7a4c31fef447b22a6f4f946038bee9e64dad2a3721780d452bda78ef82864afa74c6b57068df83ea06c64b0cd56d7ea842815a989e166c6c9101ce812c1fc3c4cbdeb217d59ac4dff2a84f3a6b7e183e6ebcc04d6f0d918be5702b73a14874426ab353c489f9903fda301c3cc7978357621e503e46fa82a2ebbd557f2dc43d40cc5edb212242356bb089ffd837c09958970c8beefd7c9055540423cf13398353ec1190495b0ec26a64bc690082914f40c508754a281337ccd04bbaadbd179cfcd093cb8163d7c542b4dd5aacfe07761444261ebc67e612fb11ec447c031a06513362de39c2e020e8ec2bc2f4bb9f92b4ae1a1b89d109cb2ab034b177f07840139f2f39dbbc2614559cbfcffcd9153bcfff7df2dc946036c6562dda1dd0ec183235e49dfa049161c5b723a82594bde07681443cb9301a9dbde4775fc7a8df326be0b0119e7bfb97c68b325d15f5cece4169ec52e0ec0def4f0ebb2dd944fc8d267209d4dfd92d07917e0ec0e4a82094be02f8ce71a756b3ff6b90233273198b397a2a5ead5d9a7389bfca6d8d577e2bd0b1b62d719c296f793c2edb25a478eb36ee82f0ce0061145ad555258be0e582dbaad2017f31b4f705534cb874fd75d435acd33773d1f72e58d64d6901f8377db26b5625b8db4d0ea2728e47934e1506069211433df2124411bba5aefd45d6d5f1089a5117a5d7c86eedd6ccf50dc38a61d1c6c754f66d7319bae4af68ff54f5774260f059631263b80719326596d080a389a4ced0b056e34b4bf1a1adc582a925e36b35095022fe1f34afb3683e7b47e22c9c7f1a9a5a1b7a5a3d0080f3ee66e4e3050177f1ae9fb2402f62c665544cb32909fe85dcdfac66ffd8f5dc28c2869aaf0c2130be293a13b73414ceae0805d37ce49961084d34626ab8fc8fd57edf9cec217d2f5c25949b13540c60c27434118b4220437bf7d40d1baa11ba9533b04641d7742a175536bd7ddb66961a4043a9f05c61485c0141bd38a5db5e20d923347552c0c750bbc72efbefa53fded013057c3861415e4b829aa3fda0d7bd6db680c796d4802379b1f07a831ddf87beb1c0626c97109f3704d451d10980aed9daba4908fe96281e22860b6030ddb3b10c4445e325b92c28b75900dc5e4b1a62992db85e91f2c9443e23c9029af2994787ec03faae38d49c525885e8183fa09e1012464e8c4faec0890d7de43b0432b417c92fa9788fc54842d16af13be204704eac6064fc6bc41aacb05a8f2cd7104bd3f779ddad20ac77c8cb47eca14be27c25e94d9704b527762a126f5fd91626391ecac9a7cf74437ed1f99d12d6e47e1af0a6cbdcae2c5a771e1a24809a981a51de6f1ed9d3b623a48cd4b11c8629b256815b754b193de7a19ca01897771aa3c84fe150cf2dbac86b78a3af53ad743e23d1d5d58a5b7eae918b28de940ca4566b591e3c3052880c1c9ebf603058f8e7a82e3bee91c47032d04fe0817a50f7fbfd5989410dff894cf9b60189bc397b1c6f4a48b144233c6d2c8eb0210b8c53a2700280365dfedc4674e6779c5f2a2a0b68df2a4b25b4ce3f85e5fd94ae8e355d456ac8c076c9bef88fe7c67e409c038cb6e91f8c1f3570c16a1c1a0d0d1fa0916d07cad7ba438e944c19b3f378a6f76f912153c65055d9a68284b2f6085225b3f214d7da32dc3b2c13aaa0669c0be90a5d3e8d48a0188f6fea28e391d8317e824e631482208d8be7cf7b18c193bc22bf118746418906fa4e23a2d0bb7b388c89583c0356a5719b0abea895fcda3f499f8791a9bdb60c77d3c0e4dfdc50156f33279ecfa8b078776c7008c26162ced7244a31b08a5b371c2e2b6c5fb08bfd64052a447286984eff0672c191af0e357bbfcd8a91c6e9062b3095995ef09695dbc9a4a7fa79945b0c935a0ddecaa290e0c31ad46ca7c9aa27a91df67d37a0684cf6c8ae4716ca413b2c584033cf2aa1609ff3a57987e690fdd3d480d765779ebb9794d46a415f288fc2d52c6dd584cc265b746c60170bed30c33deb13a58118042e84263238f0e5076f7665d288fcfc14fddf06310d3447cb96ba1dc19f9ec8f63a258ef76b8ff6e9787792127fce45a78e9bbf042c55a2c7d0e2167dac6ebb218f7844b2c9aed41708c8c478b0efc4936460bfab33761d4c2c4f7beda53477304d7e0d7ec0cf521871adb9cdd436b9457ca7856659ffe869a6338a72650cef63860880d731a0d3ed51a6ff7f1d6643d8da98b16713c7012badce39e2aa0f5d19eb86b0eddfd81c39974788c95abd732ef93d3ce7e533dce0d25584d663314176875d1e0642e4858c19df642d2866b92e40e683727a14de01775dee9392fc12e52f8e1933ce98762e8371958c61cfff86523161c6db101e9136782da819502567fb8668ed6ae4a4b3c00eee9d75a710add723458e9cd660bd7467db8570e21b3e295a69f02fddf0120b2a480076d8ca3273de406cc7229525423c9ee14db0e2a5687f5d93d32c32717754e7d97fc553b0759f77d7efeffb969dfe0fb539773e3b8b2f1108e0bfe506415bcbeefe5a66548547e4982c4422b3cb45d17a6c928a82aff83361f78563fd27bb68bd1a6bf4ac80c4b455ca5bb28b07b52b92f398a693d9b0faaa91a43b7016df645421d50c863f3d284a5ea75f262fd958db498848160bb5776e72b1365fb25568c497b4554ef56fa153851517c328b8db1648074cc8b9369dc46f6e943e229fbe80c51820abae660c8109e6ec19da4cf61510208a7082782da275e0d5a54cacac70feef115d0f21947a6f672e8b992cf0977c2f561d1fa8ef9be6f9619ea8f603cefe04f53ee88a1ac46b1006c7c589d46c2faa71e4098fbbee407646fb4cf7b148ae107a872afb8532ad7b64c0cfb0a7770b4ceba4c201174b11516a7bf6fa051b331ea6aa928f0ade68cd5fb530a3d8c456f4f636266040e0877622ba9bffc13046d82dd158d5da579b964c73e9789f10ca9f63141a48453a61a454086a3d94a41b8c78410b13ec39e73330e6df0476caf5f0f5591fea5689898849a677440e3ab812b640fb103349abfec5e7d96f04dd5f2cae03d9bf927a2ec0477e293794fdc92ab43c620bddae7a44f2e90d33b0257a5cef70993a3b5ee2674fd51012f9d4c699cd9203ae3413599a60a3d13be84c07ea13c7bc9fc86b549efe917a0503df95aee8b6f8c769bdf671505113bee89f968da307658417f90a36a81eb36026ad3aeaee5309a05edc8519a21a8c8b88fe8d9b5da019a299b63e6a09be76c987616378151f249fecbdd1cfb237a8dee3bd8ce6b0f8de13d48f499d2dbc9aec4a5a38666b475034626fd9dc103c5952ecd1a54365304e3a4078246c723b72f8c9aadd4cff9267ab74c35412a005e42424aa2c77fb4ca11289f95b44541d9e29692b9d3934f902efe12d4e6f7446043f98b159293c8e120d7c1d2dff9b13764af85381952e172727adbc3fac1feedee324b79e503d3217eef8b47a2e4ac29c7e5b51fbf4759d6c84e8220b649590970d69b222d71f4a29cbd62bfd31110fa88932392a6f6407da69f88e16587a4f9485a2f982db8d21861454c1eabfc0b57e6f37f470adf005232fe5ea38bf7870a6dd302fd2e01218f2eb08ae0314cebd3ab6f1ca408dd789bb68c4fcfbbd003f22e7f1f0a56de9c0257214559b944ed7bd6ae7e77ac4b2456fe28179f38fe65eabd55b5ac6bb0c5dd7a9df2b7df7957b9e238d5bced728d294edad1fbbd9ef6cb3d6e8573469b0c5f393f262524e45365bade9e016c27f33d06fec702e9aeaf350b34dad52a4cb8a58af6079857c692f89d49699cc6527adeeb2ce92b290d8404e175b3d682e80b6a7311aed857dc0bf1f34aefd63304718e36af6e56a5eb420f2953d74be7bad471a979a43728584c2f1451cd210b72bd0c33ba904789fbdb6a26354a5558a1a5b5e532b5b2fbcc14a973bc8dc3d4de45c0bba21d578423fcf78e15fb11b20918502f053ad3c7edb7221cddce74b4216f2aca51245ec87c3575a6dd07f39c5d3ef715f0599bc72a756ae9653eb311a7b80ba9876b39ef4a4c168372ae5c616701fdeb01c8e175b9c8f8df7855306c601dea40508e31f9222106b54a071ff601e88c5c237554b1f5d94474ad30af8f31d53d15c1fdb291f82060e0800957422aa0a38482c06da373a2e6f3110c0937ad4686746d8c5615575c3c6a82fb8e7a2066b561828c197d6bef8e1416205553c3057c1a3eccce56f5b265f325ce04b3a39fdae44131b427048b5e92b4af3d7f84e0e4ec67cfa9b7b0fb5e16eddd96af14398a8d034ca87d38e33bc73b47fec0be48f64240d08f409cb005e9b2c99b3964f6cf3d0b223812c881f3393599df843c2ee7cef58f5bb8e621c365f6d471ab896ce890a4f9a9b2b1fc08db1565925c5aadb9978a4324122437fc96240ee138d1285b8a72866e9cecf3a3cd845f898c0d064f107735ba909f6943a89c3b347bb6c6246c7793994551d1017e9f81bc336a74536fc85f0aa37115aeb89edc84c2e19685d7339c21b194bab71e60301f0c84bfaf22ce591a1c29e75bce5a881b196ff456aaaba13b1a6e3a3374ec3dabcbaa5f1069557b0f45499d069ad72f9eaa944b9c2697ae39c8f086f68a64e38edf53b142d4700c5ef9d8362261c69ae7f1432321c6f6ffaf5571f009f7e76ad7056dc9468e971c96d300bc758c53d888f6e3ccd7ea3d807bc32f5a75c1d5b86fa4ae2a57bd06c60283d707a193975a57dca75d94a1bfe489be6c04e637bff5ddc10000666cc47d",
"spend_index": [
0,
1,
418482803,
4294967295
],
"result": [
"ba26e6ce9adf5b16d19356d501b84d5abb001097bb87bd903cfe0ae1d97cbe82",
"cdb2989c82559c31ee7e9b6efd00d87c51cb67efcc371e2a8839a5f9502c0fef",
"8afa6f573ea8e5ca2aed628fb6cc8f58e730f7179d382bb7f4311f0f205e38e5",
"034eeec69918a72106275f882d5d75cb3ee4d62cb8b302ae70e7178eabf14a1e"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 10,
"Witness": true,
"Version": -709681065,
"scriptSigs": false
},
"hex_tx": "5720b3d50001075daf918f000000000000000000000000000000000000000000000000000000007da23531008a997eff90dece7500000000000000000000000000000000000000000000000000000000538f2e410073621f9515f3f0ea000000000000000000000000000000000000000000000000000000009d57505300e4d08d893086ce3100000000000000000000000000000000000000000000000000000000342e363a00913892234ff4855800000000000000000000000000000000000000000000000000000000d9606d2100c8886846a67bdd8e00000000000000000000000000000000000000000000000000000000396bf93600f6c564ae62a21338000000000000000000000000000000000000000000000000000000003175be2e003a75017e0aee23b71d09d01235c865b262c5ae164cab8ab974a731b034427f663ca7441d234e0d2f3395c8cd606f698096c03e6e7f16aa89cb2ca5defce9cb543ab636ce563fc76efbe4abd1fda808d607eea2229b3e5846ddce5234a4d098836ad5a0e1e385d83d5c093fc8762d99aae65acf2140509bf0b7ad5fe0d7518db59e12dbb02a815e9f39193abd9d2f90cfb24e989181eed2846ce3c443374d2c869b33c4c551dc76d5cf9163649d0ff11f0f307486e72a62d848bc8e7774f55addfeb573df387199390e0b17233d2d4c8fb52f6664d80a8c4d6d134f581e01c830425a7d6b904744a85df661535c10181e8a20f49789c674666627e4845a99e9b21ceae2f5fe70f6fd9d3b5414f5890debb6a567d8ff342e948a116db25463becd0f5d8bba1628cd629ad348aa64c88a98a38530e9b21c2725fe7bd303a1aae9dfc662326b9ebc416262b6bac942b9b5329626c16dfe2cbe94f72361b741089f3fd21203f093bbe4b04bc3fd88022db2339267d467ae6168d81c42f3e9f44074809bae6f7360ebe955473a557bd137ea22c357e25b2189726a5733aa13623e216b1194fcf2c13843769f42703f01ea54c86c66abc870200268b937e5a4e2d1b26c3b81d83ff702fcf271e2bc33f27b4b6dae4c9c14ae8e9231b7cd0c7275ac61d98e00a53820a4535fb4ed6b3c143d501542d5ba0678b70782aee279f4d5a1d8e72994df5637634f6af86d7c63f47b86ab4e0297577ad2a3092f0319d9b11779a22c1080fe34254f4459a73683ade01f149c3501253d63d8374670a74da878b372e9c3ab82a52c8ab3d8e7aaf0729ec8db4fb0edcf39c057b22ee92e30b814a5673ce84acf82393f4b6869a6a746834d118d96af4e47cc0752da70c687e65ee94fc8cf5317206c7db7f91638c9b040137e6023b74f68b8126952b28c14e4b538fca65fc6b1739776d57d47086bda8dab6565ca1547e4d18f524f3b204064d7cfc19b56059fa101ba16d3969f9384b252f5620ec5c18c934a3b23b8bc3b9928e6e782e045bedaa8021586f13fc37fc5afefa013fcc4ae8d80727e82259ba2cce5cae5f05d725732d16479b95fcb2bb93288263079fe943985837f4fab845d1ffe45cfac9ac38480dd1ba834780c27839ee6c0187277e0b621d609dc0416f1707385e3fbb68b2eabe5774aa6c320e60438da07c8e1ee0132659ec1f972ebdb16bd3484d220661a09487b9c03c480052cdba71bfb1994931a6c2db1502e18e0b8e9981ece76095fd881aac299d74a48b0aff91eddebf7f98a438842e5142d4724905a47968509591bd5a003448e5e3ab3e1cede5fb0c40e305c29e44cfe6f417d128054d34444eac07f5bc4f408fdb66cde818774107852e9bad1bb19f78522ef925d42baeaeedc9b26483063c6d6274dfc16987bf0a32348588a6d45632797851b4fcdd5ece841bca13680d1b422c3f82fe909d9c5878032f976ba802176803cb6792568c82e8403ec60d535ee113d1d888ad3101ebb786dd30ca50bc8e3020c4a4bf1827f8253cab95d1a6a23b3ffd6862e6715626010d1db514213db2f87d5b6172cd804ee9d1873602b023174c9b4f9066ae77fbcc506d83e9bd2c39a55cc8f19956d54f05b88ff5b8bb707e829cd8f8b085a485fe49acfc7939ceda32f8ade36341a9e98ef5309515dbe57b9b3a4aff3d65558132bca792f626684c82764f6cf730e265551d737f531295713f4221ef5c70927be9fce1ac39e93bd30ed1c2e19e9f474b5cce0771b464795d21b59cea8caa60fc8bf9391ac806671d443cdcf6e5e07eceb79e0fb4f0b89f654afe3a0d59acf673ed00a641c600086992d1ba6cb7174e8cca3f1976c7dfadadc5ba544851e844e030968a67bcdab64f5753d2085171d96e03bb4529aca0ac41079a81987001b59a564542afc0f5183c30d2f14e6d8c6213bca6d649856fd6400368d3386db1540198d74445e08acf8838bb7d6e05e8dd7385a83a7fa0809a1d715b8aa324b1438a7f649c48ba08787ea039bc513d75be634ac3ff1da177b8438afd7191b64f5c7414d2053531a6c98da8d203ba2ba25e64ac8a088c8688b78d1eafa977e80f021e86aee9c3f9514357888748887d16021068bebee1ae4e086a1c6c6b2ad8969ef2f091c737307011c5779f9722c4a8a2c0ed6b0b232f7412f296cf1099e8468879e822431fdc203c7e3e6248b0c45f674832e2ff53b9976e3b6fa1576050de3adc0baf1adfa9fb42557c574aae18fcb7b9e7ceac1bcc370771da3017bb7568df624f2552478607aa71a2ed66592db423145ccd1037acd9155aa4cc4de1db42264602606cf8d6cb76c32ea9d973ceab578479e1cb686d2dfaeb703a857420670bc5f0fc8d118dbd528786ac4d2141a231385f02cfc7693c370ab4d2c9a62bbd3187a425d135013a0171fcec67e8ecc5c393db8b8a08518240c5ae30fa6eb7890a84448ec714c4e6f148d9b62ea48abff19e039499ed2c90fc775062ef829367c3a1ee0ccd11697fade32ea84c318d9dbab2c94a28e57a04e01dac1a34391d8eca56baf60484724a6d41497f926b0c43003a85398941b8d97e95187c0cf667349cc75b04bae8d458da31381c709b7f343ab9c654cbda6478b0a0e1a71cc376da34fdd62d2e9d4625aadb0062d64c0b1a493057c4cc8a92ed4b0ff0d28793a6ccd4b3035d235d878a45d66b1448182cc44308213f0382f1e551ed559b15c5cbcd1d559432a7c2d6be60a1bdad2baaa1fd89a50d80f2155ba511037f29eae8a7d611423f9304e846af72bc3ec666dd1abdb8790592bae33c6b86150c9afa44accc72a476a390b14a59bd5de1d00a6b755096d131f6ffb17b4c276c32c2cfe59805f64b5afaa4793aba92001d970f5a155bfe97be3ea4a616227cc1481552f6f509d2f0a55dbb26cb47a7982dfa53b74ab328bf6def73ff01196b0023caf5d03ad941e2eaa3c07e5b578c2fc3d375ac33137a51997084f584c99fe97d4db97bc6b51fed7bc85a4c8cd447f19fb07f5099b7e24f8b9d2cc47000df906b0d62825743d0f077425ac885ce6773d3a87192237c50392688592027a7269e1cdd7c06c03920577e3e846e07ebc4c080f1b26a2bc83325c2bbb066f6050465178cd481b65f7e36e15f4bcfaf0fd1925d238a1c80ee2f689537b09128cd0f6eef9ba1ebd04b3af97cc133f9844baeafae1153a3e0aac978b23a528aa80d87239bf5efaa4caf1019424e928c45debe598ead7b769e062a52aae2a33c82a1afd1c08818935d1df635085937dd4a7fd0101fb14f58825e93873b9ff6cc58cacf3639fcfe0b08a2bd6709d58c03ff31486100ba6bcae81c64e9c660f613bf5cdefeeb1cc66983417462347050d6641e4dd83ff4eb40330b47a2eb58da9c4081e899a29806d25f0c1e9078508d625ecd5cd9d7678040a74072d48162f6ee8e984decd76173a3e73421ea3c2341e20fb62d7f1ecad494d041e0200eacd1a16f863ed3ea103280f9d8a0c0c007e397dd3feb8416d2f15fc40a59bbb1ea3c25ea641e6cf7da7ab3b15db3ef5c93015fe85604fe97e1cc19aaabc48ac4324893b70e2c7dc23803f03412ce6a995e149efc2af6f45816fbc18b3cea8039a433b0b4ca44c9870192171065f061d8a23edc994a3c190a00001fd2701742e4c31fbe9a6a948b3bb7dc501bfb242936b05cf023e2cc8737f90a2d7cfdc7ecd08174a286ebdf7db56b3886466ba473d1a8eb5712fb0bf8dae86958bde69b0efe02ec7fa8fd5b57eade65d944acf4e2c74551a12feaec6476ef415c3d48b464782136d13f42b390bea3f9dacc1c79def8b59f1b7a268b4ea604c0ce0dadc060e62ca6245a893e51c7b119b215e3ff31407482dc77e8a552841b16b37a0d91aa7d431f7a577d5e26bcbeb4c3ffb08ee83b2ceff8d200cca56e1cdcb4f4530054dbaa21d962852d1f1834774e82b287f365bddf56f1a23467aabc04c38c3f0180326cf544b7a2942594c204430d2918e2c383b54f306cd96525e5c613b67f1997c941f4b2b1cf5884b847c9542625b48aba16ff78abbf8fc01faaea6bfab8e75dce0047d3a5704fd6f01f3d69bf4d07de4ab6ce0c1fa299b50cc19d285dac8e5ffd86742d07119b3a52f3de835b0d9ba6ac11f7c3afab482024f476807dddc8e4eaf4f0cc8e959df06bddfcb51ebe2976066ce49067ae36249c1734d43583d4c2cee3514cd2285f794d7aba35f6ed44142da7a4b03d35bd479113d300db9a9eb78c596c021bf8d706e19e3a617ca14f897f1e3fc1f92032b872186aa876fab36c32038e6ea5a418f92d556ee7925a08b94a17cc5042fde4f1cd9c1fcc6a96fd88b84ee4a5855521c1e4480dd156a7cb86f5b8d78710d6c09c7b45e8fe99268a1ba97ccf6e337d18ade3f3a47159e3a959c6f3f9afe3d42ce210d703ddf7f12f03919e1b9d8396fa55f88b02a6cbecf8b7c39c991dc7769aa8e287725199ebbbb5d2b6d72b5910c719313826940b2b65212b89d40af36ced7ea0f1a26468c88f9cb9488fcc2ecb26d9433f4cf40d892d7118f534c1f3b4bc599dd4d8acac3bf315c2ed96c25c7b1c27f43e345f0c34133763ca673e94b4a06bb7cac555007eb8cb0065b64338430cb7abd09103be12487192489da6a656d96cd43b28e714a74967b9c6bb40b8ee39d3571aad5dab251f2e5750fd2a4bd768a0d3667f8764fce5ed82971812129f0d330b2b7b22622baf525cbafee81d309f95a95b8c5e61faea5933a810d6681294bc7ea6f879cfd026b5e172ba905ddfd940115a8a51ac2fcc8b256b9608da1132367521d508fd7565978b5886bf547bcb61ca2ef122508afd507ab19c28f6b927e1925d522c6ad01191588442f94573a80ec45c5f6e81303982e0ad5c8c20de87fd0035df40d5e2331d32d85253e9e1cfe0717d2f56e20625620a13a961fbdc6237fc3ca09faa939201b077955a9286d8c6607638f65724e3b37c60a0e4ef7623b0e7705577af8fd40def56a8fce3182fd3765adcd586f5b75963878d89b20d738a5962b3cd4e2a23739a5b89dfb26d9422c414c963c67fb8c9aae70ef5a5435575fa94848ec7efb742c2f7d25aedf2d143443a4da032697b55f5ba87f50e78168445ad8e1772f28c3f14f9a571b0d7275079ad8432d937384123fa39872c88d1a8f6b205b8cb47f305bddce550ee93fdc48fad3f18cd6d8561a1cfef9c7410dbf1ff254641aafd01ee09b1e69dfda4196d7285a4e3a8809cd498603201bb10b6bd640d307f1dda6c182d574d7dcb8dcc29094406245809340bd95d4d223f9910f8e0d9287585800a21f0664f19a10be0f0b987513d65fb2b088a0376fb4ffea57be528d34ac405e3699d7ea9e7383f03246137e35ebe578efbe9f939e850fa65c3c8b36de6233bde8844966f760d3ab8be961d7d5e92fdef2ff705e0498e2265a7a0efcd07b3c0003fd18016fb0cf85737d24ff5700d01ef9140a3bbde60127a020e1f87692969c5161e51daa74206dacdec9ba638f423d442fd7352527cd03696fa3da7d41f9c1cb620d1e6c82d72d9d07877781b671e7cd39caf63277e2869bdf0735a9170c8ce15c9474345a1a513aa204817d3f62663fc83da84ec7ef07fdaaaad7656da3d7ac4b58bee10d3d5b813be5c95a482811fceb6867ae4e518664ba3439a647ee02e8580bc178c096e93c02505bc8a43f4ff6d1e133e7f4c7110ec938d77cca6240fe97b74064824813de55cfd6bae2fa05005320093312bebceaf4ca3fe609e9f5c8a041c231b0ecfdd5b12c76cac786e8b3984932d225ece946d4a3ce2512c4646965ba54d59c162ae71383341a81c0b1591339cc8907208c0cf9d1e7fd540103990555004ed328fa827e4b3a3e14a3d1090e36fb54e7606d0645f148f6adf0fba1dc44587f2572d3307c23696ea2f189f1aa54c49e2e74d1827aa1f2b5cbc676bbff2a69754b0c6be65e9caa98275879a5a421996b212f9660cff59357af5082c7226c3ad864bde65f1907f3f0abb7a1000c3a9da4d2326e3f41920d21d5ddd22f5b04b3b45a8012b95379eb1e68d376cb182512a4af8b0b716a98f7a760b50eb3b53b30e17a9661603f6bfb52bb438d162b5a2aeb26dcebbc7182985d182b0dfc1835a4ffee8fb18bb767ab2cb07b159a333652ef15df7ddd96d22d2d246cb1d8fcb1f67976df9f6416a92098338e9173a1744bd40efe60357c8d0a742ed2c87dad4753b99decd40667f9893644e6956de0ae02d97a75fb3ae2f664eb7f6f4af284939fd7b7fc4c588e624cab5f5bada9d5057986fdfa95431fa6906beb3821dd7e4bbe53b880d134c273d44e0de2cb151ec4fdac01ab4213f9e9a33d8967e7bbc6545fc623dc72f5c8d88c99a937f5333a71d0a3e4c29e2feae67c68801f215077af579cf47691b608819504b355a26adea026a6dad328f860fd6dccedd1b555324d2eb0e4517d90ae9cd2fd26cc9a4f9b3385b0624cd5bc92fe68506212561998b883948626879da18c1066a502c089dd097be8c71923d5e3d064fc588464c66e19a7be6f460056225c91fdc1ccef65e86b1c016434b6474f30aac1df6c443a7e32ce84d7b6fb54bcf8bf29cfc3c24d771eae136ee072ceb69de5f36c0d48cda9d91d853aa7c1566c77650cef0094b613d97aed46a6111e9f76ed8f983ee80d607fef12964b2f8063ebd13d5084d53b6c2b962a7733718b093906e223982d4f374d806302124778b86678779d8f7f9c73a009cb1a6577bbbbbcd299ea048e6badf2e40ff40e66b6972cb01ca874155e46095e2c5d950ed233f8a7f04fd79abff2405d0b5aa0cfc0674e0ede98a2de90e88b1c2843dd07cd06406edf0a562fc81aa817ec208fe75dba448287affe48f3422b5a3f482401b9a43740df1dc7fe341e3e68a4d281237a351abde1d38990032c439b43e38d1659c0a19f83668819dac300b20727bc",
"spend_index": [
0,
1,
960680172,
4294967295
],
"result": [
"9bf8dcd115918c86a90e3b1606b7554a0aed8a8b4ade64fbcf71bb7fc62f155a",
"653676421c9f3c636ee50a1ffa8b0d78e59171b87248f1424ed423accc5f08ae",
"17b38e8a8c1ef172a80aac99196bc991871c8bba4849b9ce8f76495d2a095bc8",
"d15e7d2504f6742cc4b97bb65a6cb63978ff211b4bea201fc241a1460af2c407"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 3,
"Witness": true,
"Version": -1391982199,
"scriptSigs": true
},
"hex_tx": "890908ad00010a6a475f400000000000000000000000000000000000000000000000000000000063c510490057d8d8723a61c938000000000000000000000000000000000000000000000000000000008153828afdaf01c488b682390682cddffd1b933ade8c7aab8ffd7eac633b9473b611b3c543d2d7bec08f85b60a3e2902f5f67264f7dc47836a2cbf290bf27d1602d7a6d90d2dd9552f39dd9e317c208dbb2f4e637dbcf41233132191ba7f53b65964d386133eba2d4f3687d9a68001dfa1560014d38892ae433fd1404a3aa68ab16806fe5cadd97c3b13f22499c5dd1aa3bf26a15a2ed4ece6149be46270817dacd78ce297c55a9f86be94d2044ba52c4adc21b9927d45190e319776ee41d8662ec2f6dff25adf7e07c733d9571a0370ef2f76999003c783a51d72589fde067861364519fefead40a40b82ff8240eafd48e54a19bad50e9c1b6cc75c7165a373313e9d69918fad7073ee75781958c8c1c2062e54e2cfbda0572a693e008de42883218bc3638d71c54e862f84835ecdda2ec3c5cc9524319e055844d672b972feaf3aa22e5cd8c5b4c288bab928d903817f8837b7519a25c6ff07768cffe20b9b80c867ef4b4b2d969ae50a44163c2c02ec19fd89de62f9ddc9480c7fa732d7f7c463da9418a7cecf5919b27efdc0fa2b4e3eff4b7583c768c16b9fa12f20899a6a93d43cc7da614d151343c2449d5a503066bf769f2efe803d0ca97f20460000000000000000000000000000000000000000000000000000000030657987fd5f018cb1e741bb2e2fc23de850458a10d142e801866b4cfb765bbe4515cff7bdf7cf5c1a25643e81bc27077cbe1e2cf800e97d01a10cc224328438e3d8f1546b61e86d00df12d039d714acc3c4bf36043d231aad657d48af77ed7f99024e80fa87e5801e2cab470007e536bbec630c2fde13d5dd3481b056f64bc78f30054c18bee2337a23a1ea4d19439def9662c620cee8fbe3224a5d117a944e264b9152ef1300b0aa5956dc6855d628c5d7043126ffbf5b4dab4218d5145704ec8f2825a41c9a831d0e53ee5c0607b6820f48f4b74ce1b43f3a853af5488335fd614a71c27bd4bd75ea3dfd6b8f1cbedee4aad2836e974846f4919c86b6625015ad5f97f5be8a1711b1fc5158e03d8e4cc42242c0cbf680b94f3300041dd8549b05c880140ee7c740dad0eb6a85f38cfc55be23edd782b292f272687dd4ecb326145445b86e2c7f0031daf218ecf03074235a3b1deeca85fc9904154105712732d5e69263378e86786aee1ad80a00000000000000000000000000000000000000000000000000000000bfa25a9ffd00013df8bf0124ac40a0480926d053d900cb0124d8201ad91484539c220b9b5fe5ba2e739837563eec6454b7fcb08501dda4c1be099ed3d1a6033249c2bbe46a5b1958d3ff9afe0a6bc900a3443089a8e2c7662afed4ae4fad28dd42bc917c28df54ad969d97f537a97b9997e6bebfd187d0bfc78e319278d0ce5021b9ff191af8703b3f0047fb702a964a9f280477ea813dbdb6854c2434852f81fa1694acfc6f7504604a3b9a4d8ee14f57ae65e82843ef683e57259273fe9aba6d4b7b93c539ffccf7ca9c9df9fa993e60b83f434da9002763025f4a765381270d72a176104efb54b232762511a2720a0b8ef1e67f439e84a581bdd33e2c393283724ced33b1c69a43a11310d074c70000000000000000000000000000000000000000000000000000000065cd7f7100163808f7e0b6671900000000000000000000000000000000000000000000000000000000adabd5c8b249f3e9ca8e8f7d0e926557de444ceaa6f78d9d94598010997a0f2b8de4b6adeca7fd4dd2edd1092eb8efad4690878352afd361a6ed9cf4ef3fa88c8f7e1d7eecc5f226ee6b99befdc1a870f69b9b060a26752fc84df3538a0b540d9fcc415717ac6d1f556353b3ef1796bbe5a593e4e21b7f44c63f4542da3998438c56f3153cd1da54ca41e6f04df771b88215f9be7bae3670597344dc601ea6493e55c096759a468e2d25966a1d4b0c771255571848a3900ae7a130689904bd00000000000000000000000000000000000000000000000000000000bea14f12003f022e6e3100d25800000000000000000000000000000000000000000000000000000000147bf880003e813dcef0eab32f00000000000000000000000000000000000000000000000000000000f30a5748009ef8a33b603b8d5f000000000000000000000000000000000000000000000000000000005dc8f84adead025bcfe625415826c25c9455041dc5ac55a7c4be0f7d1e1fce4f9ecd313f1806782a2b6280464f8e48f5c358a188df8b61f4cc42f2bcad20884c934eaf6591cf1a8d6e8e508b45f23ba4fb21f6d0e4c6ced04e8da7859eb70738e152a0753e769992d5442b7c0621e4af77cfaf7e77e893da483633f4ce818fe150bd5157d61eb5131cb9a3012ec24ed114e7481b25e6067975d97a16fd8be9735b90d3bf27555e6b7cb5383bc3cbbad292a77ac4fbcfe9c0ac64fe7d479e1f9a1f1b5a6a42994e80bf4f9f4f9db4a568fb149b2f1bbb2fae7ab356d3d3cfb724aeab3636043664032ae1cc41d9627e2ec8a32a30d53fa40976baa952805bb2beb4278b2bb8d7a051de49e2f36d4d8e70110e5ca496416a5f0ea82c341c4ed4b8c7f49513586891485fcf2db877c5d26afae97ebc92ef04087070a12a1cd20261deef5d82b7393806217476eca4627495a852c8ea327a47f9845b14a9d2decfbee4ea3d1c4fdffd12aefeb796f77ad5661c17315701f9021c01dff98d85f45775c680fc805c67d6a2d95ae4df65a71b0be89af31ba113af8ec656d7896ab1468f7aded2c35819fc348237a2a493cdf7b9f2b377cb3a17e400fa4d42513af235fd62c8ea6c44ffa248a0ab33f44cc98fc166fe72715f8c21e6168c6f96be4322e0611eed31b1edffae929912dd497654e63e9399845e79ee866079cf3af2845a5f130358c27470ebb9241969898e3458d9fcfed3ef24c31e8c3abe2dfa541ea5332e6c056ed8f0711b023f4c545f28cece63651227ecb00bbd9c7e1fa1fb307bc87ea5012dc47722a9032471470d82e321b5725a7074088e3ccbbf2ac94ec47e3527429b5a7a573b7bd6ba18c9dfcda52d28894d292fd160401f2cc5e0514d1f01b49bd512c7ed8945be840b5edcdd38fe8d4fc8d31ca12256160e8d4134fc6215baccf06f02bac979c84136f9dfa37a81ca6bc9b93dafd369fc688a0c60218475cd687d5fb35c6bf5e969c6e8e4c564764fd17b9db562493573e907d211ddef2ded4332b5b9754845925f525a49145e04373f39ab8e26ff525ca5ac08e7e5358c598b4c399bf7f4747d7e76737e46f5c0467787a9956fddcae563690e41af1926ac665604ce84600d07c5b03d058466322d6281b3db2f0e938e0c7aa2d0ab8c9e4fe16048ec51fbbf1477deacc8de18a98d4d6b5a171b9f1360735f03fd7d010981f2056d4b289eb228edc0f65d71d1be42fc8384233ee944ea2ff6d19760a347b8b6db7638ec1445bafa9ad1b43486b47ff6d846551c5dead0eec84baf4361ee8dc98b60654e02ac96094b10078f7cb1ba2e4bd306f740a37d4dbea8fc4058ee95822e85979fa6cdb24895eaa06dd174c5176457fceb9be8ceb7c6dee01d599aaf930f1c374a191a4059dbb48cfa948639f6c4770735500931db6c5d7597672b52bacf0c4a80a6cfca728d0a98f47617161586000cc86432bd0ce601fdf5f83fd953dc38d83460464afd5d2ec44bd9cbc649195c4c71732c06a5886a0fe2e772715d92547af49ea294c7500f1e5e030a8e35b45720d729487f218e9c2c5b8d2f9b0df9416df1d1985965d509247c8ff72aedcd67d958803c4a37230447fd44b4506273fa2f236b031a4656552d24aca9f97946e29237272b9cdd0f5cece3ca859f548eb4a35b996fa6f5b229872b87f718209a4a5b3a5922060c30a494a22e93ae52e473e8663924d77763f72c1f269ff4afdbf9c31d50b0ff7bd683fd92010aba122ad38aac797b51c3637ee942084e803e531e9836270a45541f2d9e24166ef8b735ebdcc827ba0285d6e1db05e4fa155367098458764abcb4f153d9175eee8b8692a1e4b0a32b9717f3906a173ed23cffbe32d87b4d9d457c52c827676c6c0cb82b057185eedb49d37f73efbb05f5d4f6fb6dff75efe43a4b8058a5edfbdddb0f55293030489499f89276954d1ad2de34b066c9bfc72d33e98854d86a7c7e1187031e088a169e1845aecbbb2a47b5f34225dc421b6658c52aa6a926fc024ee697106e7f282849522706832be42f78436143993d4e4e8a6fd77f6c6b52947a6185eef3cb7a241562f1feffdf33b3116a9f1a28d542b2c6bec88b133c819bbf6b2a26f8ee4970364c8da41707f0bcd1644320d0e2b94e35bf3a383a53966afa80a161ff4d81cb58b1dc416b80ec71158066114a570fffc37ff2da7d57d7178773dae7455d878f6eab7d4f697eb66d8d33ccd911d0d13d4cd6c093b96823e83a8fd6a4917baa2aa976757a49a8be80d00011bfabaef4219efacaabf71e19b32582826baffa8df4f0a94211a6e764049b8c473deaac251190aabf96e3ed30019e3ac3a778699030fb9217d792d380f89ceb44d2c9f0891eb6f78a50d293c7bc67a3d7d1a9095c0c984acc2ebe72533c9b3c6978b9a8a7b23136013c2a7c69bc3d3fbbdcf3294c7e722cfecc8e02e6873b7b10ab8c885ca5f39a0ee1f16e3225a0b74c9ceea3dd4764854cda08d5b6f46b6cffe9c9743c6801fd950129359a1fe365e76c55839e720d4f2c56caf4ac8470ad71dcfa04b01cc873b4cfd7e15c36ef856134b97ef20ad53e708741ecb26958b7f79514ed18ad835d8bde79cb95fa2788c1ab64a3736df96533acd9dccc03fccae92414ab046bd09f40f0bde7d31904ff622aa15ca13c69fb11d9bb70d904506d0aadb871c6d7c4099b994adb094611b86b2c828525db80e83d00265a9c4bd20ca153b6f9d0a107a6a563191106f3e6ca3c67bbfb48410aceb2c9534bf877b1da27c70048d4236907d919a1fb4fefa6415f369f3fd71dc39cc69c72560c76022ab200fd6ff5bf7999a798e59b1948fa01684f648be7aa40a6b2ffedbc9c216988b8b41b0280fd754be8249767ad3ce4581fc9f903ae2c4405588534b3693f34f631bd8d6f2c25614ec148e13cc91b067461ead92d04ea8707e1e2e8f99dda14f9c38d9f7474594a1cf3a75388746df5f7e569f1f2ecce24319ac8ac4ad3b5ec7b1e886298d3ff52d42707c7eb7838d56b0992504eb6ae8b4794132009ad7cfe16ffe10ea94f6f37928d339361e226ec69bb75ce7a5f40e4011b19f0c6a8292e0004fda6012e63e3ea9fcc3eabb3bc7888b234ac667e9098245a32aaed19178b29ad36d7a33465a331ccafcf9a8c2b8dac0442323ace7ffc7a2b39f6de97efcf261aac11f984309cf531c7b6254e1c6062b4a2fe7cc031cc0fb2b46ca1891a7065719059490a2e3f6aece850a5aa9f55401519dbfa5af5508510b8f7697aea2fe13090e79c848a3a087536728ef24ac0f1448bf91d1657ab9f4cd11a08c86e146daf6b6b0396c0443ab5110f6132e7c6ea137e20c38c396e10bc151346ab3482e563ff9220dcaf31c2a6f9da7dd220df26cc53fab1b5bd77913c1c2cd903b2f3fa4fa3546d66f7ef2407e441006c8a8bbbaad10153dfa57ca03029071f24ac30f476012f92931b997b195fa60b431eee4b232a1392b3af022a285dbe1062ec9dc27bbbb04df70000e75d7197fdb33ac476b0a021bc36a1a1e92d75ef35cd376694feba14396f1283621d644e0537b0db0b0c61861ec168e749cd7b7ee90a29a51cb91a23af8e154fc6b4d8fcbde27ed63233aef655435624c84065f6e4e1d161f86e81982d51adf016c463acc15313aab3d7efed09068289ac5045374fbefce8dc3a1e24d66d1441d1636cc1a460afbe177e807ebf88c1ac4295660688c77c5c5c60bedaefcc0f0b6fed5e8f4ea5efe22c1186d302c29d32ac472973eed1048484b57a424433fa6c3c2922a9fe7e82131b19f667744d15d81dffc81bd84db82f118e3a965567f8f5d03033a46b7d3346caccfbe21341838ddd477af81d64a1a4c18afbb489615acfe94cea5adda21338878db3d7070ce0f1d885676e9c568b602ae72964f128fc52d6221448b359c8ecb127af09511391426dbb6e8c5135d6ae482562feb9cf2029ec17bd2b31fd9d01dda34002bf7930870b2271fee4d8f4fe32796b3e6123c1e084977b170ed9c776a8c9c8fc04d07d4780bc8635b67a7e8952bc01c6690d5432eb2d26f2c02362322ea7f1cf110b0a04eb655fa21aa221069b4fdaba35d4169ff4a39fb0771ab2553bc952b75258c1557fccd196d9f48d3b79c135fe18fac94333b36a0da5579d17bc937aea95f92c45ca279f8a79be060a5562c3aa38c6fa772b649905e2ab888d11e97b6fe5dd4d536825960c0de58f572056eb2d5ba34ab163e83baa7187ff304b370611fbb3a28ba6319df332cf06569766f50398b21de281a03460cbf94a9a136f81770de06031bc61eedabcbb0edb0a41420125f334cef5adf19d1a27b4a0af94835a3f91d1d756b31339201dbd433d4684c67a693a5bdc4fa5b440edf83cd5fa9bbf07470dc6ebf3eb7933f61e5abe2bbbb859157b7c47ec79dfef591f7cb435b1f7b48afea14cace23b3a25e27559233dd8b5a3af620bf61fc26221345f4356b64542a0eb2b99ad3389ddc36e843a6d6811f2e0b6b8dcd5e4afe87524317061acd2f01e450fd8add48f5a756728ffd4944e3b917b661b1b99e44580aed8c803f154c32d0036bffd9f70361160725dbfad5646c89f3982841bc199a2ee8d33a12e8091029703ca151fe819f1472bd5aa5087f2f92ef8b58cba3a794f0344ba301eefd873c4abcb98f5d2878b059513ee462e94e12cd6d2892f1218614622ff02e31be230ae7323555ba2116c81d2290704c1e274cb78e1813292c63103ea401b48ae93231c37c7e94b8b8b53415c2012c4a960c8fe683edcfde3eb0a6113fcffa71b41968c78d0b6cb5151001a1587e6fbda5e768c78a692c6ed8c43dde3d96807ce11c0111ade6f9f885761ff9fbca66e6ded3ccc5436ecb0cb2c1a31fb8a04bfa33a26eb49c76fc98aac74ebbf95071754564bdbebe6017310338092c94449c8742dc79ec63dc78ac3b3ec4f0604936212c4345bb545d7d396d9119039072de055580b027fe0870385012b2fe949f9e2e3fe2df3eb033c38665bac40296d351ae708dea4219d4d9b7799281e6f4a7b03969412f7b293b18e62647e3930ee942bc671c6b12cf8d7852b934cb84abba15f968c9286fba2c5cf6dfddb7ecca1734f01c27ae6cf4d340e19ee0d7bc76ce47b39b185df00384855153c5a332db02fe441b26d025fae80f2ff490dba492abb5cc25e92d6bf4502a45a70b35b125588d940dfd26f7cb115f890c3877345cda494fc96c04a81983f7528ecd08185b8cf290b2da7da49638df1c400ee4bd4fdfd00eca96e7d3f21853d83d27e410232b750c9898d4bf15d5b253624469d027e20aeb643912f87a537503c68a6a084fbdca319ef0d3a64badc883ad1a0c48c163a1987c753257fa66be3ad69095aba57fbc1308c98e1f5df39782680f24791d3cd949f765a859c36da4158edc184711d74470d12eb4ee1d45a6ff2e7f0979e11d434835f1010f456f108bd43c2ee8672366041a9883606a11dc61a0220eb5fc620985b3afa852a0d6adfd80f34c8c0908112b9757dabc303527a04e1bd733ea03dc64b9df0aab89d2a3c52bfcb6cee2b5a02db9bd3438d9f8335fa46ae4ce4436ad2aa3de93970fb2caed3d14c324891a617da6d0d86c7676374b770505ac302fd1901e43420c809945896c873c09b5bb6f43ef497e9f98f73a936dff371f1aa9c15495bfda3b0e562b8a677abecd74a7318f850942611caa66bfd29dde83452790f2abedace64ecb5fd07efe8d547b7c781f02d1ffc540dd47b9f850713e903f1e7b54edaeff3c73eebadf8260181dbba2505b21e0f1a6e809ab212fbea3c94e98d8e35b139d4feed9b77b093e71969a2d61c1b11a9152fce2bc7b9bffbc7e6e2f8c1cded37950dfbf0f300ede9ef4565aef82e6c4c61f030a9a2266aa9629446c7b5991ac3eeaf31b52fa4cd22bece4c140cb22d453774f05a62a73d45f6ce8ba96f629d85fcf5801ef7d4b4c3080e4cb07edd031e3697bb429f5d5fa71560b748f6696b624365ae5bb821a9caf5e86ae20176c18857bf6f4efb07fd4601a3f89c3fa908f1c3552ff652922582c2b798e2051f43bf15eee5b8d865116418ffe81d7ecf5aef7c1c0b0a85b437b4459fdac54a5d69bee0394b774e2b77cc0dafa9a48f6398fee17c154ddb5ad4dfc9903a2a3a35461b8547b56449fb4e552e52d93b09e774e96ea8f733269f118754837ebf431b082f97a4e9cbfff1ec9048da25901e592160980776fcae68b9c113966844635f8ea71715a940cf9385c50757ac5787e49d30451c6ce04e87a47e49e6fd054a63d364a20919b0f8508e5a3386903112307a58e59f3bb4af7bf0aa75e63e858abfc52055c5e7f539b44c661b3411609d58c4447b4fb4d01592ca020adff514057d0db6c73d24ef03327d17a860c3639c05225a4a574da6c8879b1eeaeb260d32d72788304b05a2c62e0c7119fca55f27d522b55863a1fe8d48919f8ee58c9944b31be175bce99474bf4aab57582f1203132b03fd7901f219f1729cba8171b741a33b8a163cb7bcc80b2894930c98f36f695860290563cc90b1f044af2e0f78e0491eaedcdb33c71b545f3d2839939fec0f603c10ad9d868620c94fb4d477790e657f5a624c52a80050d0fef5df104533371c2348df517a470a0c6e78c974b67fd598949c81a56cd0834944556764480cf6cb093c85338d2ebb8bf3355f40e21f2944932bbdb5ad09f453e5ffadb8be2ec163342297ca157b0688bf4f896c5bdfca8b458a2cbdf8102d0e65053d688c4abd4d9b3a238a7e88cd31ce932e06ea351ffa89676d8387225213ee66ddfcf2f4df32c11c369ded6ec98c4421e5a63d5e2c6782a083ff514cda5bb26dd59b32058f104dd34a6f6d129c11e3a854a1310004053140963c853c0a6805a164cf443127ac326bbe43238e54d14032417b7594d4ab3f433032f94ff7e19bccf860dd023a8deb94872413a5850bdf57b1d3543637064b52862dc4c55d8727369c2135df9697d80f8ce23a990395464e500fba081f438778c752f7e0b0d07ab4607ebdfdc2017cc7ebe0cdf3a079904dbddd27859bef4f5ab2992ad55acf27403f9c226b14000af970b8d67ba8464c54470d5502de88f84e0af3d3348d3b481f75ee8a01ea75082ba910ba0ab7bed4c14feab97033bff8270d7f5a286fce30fada23da9e004acf0d1094bd85eb2d3c378b18f0bdf96e6fdfd0c73d5dbe27f6401e276f99a0d247edce8225028b8b67893775f430cd11d54aed13514c41ecfeccacaf7196285b2d9da0f9c0da2e56d7012da39958d5616652afd8c18185118298df9f35099f6060bb8d6cd8d1462ceba20b98541f1024a1dfbaca9a4278fd56b7b3e9c61dafb8f1047e2f27a141959d1a0f6e53dffa8cac8e9f64b12bba315acdb1fcf8a1a22feffa3fcf863cf9476c6d54fc7f527c83a327fbc5da4f383040e44baada6259d25763792a4032a98b79e4acd6a1ed08f55b2d8e6d8dbec505bc03a8bafee6659ec534716a9c8dc4a5694056ba980012faffade4bc08a2a85f19deb2129a22c310f828ebd9b8eee35524d4d259804252646935ce6e7dc0258f4fa418a543825cc086e1be69ddb1fbc2b6c2426f8bab8169334bb414d4e6df57e83f871e68e7e807a982e93310983626ad0d866cd00c7f2183c48ee206e3982a5d35e1c1d7c184ca5147fd5401385b4e748b9bcc0459ae3063317bcdccc3a441340dc182e804ada77f99229ef5c8b2ed2c8440e0bae5b00243372af7b5281b335b2d4d09c254e32f0e4d1512946c27e75f305953de6db711482e8f47e18c03e6272b0fa376b3f6f87fc216838e8304eb3f7b8a679b86cec63963c916b66b37fc86d71f55bec1b97a6f7b1da406e67107c31fe3a6ab5adee16debb4d9d6729d49fa29a7944dc1dc4887e69e334c93de5c09b0b571f68003f1af05d6f6568846b040fb206759c5f13b34bb93b8d39409b945be7e812829899b1cc628bf579ce86b615b4184865612ef05c2c5915c7af6c64c21e16da54b734e999627673624ba3a93c41b5239a6dfae89fb73f85f85e09c40617e8cc080fa797d08124bbdf947619a3ca5f762a4a1968984008bac06435e39b980680e5ff60345a02cc66f0e13566d13e1aa2f815ee9bbbdba2d79565baf8915ca0167c8e266077e557fbfad60caad00040ad7b91583ade01f6b42cdfd2f010121e30d383cb49ae707b52a00b8168354f86acb099db4b5740bba3d3841214dd7eb78c23fcee6a5025d0759aa0208932d2d2a75106689009344ef5d03693000d88927034070c8d78f5d77538cea539d6cc70ea5160f4d362a6fd738c77eec8fa7d076fc9b6f9197b86ef98a6d86b298ffcf3db86d8cc01fa73dde6c103eaf18471ab31615f9d879866266ab808d52c7d893ba0aca1be375aa2479186a0714df84ea727d537beb4994e2e50130224426f2485d682a92127bad522df6c392348033076de514621ce509f8a6f88b00e1275d5e585fd4555e29271071d6aaea1bb2cdaae9d97986db82b29c6715a8dfe843c0c1cf4ae40c57d0d78bd822811801f203b9598d94413be0b4cbe0b8c833a74c084b1ee66bb6258ef493ba4a096f2d1f758d967318b0a428c3b8b781470c76fd970118c02aec90040d75725ea3042e08de9a77b9b1716a970905c4b50cb63402533f4357c3a697d7a24c578c096fc67bf144436c57e8f68b88826bbbf3f4784de0731c26cf64828cb9557c2e7f1baf2631c4fd848e9ac4ceeef6109f50528ecbc7da35341aae338055e62663ce0a3c43d9662d6ca7f58590b8ef8b19343770c7fc2820470e3b969e90e8e4adae6070f392d5d6472afad455b69300c70e5cb37f7e9e35e6de31532e660c67ffe67f3c4fa8279b15c323b89038b8865eb64f07b8001b75b490a8cf743b04370b6098b0ae9dd26f84e9b96751eb4bf88469d12762f268df11012950d4a2a9f9bdb48a6397e7491c22b64c3fe29e01d0a098df92f15221f73df80d2650621a36bcae34ac73a85dc8a146a2e0320a0a84f164756e352eb770ddb438d358bc85b431ff846fcfd614f62caeb6e8e5c7c33931aabd6cc9681012afc096efead404b58a4e15e3540914332c8a0ccd0d63233cb07a666b1027a0d0f4c7e6b70410486d223758b4ac006668cd4bce09d29aae796bd49559fe86daea9c7801be3a030a17c8ae4873f98271cb51ec2652effbc86bf15ddd44835ba01fe3fd7d6df43f5ac2dd2d3c56c9ac4445e0fd56e43af74714ef4d7377549cfc65f7fadc6276c1d8db5e7f9426c4c2c97bc6ff76a90940965305c6cec17bc25b78d3ccd02e1e0583ab7460b7e289449a330e2586c837c1cb01c37052a94b4f71323aa5e285e1497bdde7fb5faf8894719e3eff4d8a9d58ae0ca10228334edd17193881879cb0d3416a9158d148af2da3c055b94bd1106f88f745dfbeb6e4fd634102ff81111d255b55bce3cdc0c5e542351a0b4dfeced9a70b2baef155afee71894f704f",
"spend_index": [
0,
1,
2256832467,
4294967295
],
"result": [
"7ece1b4eb1686e819785ed780e21833c9144696c76978bbbf7b91542482d7dca",
"907562fe9c4028db2a209fed33d17b9db6b513c617b65e08fabd61b725d10035",
"7f66349b5ae68c930d9aee9a7a73a57ee7a793d2ec17af127e643a5969bb1a44",
"0e5fe7af882abc6dc8cdcab52a6f06d7c8b0a2c6979a8b0925e05cc097a1bb39"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 6,
"Witness": true,
"Version": -1121365080,
"scriptSigs": false
},
"hex_tx": "a85329bd000105bd273b6f000000000000000000000000000000000000000000000000000000004aaeec4800d1105217c17fc93a0000000000000000000000000000000000000000000000000000000071a3b5b9005fc09db682cda04700000000000000000000000000000000000000000000000000000000ac46a23d00ed774f8f67a4ea170000000000000000000000000000000000000000000000000000000048bf169e002d4145bdd05a4c7d0000000000000000000000000000000000000000000000000000000076ee89f000c4298670060a0dcb4af14fed1dc827d988fe2ec385251a53bb551ebfbe72c53fdf08058ec3e6d6161e5e2a7423a16062f2e4639808a785c3d59ee3f3a69d02007db9101ded18f687f0d10420caeb2400fb79a78543a76a171a99b75d3b19fd523e9672208555a22c3cb619751c1aa40aec38c21a2ddc3dc133200e07446bff0e806e5da2bc891065648818eee19c2edc57bfb62a33f8bf46f347fa8eb3e72b25a36cc011f6aac189af5ab9a17b8b8b57299dc086d519b000eebe986e29d29f236ebd64da694eb7d2d02942c28425c9faa46941d271e4ce73905ca06c615dc8bb355541e131c80142beb9629e3d2eb8b9c61891aea29b67d6b0d2e01f8b1a9b22bc72335284ec3e93fb919d62ad743950f877598fb2f03f80e45e3bd24405afad57e82cc4f71d1936c8f1ac3ebd91f8641d7bd90caa0919a5948d59b7c7fc81ee5c3e38c3daaf1cc6288076be779b0a72a902931e253d81854de11dffddace28c8f88ca85be9436dd5037e4bdb1eb710ae59b2053530190bf066af04094730472f9125faa096e41c77658f54aa4d7d36711602aec189089d25cf39315f5df4cf8d11e964497d1136b85eb3e8324a12fc899222204b2df1229746ec2c9e5d411a11550be538ce5af13a6c176b5504f2cd708ccd8424069470b1c43b15ba1e8bc1503d01aa45d79c6e54c408459cd922d812e6f4a156133c867bbd2ee85ad8360c604961c8a1051674292d02ec48c0c497e33f772c022c139cde50c750cf84311fd8611eea3cdfdea8b16b2d0e9ef1ca1d03abf9ccba85299fd6f115af72bdd0c7da14647d033bfc8402030cd170acb8c90dbf54b4c530455f4365f39b85070370d0ff4e938bd356bfdc423eae36ff0c02f64fe11f7c610f2ce8f1d4a2b45aed32cc80279c8367658b0d003f0d7a6b3a0aba3bd18eb27c43a5b0170bb5c8f12316b2959ffeb87ef520c3aae27c2356d0cca3e5c12be0146c8399ab410d839f61c82382c3fa8fca2941024e4b6f3f84d72dc3986095af476021c8be1a7e42573f00941c849cf62782c0ff36b7a7b5497bca47b9b1b9a46b22827eb3fc53496c409907026fa942f7576ef948db31d22fdaf871a214166717c0109769529c55ec3260299a4f240c20874e3216cfc7b6557ef64fe3a74032a07b9971fe4f927e4e95a549df4e0a3494d301c637fb6f4d21ce6e36dc8ba40f4e2272443dc713df51e35ef69335cef0c382261a2417226223d8e0e085e457ea970bfde510ff6a076cbadf31042f9cc16d60d88f952f3518cde04c1863d45a2e1b44a2c230077ea1c62bd56bd2cb46fcf37ac22538a60ca77637816c2553977b8a8e55ba3bda6076698056fe2be0314a0eec5917ac78d6399274e2907946445ae853101569d395f6e8d3d5816b6aaa3328aed955d8627684415c1bcd284bc32a078603c594a06b5ecc214488486e77c0950e2355b28f99d442d12b41fc583c1036e254816b9bbc15e5498121222c81859344c7746628c4df946424cba87e2d1a97dcc8ee7e64394ed194df3b5e78c3e05587720c503bcce1c40490dd154835f1f5ae98306a71822f0f3a16a1fdc8366a83fcc24de976cc600a5b050152ecfa9fdf9702945fa33d1c8d0e51011da4ed316a20ed46d85d63af623621f490dd7df5510bd7b5515989753025fe6e26074d7c254a9ae38ddd6d91210d6eeb7696ce5b5a9264ffca2954a26fd6c3d7391ce9402d755d45409eb31f6fa3c5be14f30c5e3586f5354abc245eca1f18bf770260063e0ad116f667903fd2b019797c0c6f8da47f4a7204b1019c0c5449520f3b152675141af11985746f9c26f4738c4577d4f833efebc11071c7dccc13622d55f692bfe3f56fdf1c6b54ca598e7317eb35d14d1230f93a8a6de2bfecb18fec35fc61af109fee8e124cf67551951415e71cbf78628719657c3b180ea821e21278f4ab030e31f5713f4264032ad81f8f2e9ac1dc2581bc24ccf34baf127ca8d636032f2af82434d9a76144aa7aeb4d0e62bba3bb6564b1070676be310fbc96f33c7cfc749318d6ac90f64196ff89dfa08c4363a5f1c211ed36038cbf5df1aac3647696567bdbde61513be983a9639f5fb2a6084d0b0e9657b0b0b7d735ebe50c5a5e7fa0eceb8be0748d6f7ff257441a417ecfd3c525754728c87b228a7771ef0c11e200738121786b49d11994ed58aaf276db014c45f963cfd3d0137006350bbe52ee7816c885dc9a4b560a84b12ff8f010b0296641da8fcffee360edfd8a245782887ee3cb369c99a1693e919a9e1ad0519f5974f6fec0355f3e9f3669acda3d9b37d0eab9c7823e02798fa8aa433194f4812bc328f37c79ad3d5d9fc225571d74006c958b92d91fd026ca3fdf7ab8e22869f17041349a9463cec66691cc09f100e9b7064425b184977861499bfa404f773f798aa475653754fbd71f004f2aa98fefeb9f1285629dc00c00ec1350038630fa0b964f9da49fb6c603f161f344b1ad2f321a6743de17b5b98d6f7fc80933836bf4f569aa1d7bfb8c493c289208a8dce556d3b6f2a64ac44aba3e47ba4d23f588feddb456b6e1389b35cbe4021f1ad4f240f8ae77c6e8c1567ddcd995ea4b62a3fc7bcfbe1c8bc8b6676ea89690db799bb9762d242d67c4d5a8f98870c8ae683dffcde119a364c20cdcd0a1b055d8ed43cb127d43e62b1871fa8bc87b308ff5419d60b6c7b80307d11e93f5719b384a97842a7a1543a62923112239d05e797b155777148b86ee2ca55515d238fb0b38d61f76f00042b21f785e70e481945235ea7714f267f281f7dbf86af9c49e2afd833c2b333d889234a81d7f8bdb5aec5f45b3b2d1933785dda2877d98bb8e7e2b79b0468cdd51c93601fe5389b4ff66cec3fdee8a970c57d4fb5d43d56dba3e51df41586258cf4de53f5b333658f1dd9b3c4bb5e881f958f5892ceb9baacfdcd74a8f00b302b438692c1e5bcfde50168dfc8eccbba89d7f930ad3022fea15249cfd94dfae54aebfd3c14a6cbefcbcdad6389b1b935e406140ce98b59ec617ed2ab62d70d085cac1a703f85af5afa9599a0591002f3a2a6bda8d991111526dbb8bd1115fdb155f58927c74f936c0bd2824817ce718e7bb12b1b9ada1f8e150f05f144899b81a96cea71527e5ff5a71fca4bd4edfc50aaa74846f0970597aae8388bdaced656fe24840d4f8c29624d33b3622d00546a1d76a2b533a94b5bf8455d7fc24d5f22329486125a1877ac4538282da12c6b667ec1b46ef72f365e715fe17fd295c707144a33a1db8ec7ec4fc80985685a31b2cc785b1bd5fb15d4254dd3a70aaabea50b604e39d7c4429707d89de53da0026877b675a09d34d23f52b0feb8f3bf27eaf2dd381fd17f9cb0b984fbcd63aa1cd073c6babf589ba34afeb49b456fd741e9d6d91e9a8c1e4488fba3e57cf23ea9451c2300b1fbf0652f912fe51148b9b2cc54b16c454b555acc104bf90f6ca8e4e77575dda189b08864ae1dc9405d08c6e20d6d609cc315a27f0dea43df7a3fc63d5b28a43cea0be0cf41dbe364f398a6720f61f6f5a4befbe2198b5f7a634c8c8d1942e714014c2b80a46095fa5ff5de0eccc957b4b85566de6cd59505f9a69d9eedcd410d263e243165d2c8a01c9fac4f0e86403bbdf7e4120472aefa3d1c62035c7e270d49dbd0f51c49c4f16c4622671831a9f96911ab7a70619b49b65e50abb0f9a40dc88aea860b9340bad394ee58030e3a58a17a82210425f8a08a33e9ef0e0547f4980258e1633c35c2d2ac3790825bc9fd7a5d40dbedd1d5b1bf00e5c368e6972e3ac8ef7f5ed5b7a3c27595b3a296d73b204352613bbda155234471bacfbb6bdb7d3d986d871e1bf701b84394b9ab1f9646c7370e1b0e6b0fa26c9c1539f617f7325df6c9d6a7872cbd67447cb8cf73a0adf3997e83d4373ed3525f938d1424113d94d4eea2432f76ef9ed805093cf57dde55ffea902daa4690bc7b9c3728829fac59b018c17d23b2bdca64fbcff5b951a796e504a32c7ba8776ed180046874e89d800bc2408114e82007a7190f8f937a9a8669dce413fa8910a9a7325487b2d3b6cf87197141459bbe38e05959c24ab74b9cd3fe3ad2e84b730fd80328651bc1002d586ecc",
"spend_index": [
0,
1,
1966205163,
4294967295
],
"result": [
"e621fea8972801c609584be59f2847a8ec50a9faf91c0e17ec32ca8e8e165ae6",
"9d938fcf5a87e0c748031ae2b11ce67eb76512c5b7f627a7be40e3ba0c4b656f",
"365258ed1ed296bd7011d1f5fddc452749352df21ee50d72d1e02cd3213711ea",
"856fb3d89e5d18d4e4a12dbeea1366026a5d1a155ced01d743048e78edfa817b"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 2,
"Witness": true,
"Version": 14177900,
"scriptSigs": true
},
"hex_tx": "6c56d800000103dc1d957b000000000000000000000000000000000000000000000000000000002769a2eefda7014fac369f73dd8922f35850393dabdfa701f6d3ce48973cb051d46b59b775410ba0e80285f48730e8178e4d2417cd58a3f779e1b34eaa1eee4adfe2264abab895637ac5d169cb043c5ed47e43cf2cb8b9772c4acadcf2775faf03e84156a2a6eb0cebad5d8671bff45dd7c96f8cdc01e6404ef78bd453fde86cd46a71138049df57b55894fb927af05a51924a05e9be935561d72141293a1ebcacec08c3a1034f51395599f968d2fe34ce76916977a5e27e33b9005174ca5e39f5801ebe0fa0b0c4ff303803f9fe6e9cfcecdaad5d92f51a1bfca0ba679f5a10a1c33bde58eaaf5c920b31799818b15e0212bf3c8882773760155d233e3ed093b7c9cd1fb2400f9e3ad443daf835c587d2ecfd4280f15790d4aa51be2a98826e630cffd33873c46df52cb50a8b5e5fdf791c3a6bc4fbaa10e6196df4252236dde90c03d42eb98d1d86cd752f9ddb4e5b99effc659e8a5c2ef2120eaf532ac03e35bbce791615352ae6756cbb5679ae748421daf6bc1a55df02672928b903cebf860efe165beabaa078bfac2625c89190b987c36bd56dc0d04eab01663212f0e89143eaeb395384e4fce5684c4a36c1460e1d43d00c13000000000000000000000000000000000000000000000000000000009e9e7da90057f6aa00d9b8513e00000000000000000000000000000000000000000000000000000000324e2466fde701347b2a1a5e83b3499c3c233a256102da9017b348266a0fd7b0f308e53c4f155cde9d5c006a1249f38fe70c6c8df6f47d2258ee470057b70ae70da5c9d10be083d6e6dac732254b2076ac3f64caea7365c6761d74079b7ca5eadee66c324f36b06c3724e2f6b65f204c9c1a637e7199ddff4e4a916a607a82d529abe5fe33e2eda3bf6dcf4af60c1e497813788d2493da4730431c91d02c03c98548b89d23998f4f6e129bead4635e5d5c4d68666965ac496071f7922bf2e157f9b3dfdcb276774d7a08f1e8f5ff0e282e123168e16833d1cbe6c1774cdf531872405f2ae69a07ea44a83e100771baa28e304b03eb79fae3767c4c4f6b6f3ead4c05daa4e849ccd898b6c822efd7dd6a031f213ce4e0da322cabb60d369f0ea79465efb495434a7e69705541e0b02080e7742957cd6c5bbd986380fbfb3a74772ae248d00364354366176fbae18809179911a47504a8711ed0e2a1a4a5a77164d1674bfdca4d3af69eb13246aa9d89ef859619fa4cd8f513c79346ab4cef2e6ff5f65d302ad3535f58b8e0caefa24914a62deb6839013e07e09a42ebe9f26661480958b8cd82b8c385adc240f47140ba560d5c93b06a1e4d79974ab5847098f7ad8b9c8cbdaa6edc0a639963d09b78dba016a2ff41dc2728e55d376cfb197ca09f58136978a3cb149d796b915e258efada5d02b89df0f0d827d82bc89af85ea26bf30089498e1636b711f9e6f9204ad123de8111ebcc9c7160bad2249ea106120844bd64d419581515fa0d5492bd4542f26a16151e456253e93d0d0d464de3ff9cd3b84f571805b43f88c3f27eca3abce06d675fdc9f505a83cfe496a13dc668756308c8366fbca951072cbec7140c8e92b687f10cbe35677e10fea684f45419b925e135624a072598048e81d9381323783ca9211594eb314f657a82f22c4bfd4af426ff1ddc32b9eb736aff76a1fb488376fa6fa2376682192a8d93715ec7db49b44b1a4d4cc8b0e62a6720c8ecb7adbd65c6be0dd54f1c9e5cbf9dd39c98376597eef0f94e6a207507148e24df6657cb3ec7ba43f0ed91523de1e9f0c8799e709a9ec8730bfb4352c1a21a34417c3a58f74f665525259d6285b8b0648c20683ebedf4f9e8fb912eab253a001bb2e28cc79daa210d43f36309550e5244ea9af5aa62928666edf42074f7147eb26605470f4c4916467128d65dadfd63a48b864893af9b3d819ec6fae68208a836b5e8a77a81fa08db60d7f6e9775d942d67953df77e48cb74914b61b43016bb0f54afbd1f98472050482475cb23443e6751d82a0760a51f91b8a41a854a8ecd0b7c1a839ef784f0e7287e2e8cc03324cd1699e7318867330d59461888289d1b8fefad56be6f6f129270c000032ed7a0cd8ee10e50e0fd9e7056941d644d25a7daef27eebafb24881e114916c7c545ad6d16f74e653069cabdcc655ffee0f60a1406c813b4c288f793a48d86f6690696be47c9a544e87d1655bc0e9e8048eddb90217fe9755fbd029c5b1d08b5dc767a08c4428a9d8eeff0d35864d51a4ad8dfdc776899f4a563deb0a24df87bea5ae0799cdb9eeb0972641b99b65643512a60dec2a0cac676d4c0bdae3129443dfcb744efe650fe82b6c16b60a55c69a52d4e5ab6c156e30fb2d8f8c2b680848a217d6b8e85129cc565930d4b913fb2376f23f1c8043ec7cc0ad45f2a99bef965e948c350c94726e3255fa6b8035c6eebce7fec5fa54899692ba1f98459e0b1dbe355260e2315f024e87e993d265521d2b6b49e642a1488a6ab201956da05e6c0e590a60210004fd5f018dd55831ee67bdd28c30054e1ef609b2ee88897d0c814aa1898978a299315c5f3509a46aa09735ca318dfecb9be3bf8801aae72d281aec64ef2fc210df7ad3b8e00bf494d462c64ff4ff166c4404d4cf1e24fda5149486f1ca73783bf800bbcb8b8c1df06642e7a89b6e5dfcce49a2591f971f9db11fd5628afdb22e12228ad75d053d7ddb6487f28a537d245cc3265e3f067dce2fc0d07a4cb9650b066f895555909cb9ce9569a516d9dfe3d1359f6e4295d2582572968898b5cab0363cca1dc9cb85bad37c9269cf75e0f0fa10b4dbc18ae2a62e9bfdbe441da9a2959730b17011ead2d669d5f24389a66bccad6dc8df0e2e7f5d67661c394c221faa1073f6f3a05bf1e6327402ddf6b815fded475f5a62406ca52548be25fdf2b894718ab237fd0768f9d56f31e2e3c29474291c68b5b709a0cad5ea97266243c0870487ee79f967061610a9c5c5ff8595c948937f17e2613e415c659f20df446d39a685e87c36075726b1f9699cba8bae12f4ef28e15626aa47faaa4f02216e077f3952ed1ce5ea3df1dad624cf33ca7211a706b245ead08f50557959cbb61ff1dfd6c15fb5a3ec1ed1acf3698c7fd3c80e9f1ef3f2da656546733b800c1c334c0096f200e6aab1dd0aad63f5c56ef353e178214f589e1d7e96746eb7305bf6b819930329ddcc1878b0f192fffa4d8aa65419a01b0ab4b3e4093c5a693a3ffa96be3c51a7a56ad66be6b3cc6921f6b1d82884caad4e258b68623bcd0b59cd8b42bf7ee95b5a300ae9b18cfa8885a4364d93e48c0058b740ee84eecf2bf0dbc532cc9b93dcccd1661721eccbdbfd0b01bc0f3b0391db6eb8e92a3f67969b1ba815b8285c6248f8979e1fe763055991b306f1770fb19944593512170e6497f14b495a06f79fbb64e180d7a44f42bbdc94a38502c1dc1beadf0d869550ffe3967772373c4fabd8c39a812c514f46ba807498a035eb640b9ac62d168ce79e91117e9edfd3c9856497310d7143435d9beab5384394846f0851dfc6cf850b55f3ca527a618115e858bbeb70c935884b4e16a613ac188e68522662f231b5d41cabfe1fcea1cc6232671e3bfc0d732aea58450c1f8c702a76c76a8affc45eaa7e1221601102a84bdab425535cf2cbcbead034c8f1b2bcbc42461ebdc5a8f6128f19e965f99dd4ee00e2525f7466a920b68e33f499cf5f05d931fcc8d6f5957ff624f2296986ab5f6a01ee80b9bb2f4d657204c1aaf819e469b54e6850da7d7508ceb4091b9ddbd86667d6040e3c38d8cdbfcd826b9a6c8937d7b3349d56e4f122ee5c18600b69be4cbf752a737ee327adaa1192657108c94d61911e75ed95c6c449b002013ad4be652e9c824155424ccc4a5443472e5ca195c1907a2555ef453eacd0",
"spend_index": [
0,
1,
991402756,
4294967295
],
"result": [
"69503af7f18282622a773f8aac4289b12d802e301d45b969f6bac81f9a34868f",
"c303e94cd581b06bcd2aa205d10aec0b3ddb9977e8251fce846bf4d3158fb071",
"6f7c04b8b44c20c64453256d6e4ce5ea8d888b4b8a74950fd9f1777d0f54c557",
"b82f362d8be5f7c0dbbabbd9b0f9a908e1d168416c0fa6240ccf6a78f5225100"
]
},
{
"desc": {
"Inputs": 8,
"Outputs": 10,
"Witness": true,
"Version": -1517733652,
"scriptSigs": false
},
"hex_tx": "ec3889a5000108c96eb4cf000000000000000000000000000000000000000000000000000000008f75b167007da378e1c0a6d665000000000000000000000000000000000000000000000000000000000a3b015b00f2f3cad92e460fcb000000000000000000000000000000000000000000000000000000002257749400ade11bf4bbb59f8b00000000000000000000000000000000000000000000000000000000ec109ab9004d2aa4f869f1a73a0000000000000000000000000000000000000000000000000000000090aed3c70034e8ed89e84edf2d0000000000000000000000000000000000000000000000000000000092ddffd600410e2fbabd3f807b00000000000000000000000000000000000000000000000000000000cb2061da00c101e4a981daff2a00000000000000000000000000000000000000000000000000000000b65f3cde003bd5190b0a187c93202477d158c855b325eb1c284a4354dc20059ca77ddac89a181465f083d0f075c80e7fb5c34055a1fa99623fa3dc7d68ae6a0c6adb3d4a6269673d1caa94130c5ce080928d53d3fa72335966f1c1b32d8fc016ac03f2575507683f73f134c73be43df03127b45b0fdd99528d5bedf4bb0a84fae0e86f6eaf5f7767045ab9b82e42369c13b76b1d12301d7294e7aaf9d4fae27627a2f108579807696fd7fe7228eab650492aa342463e17830a6e04319b9e585b3070333c04f03e63e6dc62824fdfb25e6cd0cd831242321ff438d8cd5029f676e6a147c8db3f953415d38451a3bc393fecf61d4218ef34fd80ef6a16e9a36a247b883842104e19ebcec7499fe1f35fbf7103c93c9e4de19adfb26aae69c1e539e11a8c66c5da857a59dc82596ed0725cbb61b3fb56ff857c084c703f0d7398016b2d7fca28c9bedfda40133501a2f45c52516ca8681026e5afd37246c416b79d087661a36f25c415f9add15e71b4e7018cc58ffa96134e6c7a5240e30181126d05d77d83ebaa866fcf371deb50bbcc4acc682226a0ee2e100ceda76431fac7654735a6ebf13f1ebcb0328ecdafa1e4780b35fd5bc805f320f9681cb70ed13395ac10cffbe2b2408fb4b8002df23ec9cf7ef59c2a7cb708f06e18114135a03f0fd4b3476a71d973fce042616b188b2c742a5d169752d9ef4ad5ba55453e209b994916972557f46ac3922d8503dc6f86f4ed7a39317d8f7c079ea709cfe69178deef35a12c9a24bf0b72fb3740897a47786fdb71c42893ffa002c70276ddadfad9a9551485ee24d1e3b323ba271d5a288ad575e691660a330f6fb0d18165094105d9bdf18d4c5b783668a97804f7002f3c75df677474908bff3743cf90aaa04d47ecc499553ec8e0d516ea52b011489d4ff3187e4ee821b1dfac82e61b1517dde3a757adb067243ce34bd3ade7ce1cf567000e8e049bb887f669b20dbc502ea74caf0212e8780a70e75f35b298c5e43fbe3340471d9678f76cba3cac3687f24c046f81ee9276160383fc4490044e318a309a6f4cd2cc8e32c56c2def96341a22e3d999ecda67de1e7627b98baab7cf5ff7731a55297709492626d449ea1c5e95a51edf210c27b7d8bda02a93b28cc63c9ef122a50c1727f1c7c25039667198a7b9b3c004131d4346b5013f2f7af9505869bb921a2aee2bc8a19961efc91d923183bb59b8047af9be7a7c026c58438aa1fd790df2b14e5dff7c4d20e22b19a4a2ba0df2728694080d0cb5fb8250083aa44c7952d3a048e127cdc34f0d37c8ccf2726a8eeab88cde748be9182c992ab6945a6b14f72cb792a384e3faad4e2fb29c1f1a3e64d5751b96a333c6a44051559bdda15058bb1ebbf0b0be6701f1908915d8e3b7fcd93479506292ef83a1f7a7a2b88a90ebcdaac824ff72688185460901e6754827d853a9fca376ca80a2a17c7425066ae25edd6e45ce5dd75aef01a613f65b11807caa7149c878cca3710401784dd20f21acff288e24e9e5bf00e22fc4446f83581896e6fd42e520b6939f7785f990093e361be1d5579d30311f581fe9e63e5fe15420b5503fe446a33a48dfa950de1fa7998a20bfc5154e088ae7553fb8dc72c30824f8a6eb895d6fdd244fd0a148ac6da438160b89d2ed458c7979a40ce4adca8caea7ba397ce51769341724211e0b3f193c6d34fadcb03e3c555fe47a4e65d69cfbfb24be6196db8428872a1e297e587edd10eaa379505bbaa85eb95e661cd4e864a15b800a09063219751c0d50b3bf615a2e630cc88297794d575db5769bc69cf903d02bdb587fa305f4e1aad02eec007f2eeac5bfbeb6f55c4321b759c4c4194aa7f82caf216e4c681fd1ec8baa441d47c62ea6ce78a762e780d5fae4e16eb20ba217beb8cf094332584cf44e3156d3aace6471fa7e34a047764ba02471cfc2061165b6d28cb40ba8a2a59ae4ab1b2bdef20f55c943650718e714ccdce2b2848a97615aac28bcaeb2372427154657f9fd265d2990a728bd7858e82c60e7f19f40acbd58b06b6ee64ec6a1a2f4c3ce530d28544cb8c8163b6f0f7b4f6faf95aa69f0a7e23dc852003c0ae9af77fdf579fb796e6671b10638af2ce27b62a3af5236cf0f35d7f2e2f77243e1c18f40f1a9bfd0d92bab26b8295a6f8d1eab9182c46f520a741d71e7c0d4022997d8c009ebfe59dbcfc7456953e4d6da1b58d0cb43d591f26d976b8acf29541fd5b793d3d3611be820e41258ca09ac4301a8b10f75fec6a3eebdf94215f5fcb1fd5a8ad268441ebd084f6fbb75b6c0f35f56549a2f8b2131858c22651e19f555bbe6b62e81128984541dd1c4790968b51e6f6f8b4058b310e3524f0b843c9477e180e9586d67800e7f9547c8fa9d75bb7125786a629794644dab2b4d697f173bafea4e2fb9379815d9630d881883ade829f1b43d7713cb4f556ea20a27e22ef67c8757f6674228470177e9ef7ca3bef311c2c62c9e1c72807863f6f0bd0d027667a614b2b882db870cc61bedfc7392890f76286edab1dbba2bf624652ceca1c8a0e4054bf173cf92d552ed73de2a267c99c6497985a08b98dce77f272aa2e8d74147bf628982ae6113877347e972f3b06cf8b8aac0e678592c9e1cbf525ee34076713d5a0a91e3a723ab609bb9123ab02b34df16e8b84dbda2dc184cc8a271bcea7126ed62e56c21c86c4d7cd8dfe25e9f9b15994d7770e38f5cc38e0818283cefaee362fd36fb484c81198bbb3e210d9e3ed5555167efff4cd7317864d9832472993b1a1dd50bef045c7be42fbef8e38e13400ab34a5d51723af20ca1cb50451b8ca9cadd8281fb97c21ee66b8acfdedcc7bf66ea2ddb50b3894f1b65c1f30a5a52ad94f0bd69f3a949222c37dd6e16f6ad03a36e69eb29fab7bd0ce087a8ec9e54beb98fc680e1ce3a700e2507104a2ce4d7589e1378a120f926468dd39c0711958b567f02fd6301b983e08ed2a3cce2b81a15fdec2e8d8b2af45e349fee5e94d7358dbb212c37f751e47f68a7a28286aa59153d997f68ec1a22a66e793f02932ca0e7052df82cbdd4f453bd2f310658a985c35e0949f5dd0e2dc6b3cd42a1b8dc2bf903d2309fb7e2f482d158216c9c572c0d35871f5e8f30b951360b9c9f36c5cf8411acab4357a0c939d8d83fe68aa1be30a686222455c01fbbb5e13ed34b178479aa7d57af812fe3a7453f86eaf1db4765b5153fb738594d9e75295528ca9834d42c7cc8e574766521e34632c93f1d62d685aafc8131d29ec5cc1ba92da3ad041d854b2761b7f8c87add9664ebecde68a456c008b91a9c66234ca61d984de78bb1a96cb581f4721a15a5065f8b5cb033ca16139de594cc9e2428b677c50affb8e1701ca7daa0be8e39390de35656866644a9ead3a01808bbc9e339820063c5eb3358e0237856d8fea6d1bebabec0353cd168260baf6fb3c98f8e4aeebd23f4d0a64ea92b6ce908b7bcb3c4470280a37e07fc1ae5fca251ca227b638a23c77bcdecc6bef7c4755aa5d0685e7e36716e4fbba09ccfeabd9591a480b7afa363eff247e96478a7bc5b5b6ff799324b1d1b4d02bdda001ada861f73d34ae6532e9616b2d1ad676c0c0588929fa08f14375451de5b19cfd21b9c0cedc6aa9d8a1f9629219ea86390a9f701b8de9e4b4cff04bcc9db609bc7f7fa62f666afd849ac1677e882cf6364557a0908413b0659fa53d7309eb2dc2bd94a4427a51193c403fdf001f6207ffbd6605ea5cbd56e604f2d7220c976de52b8f5e39b7e3f72a90c959bb8ff714b06b12a84592a731fec4e0359cdb53c0029d54d9a7075a28ab92b143e39b033f80050d1ef52a00edd8600e4a0c3c8c227f07af71f969ed906cf84e9cbb0295666c728ea5dc10dbb8d27e81c837502b02e77333bf387c4357563388d240234a3f102f643dec5c969e3945cbb2267d0b5db30dd0654a51aee237663dcf23eafd2e6d633474bdc11656b9843295214322b72fd79348fc84142ea521a28f0fea1baadfe7a52f4b12f302b9e34311bbb1a2db10ea8829078babbc1b26a3c50d98a6bace538e5a865799135778c31927902153ef12e06b8738889943f411744d9a6559ce1188cb6b161cce6d606de96f2fe49f0713eed1f002718c5c2150b2cbd5ab777e2b8b9e968f1d4877bfa70f59d27453b8adceb637b7b4b4c7040842006a9dc5124748492af969e386d36d118fe110437b58c0008c64d08f6922d5acfd24866ad20d7b9fad84afaa9a15a369812e42e2111dd0def0ef599780a8c5f9fa7b577389369e4517ca685a160e2fcde1cd47cc5bc4ce907bd481b10a1a8b91b9b6a9440bb907ba3d1534a25188ddf7e80808104209d6a2aceff457ab62527e1667a87921dde35528edea619875677f0d16c148d1e3c68a40c89392a79e6e162cdfa21e9700d948a98d84b80c72bc5d6d86bd234282555ed39c51852a886e31b08bf6e75f98247965364ba59322fdcc0744bff906a9b6fff6b8c4a544f3537b3918a3b079e6a5df59853337f4000f81780a506f463690ea3f07d96046feadec0b7be2dd25e539cb65df7a336af4329e53bcb3708ed5a1e2fdba737dc4f2bb66e587190326d6d774b20620a218c2d588e346593bb9b2b40818f33f606853576c2983fe7fedc362ecc860003d99f8dc43a41ce93265bae39f46c3f371c4b0dda97c700e06727fc147cf722fc28c95e0909011ebea34a5b6c1b80a58ff312f4a64cb502701c3585653cc2b9acbd35c5a94d04fc646e7ef1f9e96436b937f652d42d510faacf4d945a856426ee7df0e4fb0e7b116d2d07a84a198f2641ae52b27bc52bc555bebc6bf6643417640b99c242fbc9738c9ed6a5d16f7fbd34dbdc20ec583001db8f2ceeaff7a9c8aa8e66b20f97fa0d523fbd35ba6bb1b6a62d51bd2b36da8cac1e9bba4566f0b69e180746ec8de5547d24f8314c7780c455b115a65c269f2f9a77ebfd8d011c7b0fcdec9a7b7c86f5058bdf8e00da87c16724fac4d146ecc02cae8883be767fb6e1c78e829219e2396927ab1b2bc3def1a42cfdcdbe5240474dc655502fa72e9eeeced08584edf1f03f128b94ab2a8e9336cede8ea5fef4c49bd654a237092e29e5cf550ff284b5d12e574dd20bea8f276ffe53251547e56ca4cbf8e511e3d369a003fa4d9869a3bc99b10f07fe410cf1a0051668dfd1b4d608c3bacb0add1de34024a5d37676db4ad073a983694fd4352b100ffc61b9b5295ddc9f8da2c94a2ae3025fcb344ea673639bc24263f7df5dc6aea9ed4dfb4bd8256bae274973201f4f70f9fdc636b731ebdd7568dd7dcbd6bda8855a891898d49b3d7a35f0ca2e34c5b485c36c9ee5daeb50849a2ded8778092e327d8699b5382aa72bdcb28c99d992e7700a59c62bce1f5186028102414ffa70f004da7f9bf79a12ce9afdd3a26f5215127ee419dab7de9faa8136f132e8d51f958c17e54e3ea7bc3201d9df814a79780114ace094057031c65198c2b2fe223a47b07550951d26757e8613608329b09d030eb9ecd2c24732322b1c18871976a35588eea616d6d4d1f1cca70f2a3951cdec9857b33851183121da07119c30f4c40b984a90bd03a2a2afdc2ab10928c21d2de853355eca48c9913aa98cde53f19561c454c88e25073e1df0725e5f08090a012eb75c7e0c35705175cc31e05829b8db8c27a3554d5ce19d9d789cf4c49efb97aa6fc83bf565b762c3132ddd4b3649185fc6d8329c78b07ac1e24d8411a2e0a35f761c0fe10c30ad3bb42b35640267574831f41e61faae1628d8b0b1abf35e3470e4d042a384e63c3a7174a57895d441d5395d52e018694a4cd1818118b4aa23c8633aadc88995c332f6bfac8a166349ebfd06171313eadff7c9e27deca63c0cbd1f0f4193762ab3f8fabdf5a149c9cb8d03c6c0ec40e9b78b8c7c95ed762b42b4fa1644a4fd7201bd67c5512d13fa2628acb27171ac67484c45f70e5f20b56282088da46ce92d0bb03dfb15d872ac84bcf7f2b03c2856687d203b5ddda5878bc0313d181531fafe406675f02d47c18cf07a784524116dd565e5d2615fbd746bde4a32a9a0fa0eb47a00ea4f8b8e11c6729c4cec89a09b5ec7b3113dbbb0bd68c29fc8af943312492770e1db2dd2c025f1866ac7b4684919e5b1041146554ef3ed6fb940c60d1747b292b9806e7db92248c3d006f70ba3587a78ed08f2248d21989d614d8bc3f3eea2cdd4f5e866373a16ba2369b3b6d909b3cb597c816e20e4a2bd7d3de74dd640a340b5bb33eaaa6b0c79f67d1b4cfb82fef380d13f71f6f5f0d5c2dc12195b2421467ea95b329cb31dbcd031917a99687efa660cdcaeeeaea67cf60db745593498fbe9aa461bef67d8a3363d00b187a637c01674f77bfd890f1888b01ce30035caa30c54e8f5bb82358206714ea7dee58763fcb2305de749d87b13d40b3f910270e9152bfb17a79188fa470903784c58816201fd6601aa569674ea2ea296842a7dc54b87d8569a21e549614c5cee7947a74a112ca113593af2aa6a3865effc6e8f0fdff570de1c7587ab4b3aaebee043502bc78790f327ed735b03dce237300adc6fc20d972ae01a627957ccd011329643facfd736b4a64087a55d19ef855bd3152f71700644e08e3074a1f6078c7b67e8c4cc11f1b03bcd71c80eb873dc1fb8551f3b2e8ea5ee84b21da54f6ca9cf5c6555ecfb14c18d45013c72f369f70fe57ace7ee047b4f14713ed0199687faac741ec9be64ae1964f823bc912cba04032b7462942d9aa3e1a69b8f02af3c34aca59d87179f44bd13b88f9f74a1599d61ea60f704ecd2031119a5e8a1e27e719ed9195956ea19f059a1f5300ebffa35e72d3db017a30170cccfd961d9f31a22051fb72b2e6c3d9d7fd58b117d1e0a22cfc43c1c43936d04511e5be1381ccd1a6926089f5e5defc751aa54193ef0731c83ed726a2e1d01204548d57263da8cb0aa2ccb3ec1951de75208bff064b01f1414eadc3b335a162eda28958f69d81729145db18962e396d4df01a1ba54047da4da2871bcf00ca8b217397e4fb56bb31ce46f68339d3ab896182cdd2946dfaa7cd7238d3b8cdaa687fafa406f4b68a8f673561793e8c4a2c53f34a06d6e1188acf9453ed290fde14e70fb9445c49fc8187c49428ac58c8308efe059860bd57889e2b4bda7545905b32029f12f1220bbd06ca7b3e7c86fdf715b420e2cdc8238d8cbaa4d7ebbad9400afe831bfe0aa2d5d13cd37b1c67a61bd4349742e0f6432816acb2a74ff89280fe633ee5db7a7d5912e50e2193ecd62e271b118e2567d9314a72ede75edce8596bf4207a0d1d20743c00675a04ee",
"spend_index": [
0,
1,
1832806418,
4294967295
],
"result": [
"37c32ca712f78c0a2b79cf694fcaa1d5b9507f340f7990c9cdaf302e49115fd6",
"d35774e6a3de1804d0a272bbb9ef66aad6cfa0d8d85168f713e8564cd6efb18d",
"f4542fa05da4f3d65460dbc6d5405bc53e598b7c705522acad7c60ebcefaa820",
"8f7e23d545bd6a60f1163e93597898fc7aae20908cf6d7fe8234f938accd962f"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 1,
"Witness": true,
"Version": 1048648188,
"scriptSigs": true
},
"hex_tx": "fc19813e0001057919f7c800000000000000000000000000000000000000000000000000000000e65d7e7bfd32010fa794039affa3f3e9d96e19bd2307ecebc3ad309305dde575999a26b27b4262c84cf228e3ebc3d0d31babbf8759a65d0345a8c2bf61b9be6a2af584ff23531b5bfd0f9b662cb66083a0be67059d5ce61255779f53c7238c3a7177897217579cc2ff1d1eb2f80e29de5e4b2cb15b6004a1a08bb0bcb84c4086bf3448c14432fa5f0bc38f5dcd1b8bed4b5f805a79702a5c0085f68078d172d5b55595f19de6df3d2dd394c7ff16f07d3f6cbe26f016777467b252fea9500ba2cb395d9f7b6f20060546b6794f71875555d16f657502c02256bd753cda81822ad51759b5790ba5107aba32f0a7e91a9e94ca2603cdccbd2ae090cb081983bd3df7cdbea890fcb854dd1d917161b225322ce82dcb199f7cb93f66be068cd96ef99d4ee79a6b53b4c66a22026baa3055d2eebca3c0e582d49a1ff64e11234dea527500000000000000000000000000000000000000000000000000000000f0eb47f700d9b7f0b981d8ee7b000000000000000000000000000000000000000000000000000000003aa88cdba15df59d58b7f3d9273991b0037035c5cb84016ec440c3db710bae81a7a7162f8b53831c32f16337eebe086b882cfcfa56e989e46014e61cfe190f69d2adf7ad89fe29ae997d5d3d83597ee980493ecc54dd04f767c57aa5ff7f4e7d44b230dd4e1a7eb535849e0765430afcee14861640c6897473f36dc9e685d50285e1f431d602f02ff636c62184725e15da9dd72e113086db1242b411a5450b579feaf8b85130b4e2f8167e5f6646000000000000000000000000000000000000000000000000000000001d76f79600962246d98aaa1dc700000000000000000000000000000000000000000000000000000000a8bd311223797d73a99a97773ea1c65ddf29e4e025bd6d12f0d12da4146dced8b40f9e9f58e011577dc0f28e01ca1fe9e7c5785e0bc8fca81f655fb193c3cb85d9a0a1920457a7c0939de6d52f5abe57686d0b9b8b826170729daced19309b4bb74dacfb6d3ce3b66e332f249cb92158e231f79f5e4d13e82fbfbc4e943dfb57e13c68c8d0980aa49e135a53875c0479434684375c255739c8e256fdc943edfcb7276c5b0eb18e9a12d49b0122547c48534013b06ae87b9cfa3879e56fe2d729d0bd7a71c5cd6e9c0fc7021789d634068f5140d2482a4d799f8ba6590b2fbad26afc05ec6aab0f9dd741ece954a841770e0d3e68c1333657fc9ba7ab5ecd03fdff00c4aa694fbf47ab2d7d6f6cb59c44a81d3d0f7809993078acef49a26ab47dcb204acaa9f15de4bad7f7b066889ef08a969153700a1a12e94ec854ff26c73523ab66a4f993ceea341b8fb36ae2d0a4403ee93d6c06793c6762d2b70806d4d1ad1847d0be57413fe255b382af298e4801062f51cf7e4903b80002d75d6472bce7a548e201a54d227b55b86b2fbe4e99c021916391942dd0558389c90599318f73dbc336369c2feece76768fb4ca0e23baaba952b96be66d6f3c7d40bbb254f782e9b1edaad4aba094cea2110a3a563c4da9ea50f579e095d01aa52485ffd27f46f376b8eb5da3922c65ad27da94afbe9da4e2ef143f7b7204f5055ad631740e4ffd9e01766c13a9bdc924430ce32aa146bc075a579eec1d5ab120036fe39ba33b32ac6c5c0280df3b3e67103913255a4f2bab80e39e50f6a25de1bfd448128778d36534b5ef45a35caad784310cc7f60692275c42799946befaed27ce8e60f7388c39e5ee32b00b1c9baf4f2b3dea04ebadc268bcf65b694187b715aa98d2e7538e2b4f5adbefedc18d6965920ac4f97ec926546379f13562656617970b7504351056963e2e8452291b4e26364ce3298a27fc018b421ab2b3c0f4c08215d450194b8ca8aaed612f7a60e2f1a0de54cb616688e57598aa6608c65cfab1324e74580fc44d8763379f85cab070763d4dd177f29e01daabb4f54e4dd0667e57b0ab5fba7e2b455f9eabfac1f6b1474a097db21b4ad8e08c788b2d5609016985b8e1318c431cfaf2897fae7dad1e56e1eb18f95009dab214b20d328c24bd53eea3ccebaadade7c60ca23109937dd7eebdc31149f1c0c425b9b0bb1a09dd937775f284f01c391b13a7507e1b448e1bbfa25b159d6f11dc6143d5f804f4aa40ccd623258eabdb4b161e148eacffdacf6c4562f96147affb315332d094a25fe688647aef1fefd54017218f7a9aed63a7468e04e2e7a5c5101622f2a2947dc730663680943b9b28c21ac147ea83fd2ce98df5d029a3f2e1c49d0bc0b41c65f2cd559f0131eef6867149b72e42f1d0aaab36ba92ff28fe6dbeddc8caf96aa9b261cb9da990f5f11ceccdf6d825634effe623182b2f941e399b0f02be0bfcfa3d9a7f4f7ecfc805e8193974156b1a075104185ab4471bafa751cd0f8b614a25d79e3e5afe017d72b0555ef44264921a5622a88912e19b8a44a403277f31fd462751fc591493c60891eba1ec19e1b1ddda2f9ed1678b612908a65149b34c365888485cc47f4484f6f4ea4ad5dc11b0769bf61563ace4e43e47f3a1d5eb24a96f17a8fd4c5e6a65493010d0436543dabe7ce47a239e69f1724c1dbcca5ecbfaa12ba09ecc6627464e8f490ea115d3037d2fc988df238a3ff0960ad0a2f0a3ef83ab69e08561301f2bced3ef64beb2e77a6cf7d1c8f2bd8823772bb0aaacaf802cdac226222a36df8fc1d2a36e1cf4ad433ef61005e9823c90dbbc541755358ec515ed4ea951addc744c8b49a860718d08aaa5ceae5923117ec236ddd47747e186e284b4cfe5e3be29a1c0f8dd1a4d5d1417558b3652886bc382f6cb99c80370eaeab9ab77ea56301aff7956539df5971bc22dc22eaa10e46deb5c3bcbe7ca9d2e98bd9300d7510b1735c9cad57c38e01bdb9785281493c2ccd5a596b729f3c2f78b1e53ef8c360300ba1e3fddba198afc29dce9ca4bb35c44d34bdb2fa87bba1cd46e8b9b52208c84c4a02d87d57be9ea1a5f8aa2fd7d6ed8c04b73d8dbf866ce9dd25b537ff7aecf7496374da878822c2fdff94a4e4b5f22095ceca58d0bbcfa46d234b25dabdca5f372112a10ba841cf9fc0aa2f98f3149736d3e37f75f167e90728174b74afb8d14951cd217082dc03280db31ae34b71cd3b92472316a523bc8cd5791bd60edcf7bc23802244669e7167f8860d4ffa693a612ea8756637fc03d77bdf806c411aa605c9fc9f47c80b5de79d51780381aabcdeb7d34765a29168449eb7ec25164b5facfb63170002fd77016d0113b330ba114da0e1ec2376fbc6e0dea5d13ccb97e91f07324780f92bb4b4879a4cfcc62e04ea41ede08c420c881ac5a04a5e865cd6f39102fca7fea650f31f1585bb551abe4b51e06d840094620b09422827443a8dab11b89e5174c0a76127231ede40daf3fe062ce63b6c39bf9f502ca8f43fc385624033c874fea14a0bf8af2d0e8f878c65e12d4466bfb1ffa584f5122f9109f2e06149676378d414aa32f5d447553ee69fb5f182dd9038aa7f1e27d98ef5a019a870d7d9b8b0b4ce518f2cba8148a86ee53ccd74abd4f65277387681ff486f8eb9ba0dff07747fd42d64e3e0e9dfecc3c4d2c904f62355d07f3d5bc5cebbf4ab6bd5892667a135ea792cb4670ccb1e85c738638df3c3ca3da23798e3bde0ec1bba7c833480c0f79ca237655867fc86d41b90fa1accd7b0849140188f6acc0e5c0886adcdd0b0f69b3d5e0eb98fafe9c4d6e69a3e6c83d7135f34437712e512410f70487471a30d67191c6a30a75b278ea61fb9fac3607ab088a52ae54a39efb6fde90139c71fb9cc0c673ff4606c1accc1b525cee174b00aafddafd80cedc70d7818163da95f38b887644cf9818a35249058967246e8cd70a5676092757c94c9739190ac66b13b79fa59d86e2c9b100a65229b637fdcc040f4ce14841fa72d5169a4b7b4deeff4cc85ec6f3ccda4af982a3714ae14c6a527512e3e15b7f9edfa51a6869394d786867e946a0024ea8c8ae4cca888625300de49eea2d0c54b73c3e000ffb51671641aefd6089f4aca68ea5f161d60e4b9964f4f6961dbee646cbc9658ac1f0e8be238f0e23c472d699f998b7f99fe5bfa5191e5fcd7ab3cd62c17abf7ea2da7ad384180f2e81c30c347f3dbdadbf88a1fac852b5a0b504e5bf32bccd5b3ac0e8950af75efb1d8b7c2649e433bbe9bfe38dad16b7ace8f94c98002331cfdeea45e7c93a55f5b37a04b790e55c01cc377fda7ddc272efa95ffef7bc9f30e30cfa13ff1f423484b6eada061883bf78f970521380e39cf8abac77ea7f9c17275446031d2ecef94401e1b8573698d1c91decd47bf727f0dad4827141f8fc397476ed00eeb6b30b7809e53f3a0c28f698b18d834513f04d81357319493dad3128881606468978cbc0e7eeb7dc60337ca853d5b577745c0bad4ab4958da54cb44544377a533881bd34e774dcd072ba4cef31837e90d8030698f7aca565c8d53dee22130872b30f0008a203fd1601929a9d48a5e334f3e6ff49f395c0f070b1c6bdd244521f7b465e3bcdfcee15a34a7fa76298ff78037f8b3d2e8813b4b388905da8fb019863d11ecbd5de55b4c87c87d43260d706762ed2456d7dc73fd660e1f843007832b9c1110a73b74c484a89e09b5396ed59b88c56006bf111e2d685d30c45c52e9c95d3e9fb4fafedc73b885f56bd0d5a549de64638fed8e73dea52a27f589ebc61a097e67685ee93af6c34fc39fed019df6a22df2d08d499be6bd86a410a64c6884ceab9552880893b3b34421eeed78c9fd04109c02efadeddb7d7d53f6d10e3add56059cb85856ea2ca5a27e15b714558ce7ee2150beb2774e988331cf48653b85a00ef9d2a1eea097240e36862652002441e51de78d450c382e34ef6e46862fdae015738b3601582b13040b7fe6fbc6de4e456734c53e28f8d14242555d3316b2122e3af0ba377cfbab52de62bcb33dff5cf6b20a6ac2ec69b4fa6b7c2e3ea541c75dc9f2cb85a377c2d8eda281735670d567ac52ce01187c90e4a6a64d5280019f830c220df13336d77f957f2866119453d8505f28e794e7eb4f3147c87a6707740bff8cd569bed1758a18b91294043ca784d998763e7b8e3f40638e4a4bace7bfa0d8c37c1902fd27833e07cf3bf3dd2df6f218990ef22b3788ec5eeb80f6e4e0f1eb8711853fe6abd0e1541768f139ac59e621611427bb155ecfbc29a1e6a89cecde10db352d9e47fafe131fbedada6b88cdb8be8450ca1ffe6079ec465bb0eb09c8f1fddc78b1e3275caa337656cf9d950c07a5b4352dfda1aafdfffe4c1ab0a2f187e77681ccca41dab610784669caf96099a4ddc642f3b25d9f32cbfaf5a7e0fc2be682b053d1ce5852836eb5d92cc311bac97b15644bac2a976cd79b98af208ea418f627f12ec7cddcdbcea2af39f4142d27dc082f62e72dec885c70e5a9f0221b3eaa530682e0cdd94b77162bf7a754b7af5e66235b8385818eed92727d692e663571cfc05168be1022940ebfd5701023fb4b0525dd9771341a3cc7c30e40c4b8cb63b6ce521d5f2dffd78502cd60366ad656f81c062fc9681e816fa1d2996ff1781a7faa15434bce60053911ead81a4276b5286ef6c4fc275cf82f70e03321670a3711debd9af75ffe89458f6ed08030e72f3b1009710065ab123e7c1e0bc59def831366737ed18d296e30f0a0b54864c8bb3ea00f78019cddaed1f9fa04904bd95e90d325ab38636b5ef808e642bf723bd908b880a8290ab21b517edc655fc5e153258247e86da6cc4685bfde2cf56e67c4d2223f4ad1ab281e8fe141770731666738dd85afc02514b6570f443034fc13366baa6d93f21b4c0c4ce3890c2c3318f499143cfacae2399e2a0ea631c7abbf48dc4fadb9344e541733be5a422a2e8bb3e6c191f791ad3436b985264cda9413e1ea3e6d901ec9b415819c070b550a56e1be07d4e2f5f5d69cd0adcc82a02bdad4ac97af83e61507728be63b827bb021c4ceadbb255a5f1f2",
"spend_index": [
0,
1,
1745923530,
4294967295
],
"result": [
"a304cadaef6eb838f6df326869d80c806d58a93cc20c494b925c726352683c4e",
"eb7176fffdf7912174e560a5ff54e1ac08395a806d82cb455519c2a3fc55b660",
"2f8bf5b54a8d1d4aae6856c708332f620d186e0189330269c20e0e39f0329004",
"422e443fc02afed28b59d775310e5bd176429d7ff35bc6cd1023ef209e2233e6"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 7,
"Witness": true,
"Version": 535452497,
"scriptSigs": false
},
"hex_tx": "515bea1f00010459b69626000000000000000000000000000000000000000000000000000000000dfd2d400062fa8216f775ec6e000000000000000000000000000000000000000000000000000000007b683498000ceaa30783f09d1900000000000000000000000000000000000000000000000000000000006b76d100612bc5d8ad80741c00000000000000000000000000000000000000000000000000000000ac4553fe005ca4b29c073c7a98a88aab204fc83b558c87eae04823febc0d62216f8f50e8d45c6f63e6d271e9a55847541bb8856658546aedd79563eeade644d8ba23840ecd1f32e0e1b9da9e74c6eddcec47c6e547b9d59560d00ba00ea56fea17780a2415c97a7fe356fa79b46df5c74fbb26f814fea704a0afbba57dacd18551b5790668f0fda2a20fe32f6e9734d9ecc8c0f8d356e800f05b40e290f059e2cc0c9408a7794156edeb6cda5219a52516fab0feebd6f4060b5f616bfe5977404f37a0e9cb7b15b1403bd2ca9db8cee82e7b2df1d9c791167727167c014b917e00a912c837957b4e52619b1780a59fe0965f157ea9eb445e81ea5cf2c6b46b797167cf6e590ad4e2fe2f0c0baf47844987b690d5b1a4b433df5274f1c923273c441d301be9077d600861433c275466e5cddcd77f4468b0fa50daee4636e2669425c3f9c5b5e1bf8bb93b73051aec8e11c35d1d25917aeaf4b01b8e203359cff019a9bca8b8faa25a77e6658e1eedbd598666f7cc0f9b5c485bb2d39afd843e4ebb4424bd80d7fffbf8413fa8c9589c87bc230708cc056fb1a47227a44ce150ee65336c6bbb9c143a4d7989a16fd3e91d546c9178c8145678056c75de5e54e71c7116a03d52d470721711d5f062dfe7dbe7961798941445fe1ef4c7dc95f65f43af3b4d13de55f0de7e3fe90b1b75e8fe44a99af1b9cc830ba635fc410b2896b1b92b5bee25cb6f4924cbafff05491b9b50e1ded3f416d0b21ea074917eb30247a725b8ca9833b944484913795baa96c9c9acff901e686c505ee1ccd05290b6c1f69965fe029924b03ea086f772a82f26388cc799d45e6002f42b4bd57a9be968a0576b98bc4de89b67512d4d7b763ffa9f22a128f52de0157bf03b16e84e9445f1946f7a2ac8d36d656f71d1c292b966dc621b687c4f1a40358309363213d971b61d6153eb7093ffb96c6fc53070c6f3ba203be741cf669eb0458b0a32aa8f31c72b16767c68fca193015059a906f877c2d332ddc2a7a9dba3d0ccb42642791e40920cf5c6596f34ddbfc59322cc09c02cdad94e39d7a303e49de3e6e2a54a1598754febccca739ed188a7d60d61268c093035903eb2ee5a754414d9d03ab26d0575e88ea5321154c3191ecec3c6fc0a7e2f7e05351750e09a236f81eeb792c37b8ce475e47fb1c648877abf1ab00f7629685a812f6bc82ca6c53302228b6ccc8d5c9fc763ff2f1dca827ee487321338c90d0b81051ffa2da2370d34c928527ae0edfd5b3f972f4cb458f4cfcfc1eeddc9bdc0da78f416bccab97d75461e3acfccf8da45da0cd56e0e3d9388ceb1b1466d0e85a9a5c262b6e3f5728863c72d1d62b5294c954adc112dd7a6b93099e1157d113c9fb6f5d3aa92f3f90e2fdeadea2cadac863ad304d35d0ca05235484fb3439798b689746018f02fd032bb573808b2709c7078b7100f2d40c222ec9a30ef015a7956e8dafafeea28662ca4cdf117c5589dede37a6fc8823888e2999a853c5531daeba32e578913fc8e49ac6f57733252dae6e208bee83c7a9dcbb72dcd228081172d05b858066a7a8d7e888efbe47410ff0539eb83d9bf032d95a0f705d2869f06ddefc31489c9896ac79560bab1293b7a2b0f8fbb997f3a98f173e3a3cbb29a648128903340642a3148a0a1a5b8f33f615708c5b6efaf4ce13bede2e2751b7a20829a7282b2d88f926fbb1f23e44e26b8ff665d6d56baeeecd966065eb0db1fc0b042ad4339f1c1f9aa091eaeef7089592dba546120ad92d320d7e001a22be2337d5c8b6566c83eecb73af5abbfa7ae3b1749191dad4f5b7ff0288cb2b5373bc96ef8f8f429818ee9489f3fcffde8e58432b601a62465da63ad432490b97f9f83aab7289b93347c00c66ef55682eaa80e0fd3a8eff5d4388b1b1aec069e627d87c5db55ac3bdb43fac73618120d6b6f84c45421ff322477424252ffe2aec5b3bbbcb6536d7a5dc39813a1bc530ea3c9827ad6a474fae6ac4f09ba3cf2197a25870f7dee9033a10a916b3264f4867cad04f970cc3bbd133d43cb50045827687c02add9d4e5ade421a6e021f188474f02fdbc01527d824809c664e54e8f4b2fadaa4371d88b0ee4574ad01bf803c4ba806225aca73e858e12c68e0168bfeae8bd9e5cc961b798f14560b62f6087eda65f94a2fbc3f9917bf685709ebf3280510ebaf2893b656a80ec764f495d47f51649110508ef7b5762633fbeb205ca070869b741716c89859a91a0fabb35b28921b6c5a90a3c21582617039e80b61bc00786cd56bda070f1cacd6bcc92093230000ac7a7d7187997fb5da934318d65547cb9fd6355f34abc588ae76442631d9709db6760889f20df6669ad4e9db3e29065d0502e567197a0c6bc496cc4e9af98c15d74b1932b9e22aefdfc2a70941c5e3dca15b9c83f5e9ab66fd165c857510ab7d1814b562b79ba913ae004b69a048873a83bc846902a153b08b0324188bd75c0e318f2479341dde3ca8f81f61b33441a760bc76745a70ed62858405ae087b6620fe251af0a3ed8fa831cc204103eac583ab86bd8d10e418da656d0b6139e0d4e2fc1902161b6bc2ad28b82f693340ba6e45f3ad13ba8fc52a3a264723d285565a518b1af1fd46d5277f63f159293e686dc767b9c66eb95da37aaab4c213564a6093d94ba16b85fd71a473ff4981e74bcb61a4d7db1f4fa575d191434c10e34cbfdde01c3f1caf949d144abe593b9a52524b3aaacf8dff9a3d4c25fe2076d6a264795e52de382f24afc7373635e26daaae7b80c43a1a285c7ce3598045139742aa3bfae0e4004c030be8254f8c98150ce1c58fdc69f219be6750925ff6eabfe8cf00d04cc22560f9bc083a7483593f22803ea92cd567a1e0c6fe0de2b09170002c4bd5df3194cc29409bcfc88c49248093fc7b2fd1c812a62454d3c16c768cc1de7a9dcca40780f88432a1a3aadf2d6a2f5126de20e54caea02b2f00e770f3c77d64e764854f101c2181928a4ec8377f0fb861467afaf8a32f32412202d69cc95b6f1ea6dffd9f08709c9cafec3547b44c20073c0e2450794dda51cf3be2824bb68fdd4610d671285a1ccffac680f211e37c4074f6243b16c6d01fbfd737eef125e60acbff68e7684c63e5db89e2e056d5e5e514fb897fe4be075cfdd26cca3b7c8a2cf82f0c4e48b96faf04c4cead5380e57d19eea56a658388596edb1ceb3caf2af98d080406d72595df691a785d98d505347142fd7ed2f60d4652e656b7fc912a93f259e0595c7138a7bfccead7737284409b7d1a6ef2b341d1484161c7e069add654b9a92a426eb8408b6a19ee42a4b66b9f6baae81b117899f901c46d048b4756bcc142363bb637e8999079c0c2337100f33c51fba350568d322713b9aa45f01fd1901c919c7c579b233b9eba2cc93ec17504b87f4669eeba782a38c4c16fd62c6333e0934a72b580847d0ebe3b91d6376c1123c5923adcfe1746f87cf276ccc15674a32d7bd26940379fbba307d0afecbf564c8b7e0437b77128fc5e9d9d85ee983cf23d4c8bc69e212f24e0e502e762b418dbaa6b3a801041f9f8f0dbe5a21cadfa2c04675f4718dc795d71de2cc844b4cfb07d62edebc09727cb2487e31c0d908629c4dbaad67df2ab072a1da00b94394ec434993fd89cf68bfd61d7493fdd649574a554ea9ccc9b1aa00fa249a5de7d0895faff2b2d91b89a51d37268ec8f60897ea22986c01edb50372621dd0162879f07b9cf55cedaf153ae14d857d757cfc7e1d365b11101042d2d167103051f9b1435bfdc80670c8cf843100017863e7141ff0546fa57cbfe458455a98cf31ac368fab25a2db87f7c1ae7d3a6d83684f8560050cc8069039e796b68fc9edc1d8501ceb19e6b593c773022adb152397cfd8a9853afbddcc2cf3ec5c85dbba43b57674eb63846265fe477d25ed98c020e88ce914837d23922df78ade825388808798bc5e5fd949fabbf820",
"spend_index": [
0,
1,
2274644705,
4294967295
],
"result": [
"f879ef7cb7f507819bce8d6dfdbe97541312f1e2549dd441bdbfd7ed6d5932c5",
"8921764ca88849594762727400d22d26abc18a9d3c960b6888dabf529de31d8d",
"510b2046effdf94d4c171282607e83bc20312d9378fbc796805a20d95c97bc8f",
"b7dd2560894c2ad5e70447ad231ff15591c747d30226d26b0c6169ce9717c11a"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 4,
"Witness": true,
"Version": -888944471,
"scriptSigs": true
},
"hex_tx": "a9c803cb000103251b783b00000000000000000000000000000000000000000000000000000000c8f7c4bafd7201729fb4d0f26e4c3e5eb7360935e9bf440566e57bf40f0eeb83ae10b9f435e34d38a462a1935c6b2ac739994d78e02396d81f82c51934aaf5511870351c831b4eb97c9aa6e827ffb6766d4bf10e678ae1e9667df40810132f8421637d4a6e7c938a800702832739d6727198f52ce35df1db5f970403d1575706e2782dbd1c7a8d96d51351bd21fb07db8a2cd913850e818ce1032bd2e048aec5fe9423e86f0ea12e0bbdbc129496a9808aeb5f8439ffcdfadb09b03c3c21016061a559851ee1e87a88a19ba4a3ace6c025bdf4478337fab304dc1291a273df17ad1a3577d74c87af692f00ceefb8ac81c03dfd563f84e4c58fcfa0981361a4ce8dc2ad49ea28792d889f725216f0d15204a6603aed1fc330d88415120f83b839e546935e3787bf483d200af99b9a383200967471068062da36cb23af2b5e902d9c8a35fbeae15814d1599f8d218c049f0f5f3179d680dd29fa3301679cf9dc58d52b2901adbd2ad75f1cfeeaab4be057fd8ea5ef0b23fbff4fde88afef730ce08900000000000000000000000000000000000000000000000000000000d3e5fa947504248cd0ebf1870672d1b488d6e685ab1b2bbd5fbc3c80128dfc342e9698c38c912f69018c7b41c36ee8019aa4f08d1fbf204111061f361eb2e0127be0a7265c8ee7537c68d2f3882f732590e4c63eddeb1ea2a2384b61d9bb25142980b87a45a9e3ae681cff259e230f15235b5c121960fab6087415ca96389938ba09000000000000000000000000000000000000000000000000000000002ca13736fd0001a25993f1314f5e0c90ff7040519a16b00a0cffab57dc7f70b91c10e5f22faefa53c4878ecbf5d21a77f72888e36074a83b8b444852c0f05ee7d19a453c0b08d83ee2a6a326322a195a47c1e2f7524ce5afc13cd1fa14fe25df6a3e66a4cece3a2cd54a0b5f8fbf37d261e9e29da3b9d3702865b39d3ed4292c1f48d578600134df0efb3889f22a88060838591f2b142d25117627b0b343aebf18010557e611373dddcc4d7f6411a8c02c593cae67240458eaa6c833115d5e4b753726a0739bf26becd66db413dc47207e20012244b171b12626a1cece8abc3069ad0d45d68330c46269d260421e310c0a5a4a5efdb1555c79536c0811a642fe96d9e94a5fe910f60dfdb104a15c9baa71593917c84fbd4d265d202b34393df6cde0f53f4ff6ed825ebede1758c6367907ede27e473648824cc7853ad57d93df391d857678ba09318a8f0bbaf3905dce6ca495c1e96c77ecb3dcce0131ebba23aa297533e47ed3fa21b2e6119caf3110b1d3db806f823c5b943b69b2c1980beefa82b158531812291d74c2695fe517fe78b9b6586a1d64e94a7a9b1e75ea3df9815d60657abc47cf5ee9af8421b07ba66165ca70b3cf2390269e02d147258dbe9e9fe0f934abc38a870a31d77c97bca4b0632b606fbdf08a3a6007234e4db5b6ca246f6946c8d968dde8a10de3c6c0c6e8629f19d1b3bc51b582949ad67ea54620e3bcf364906692162135c1da48d2e8ef422cbef344b9a4d0b957efa77ca5778ba95cb628c541706b148b4ddbb5e4b340a5f816f21905955cadc022d10389a356641e24c429baff1db3b30ecc6ab39dfd2eda6a6b3fc89b955be6aed5ff35888de8b3d1a41ccc86a62166a610f4a831941bea7ae2d30153071a7a9336f548c051a61d58915f2494e9102e0fb37517e69e35b41216a02cba836354401b5f4d3bdc6f5dc15bca49db4dd953a5c25cc34728e988959e00c80cfa8eb6968cdf0f6c76496397902420c48aed0fa610c4d518e8e3a8ca3e33148292c266dc2c2b441898fddec53a6295983f97ce751dd0dfda8713291be81ce6d12ad8c4dfeb274c33c323645fb78fd11d63f3548e275fa5b7de6720663c68160a36185bcfa86ca4e648cc7cac31115b04e55b590d451945eb28e787089afb610a1bbb0659dc4283a1130e3db593725ab2bfb98e3a3fd00f05949eb566ff8dc2f3788cfd1c11704fcc9b54a6da8daf265d7811ce9a206b220d3c4af63a67c5a1cf2c2752ee0054c4e2e8c6d647262b57c842278985faaf1a8a567fb2baaa7cebcace1c3b118c75a695aea39e91789a3b68d1abcb82dc94904d7b25027c92b8a3761106d9f1772cd5068707c4d7db9493339a9f175c42e113ddbbbec61db98cea297e0e48044a86e91153a13b8b8c6cd870ffe44f6f5f0a45971a0f8f7e30157855ab5168b9eb3152b45186a2cf2e82b4b2854197a8268dc2e90ac94245aa11d4fcc2016740bde768ba2de040f1cebdf3554a9492a83fdd76378d05908b4031ea74eb744878c31c6fd508edb5d76bebd8fd9ea1b35fcf7aa5850183e7d5b779a11eeef0615ebdbde6947e92ca39912fda2602c817e018816f729d6c093b201dfc49d731bdd52364c128af248e8eea1a09a86ac386c92fe71dca5c357b25b2d6de613b0f6b6cfa538944a58d3b7ea987a78d33a0e6cb371ad862593b36bb336a328cf655be8b6f130010d59b9a02543b50bc152874449a2d50310e8d335b2b01e8996e04865917c6344dd4503ff6f8cbc587f97a8311d82b81bab515becdf3dddbacaaab967d65d2cbaebf8a3d2fdfc7426bff579ccc377a3a1b269f3d678fa03a1f1ce684ec85f3d8ca636c4d4f0caa0a87fd223a9ae4d690ff4cde281644891b3b569aaa5258fade59540e96594e78beb8160339c5df01564c797b9842fcd44b0ed9cc2e3d78fdc249b4abffda51b8f1e59737b520eeeeeea89231a3f5f637468520d830d6ac314df4e81228bff017834f64d6789ece25cf47ad5f9b72361d41f7b164b26141b2150bac4aaf56c9d39e319a1822720f5f97da745f299715523b4496ebbcf9b8b0a90404ff05604bfd4c01562494a70e34cf93bcad4ab44229231d261b15da497df316a8a226db63428dddd06aa6be8ef94f6a4f97908af6a4657aaf9e291bb8364cf00e96ac73ca638c25a9ce35a686e4483b4a17a1c11c143fe0b2fc6c30b50843d27402b1f6c5d5ecc474e239b22f59be749bb37a453cdc19fed02a6273fc85243eb20c453f4db442ae2b193bd9f9ea8da49397c0adcb2a267927561c1b706cdc6e91c6358dbda5951d3c4586448b37743dac2bbefe3ea79b3c453b30e99b1cfe21b694d85ec4854057ffc8cdc71f6bdd8df96a92dae2197fb1251c6d5ddaddf0125fccd569305b1ccb4b4fe6729edc18291d947faa64f7afbf74e0a11c0da2849ff4444eaab1e296f9de81b6879c0d6e14630fd73ec47b0c5808f7445f257813aa12202748a8cb65ba35d6071ae50cbe5f9117c78c84e389e1105ff0874c19d43ee2ec622204cd43e2e81274372407dfc7466c6bda6603ac18be46e527073972f958aceffe5eaa9c8d2101ce10a79b7a77df95c319e354db74eab5960ebe5426e5be31f9c79595fc29dab8ab1e40cc1f52cb2b3adb4c06719d68fea391ddaf9f96c5ee18e0052ea48e4f7f0cc7f792989b7f44a3856b06ddc52a094cc5a8fb0a562a79ce1b92178f57680f8124236d40a0e0b6856dd78d18b5ecad5c4fcd5abc3996b29ff8ffb1ce7c5dd877700e6ce9b2a7e231d5baf9b1d0b163285d4a0fa02f5ac93e726786202d5078b4fff0491241d7c7d945483e17ca661eb81a5045b7ee6b4e175270f249081821f7440e963ca43f0b563b2124ee45efd1ab7c76de79264fadc3b513ea641034a11d7b294084d9c4a31556e8cea777059415be90302c03f8f0a21ec651dc1bd0728589738cde4e30a9daefdca882aceadda3850eea452a0c356fd53e",
"spend_index": [
0,
1,
1153863276,
4294967295
],
"result": [
"5c8a06db6631bb164a1f5ceec23ef45a0db6f21162d737b94e502453c93ef43b",
"90c55941badef257688e2516eff289b8f0f6d7d4f59392e6c2ab23983010346b",
"fb1379eec6a0604e711556897ba7af46e15adada80d34675964b20a2ec4dc52c",
"c6f673a6d3aaada09196c8bc72bc63dbf0657a1e623370397f2fcab93f19f61a"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 9,
"Witness": true,
"Version": 580803147,
"scriptSigs": false
},
"hex_tx": "4b5a9e22000104c65d934b00000000000000000000000000000000000000000000000000000000bf53673f00058019c490910b2e0000000000000000000000000000000000000000000000000000000086ed708100922d724fd631303a00000000000000000000000000000000000000000000000000000000e6b4819f0035a755681a1881e80000000000000000000000000000000000000000000000000000000033da8854007801ad48096dcb11c966fd0256c8fe93130a73f2a303453dc954b465760ade7ad8900c35cc91666158e193bbd2c41be5a02519bf5759e47054db65c0d2fa395c0ac8f6d33a850cc3fc588a1432af5ab6c1efa8afbd812a7dfe0f4c6e22b77cf973454894ccd88a9ab6c812e249515efdcba78d830e27c4c0377198e7a3bd64c4a8a69fa21ddec9036baa384d1980ed9fecf8f54577559e9119f806a65570ed6ef54c56d0054b550675b7f18e1ac4ef6be2cb82b3c57bdc92aa273ffa0116450e9454c450a9e28dbe68ea756700c50548831e234f5beff8555cad7620692bc874d6d18d402476964b3c6faa9c39772e99ec65ced20b421445bd577c8316f64f560e278dbe89f595498fe39405c045749482c71f744b94804dfa414488cb19c79268c47f8fbc208f71651f4bc7c0edd892229a624ef8d1ec2c39c4cc76323f984cb2859abe3e5535488361e6cfeb9a608efd8b11152735e7114ab9273f96a0fd4b14b5f27d8a646f6c6053b3e62d902f7ef559133aa7a00a408f9bb2b2b1c659b484df8762a93a8acd67bc78bd0ec14285fe3e0de18cc30b74cdac50ddbe5a274542fe6b26afc17acd0921557907e257c86381cf9e0307c3cd37b63b9acddfcdeb4fda9cc1942268641d5ccf320ca5ce28de57687565453d385c90d84127f0004de6d7462af9c400a394f623657a0f6c9ce4331bf11cdcd56a8d84c45d249c21837ef50d348bcd221372ac7a3d4c79b29a20fa290754980c96ac54d701a20754d63c4a9a4e065e289ee9aa02718d11bccfb61926d4bdd165d1ea94ba55342968b89fe391dfa8d6fcdaa4a7d1e23ac230ab1a3ce163692422da91b80f815fa0af697d40f26b304cece4e399ca9bc79874327ec1b7402c2e338df54092d6419a554cc85edb919ba3fe6ac556a03c8e21621ea1415aa6170d7724a3ee66a1a25eec67452ea2f0feb0d6a8973b916e259b0868a242caa425e9e04e629985a3d3fe6ed92e18276d013ee33765ef03c66b98739303a8f0121ef2e7d49f84d578740f46ff60fe7db6dcc71f27c5ef2177e90645822d512cfe704a5e7fa8d8241dd4574bef509b18581f5b1ee916130dc89e0efa35beff49077f449b22f9c1d8712312612d2c59eb0c0f19d138e4345eb89892aa037d3f39a8dfc8cbc2d034be9dad2c9360012568f7acc2de7591dbfc5ddf15836f1ec88f65073e185a60e1c833664f3c843ec5cd7b52dee3035dea7bf95bdbc7a6ad865288b83dd7d446ce4f8b543b790fabe3dfdb90fa6082e5e9f33d343aa3dfa76d0083ec8f398e193ecdd8bf9701b539caf8f6d7eec356eed95999783dcbc97766de1d93e04e5166748c80f71069d467485c94d4904216c6594c7698119c95418d84fb2e9674f2098dddd439ddd0dee560d5370b40508a74f883cfcc6ec1bbfb1464bab1382b168581484abdfc16fc7b21d18aaddc42e05b9de07645ad36c5a3fd2b34fb1d92b47e64dfacd23b8bf3a150c8131348eb04f53b9104ab0949dd2de77d3f881ec5963d6a05ceb5b657fd950ac2ee021bfeb8c58cca30bd731c2f41296c821af25a393b5246f6ff49a5a2c56f9fb882a0ce5c6878f60aefc598074235fe6b55b8cc59e8cc92788f2022688e2b8828c58d45f7663ab1aaf5bf66a11f07632716bb503b1c6b3753c6ab82fcbaa52a0c30e8ee6fdd769e21fc7358c4e3e65f6277da87028a49b8b985b7e0a9fa302393f81f340a70a6ee5127ba5711e351e67a588433bd14163d3ddbd41e88f79325d6436c2289cd37521739f728f5caf35dc8fd6f134f64c62155ba9fc49bf3e0113096b42b938d17f992f51facc4f5f02457bbcbb8090b72a0effbc9146cdbb640e3620c33dbc38726a517ac7af05242314f5e7380fa4cc40ec7a9a2158e26c217cc51eb7ca093b6425e9ecb64e0dfafd4a7d05a941e9abe755fbefa0f44e047a9a7ba9f29fa0488de73478c94345c55d3883641f85e6549eb407b7ceeda048bfa8b5711526cce638aa8c7722816c9202ec84940abf38ae4e77172b4792118b674a842c0be40058d856b44f18e5e054cdcdadb38d143d62f18df307817955888565ac898ddf2dab2d813f2b1bb762d027660387af38882b92d965c6475a9bf0b4a4023512b9acc1767c9d385972fb000512b44c11bf1c3e5a7f263b61f61515388ef77c8bebbdfd5e858dd6115c154a8031c7c2a2dd6e2b6f2b4622e9be8cf339db0da594782498b950bc85733c2eb12491fb881390145a499c4a3b78503e9763ff9096e4054a0e343d247ae1bf56b2082e6043fbc7d0fecfb59196827083c44ddee9e21ec18e8600b38e1d4a56b564beaadbbfe99a1ac774fe83ce7424dc5267155a13a38146b701ff9c37c4381f0e5aaf31bc88d694a5a978f71a9d2e536da58a64375e9ddbcafad8aabeba5f26de48458cca691e4cfcfaf26a7f73091fdd06b7ed4ad9439873b9c7350bdc4d08178bd6502ae6b22f3d62655efa5f973012930f6c8f7a31c70dd7820dcfffd3cb860992781e730d9fa0688cfa6f8496356bf5facd6163a27c45ce66cd1335bdbbe139d4ec2b43bb2a60e12a03cf4ea045523425babcbc0f75f372f53a6ebc6b55f123abe5d4490ba62b10a9c0824a2280be6b8d0d3b67f9a18b8a8d83840c5fe44d9d13b9c99e080c569f379b4c0033cb28a92279718c225ebac555660d044f51e5261aff8bbe9c7a4571d377b111950b8dec8c55baa839b8b6cd2d3598a422e8fe482a1f9f18b5826bc3d84fdcd018394b85a87880c92caebde41be7e325ee598e0ed0d92039f1c6323288f554d5c1a0ee68fc764a37b3045393e500109edb1e1642e0c214f5d447cf938a5ee02699ebd8dab9193f80ea4efe5c5e230acb8b19b09ff21b478be15059aa6d5efa8e9546baab46a9251ed688a30cb143bdd92687d42f55ea112d0cc25c9e7d03ef7c6c551c3c44867b9fe4b4330b49a7223874304b9848396db39db404e173a6d9dd34862840fa6b406be38323b706a9bca9f9e964c2d2faab77399588ecd507e264023c19c53107ee9494f1e229fe44a808a323f863663cc9d1d397dfe39432da73b83b0a892d468727cbc43be9d20953f01b0d3a486152da5862ca258fb38e30ac01035d61c21f5ab45b6dfb51c478e35e567262e242b8b9b1e84fb650ee09f251e4feeed16ef83ef61c3b3a7fbe628a05577b284167db82452897446be681c855e987c2dd5334ed5d24979d9b7a19ab43e4913d815ab24b3cd5b802162e66ac3b05a77ca3b5f86f550f63b945c3bbeaa98b1b44f28c8d26aa1ca3181a4d3bf4e209b451274c599f5ffab358634c7835b8161937352cb9524776086c6bf4f521bb4e1f9ac95a8b77a4dfd80c02aa03e4d951a0bdcfaecb466337ced74be5092ed681d700e69413b9a3de7c4bd5a41fd6b0157edf746d6c5b7e04bf22453cc2f497aa5bb014972ca85145416540b6016412dfe9e6ff2a9ca522849b349800287d3f4e67c969c6f4ea93748d8de5fe494a59b2da1be863937d50e175a54b1fcb092e95db4756ef7601fbf5e52be7ac3c3550fe4fae6e865def4b7597780d2aa5f99b3b3a9415df887185e31d4ef5cf80a13034568313cbe0282b8057e1c5786b4cff765250fdfd0bde410b88dfac0ac3b32213743887eaf44c27bcb634979c8969d4c769e4ef1bdf632a72e654f3eb34bc69977cef88869555d6d3b898ea46c9f6f571a2b41c87246a4d1fe1f44438e683cb63875ad2422f3bce6f310e6aac1d88fa968348f085aac0cd17c7ab79dfda29de07f8d968847b34c75bd6ce8c973183f5a95681b8ada5eaf9f4041430eb1997e96692a43ac4cbd4680aab2e67e49a37b6f76887ab3acc8ffe6b680117f46730c06cd3ecd8503e828902e97fc07c2b3fbd61f3c566c1efdbdfb2ea193afcc9289bef4e74d9baff879382ead580004fd4b0120f8956120f011da246bbaa1af3b62e78c9a35911515b3322cd23d0e56c4e827a0a9e83fd088c6f08fdfc59bc55621c40fa8841b9291dd40f13a804a7db0777d285cd4947e7f6f83f7673aab740ea69d5a265e5d303585332e3cd5300de52811490316da607fecea530e5660c8601ce66499657feb1cd53f4dc1deb7af6ce8506db0faf0868ccf4441b23365accbcd7045baa9e0cb3dfb824689750f144fdc614000a51b0d39217704ce2b53d7638824c6bb06922622e07db5727c1a33705087c7576942ca03162e161e1a0f9df27fc12028a4f8495bd9f3050b740d47a3b675aaff8734d595213d58084b917d1bbd3e1f204c1af9ccdd9c180b10fdec6564119d6302831ccca8c60450d6bb670f0ecb185b0fa27ead66266e19896ac4d4087a18ae159fa622c400fdf6c88cff0a016d788d5351bea2e51bc8788b08e08e486e99404231289aa7ed4e9a59fd2b01b3f52284c1b0ba242eef612e8cd93fbaa20dbc29ec3d571c02de4592e35122cbf251160241f47ce013a9052be3c4ed3a80035408a5df87518877172e1d76e576b651feb103e81e446d82f8ee34f7340cff28d2f44228a9e9f3ad1713a384abf39229f8200e025e09284c4e93411c04ea1a10b871aea77dc155fd272b94bd2c60e858194842bf8daf8381c747ed10289b83c0947a6d6e2c9d2b735740d6560af9e8f75d2fd4e72df8f2ba694274f4eb84edd48827704a28154032dff2cd5509debf795d80d0d1f23bab219021321d50c774291d99fa621ca6e66bf6f3eb38f2f5476830cd5975e1f7382da2a1f4b27fd0cb517e41e50633f370705ca72dea4dad03f12a41f051cd31a1fa91c7dda603eead5394ef291e4c00ef4b205ecd949c7402bd0983db716c38f974bf86022fcaadea58223f9aa1ed4de669aeb7ee45c26cafa185d4ba208bffc952de67abaec90b263fadcc5c884a13eeb446950e949ef3eb9ccdefcc461c49159a18035a16aeaf16921ece02ba62455df77a2377b83f0f509b936f7ed867d7ddbb1f3df288c4fc9b3cc80f96bd607fb3c84807a83d610f1645b6aaba175913384911621980a6e3e531fd3a018641c629ad7fb6c613b42f9f6b7de2adfe2a4d008d8dd203a5f8c293d1d6191c728cf71edc6b0057ba8818d242dee43dd02722142d6fea71310ff0f822b6675f2c4d4b49ca9987b067d7c094304295b027eb58e9fab52cc4b604d56391b29cbce2fa7649a760cd8e221b878668ac6afcbe3f35cbeadd9d0292de04407da3519a185504730c42c90e338045120774bc3856b0f4b97038218a0ed0adb355650afa77b08270cef2ff292e0e253224d9d9a2a54da473b02afda724dcc79aca703022f577049ffc1584d4edcf803b17795082cd398613c7cd1cf4e04065389c43a1b0ed11eba916a17cbfce8f3036296dc8377ae662ec2b25bff9e2c0020fd888674bed90ce5f5b74127b34c6e6867e6ef167e8ef346c9f87fc8e89e983f416e0394f8161f0cc2c3ecdb5671d4b202f4aa4b76cc89bd9d497bf2492cb03c21bcaeb0ece7aa1f1c9040524f218a95b9e1e4cf8b0e33cc9ac151ff00bc9c25748a90c7843deb84487163eb12b752eb670a852079394da01042def421bb8e6ab133663fa9c46df43856e06d08ece1d2f518b4e60bce03039736ff60d1bf030e454b845cb0b2e38623605e4924bc98532281194772ec6988b0bee8142acc559ef3bafa6461f4445e6b2ac2307d7f48fe70efe6ad8c2fa9a5e80cfcd8f93dadd55917a054076426f25b60b09c466d0fbac45fcec52267b2da9a76731bd9834c7b9f67bfd9101ab8050977cd56c6551f8ef7307d978e9ac8fe1eacefe970a29b1445f18e6ef70faa70d5c6ab964b66175e7e7271ee0ca85d034c56ae9f374f9136cafe897734749697db9c9a1c20c6887f44050164e54081daaa5f81d3e706d918023b449d252e718d99980a08eca45987412a99a0044321c82472ad2655a1d0f537b9a312311e0f5f045579b2d011ea21908938a33b45c5fe32ce9fe3ca5b62ebd782f08b38f0a196c152e8e117c1075d3c4fd02e2e0d36a3b0269aed464840dc687fb385e32750addccfbfc75ebbad8b05a2fb8a40665a516e505ea9653cbb0be63850aa49067a13a1b55f6f625d1217ba67afc5c4ee62ac7d38bf368a4ef915e08878e2c77e1a5e733dec8e0d98c6c58ae6abb1f345cf121b1b47abccc6f388ee7f84db7db7fc7f1b2838e41e634e0d98627878e200a3c906dbdba79d31d205baf73cc60f07fd0458267051ab48293d5145b2f0f48e46051107a671570171c48d69ef56f9fc982d360da9825e2c75e42dea21022f6b63bb3d2606ec768e5e76aca2f0ed3c5024a10396bf397dcb73c72a9e85e0d29cdfde4016b1fc6c6df04413d2cf71f573d302295c3eabb06b19963c2725a1d96313e5b6aa6df04429fc61e8dc971301aeba91d5df5e78338b37599ebea007116805f849668b08ae005ed60ed21380c1423deba0946f96ed87e6fe7364da77421b08abc5812c7f01c60a56f4e6f7adad3d7f9c2750fd89a2adbcba7a8adac20122b5689a04090640d71c20005fb5b80b6ad0c6b49883cb5cd2050dade8beadcb271d7c33b7e1fd1b2a94c294ab10a0abd4d6804e7f9c5fdde9e12274da8518eee580222ee582ab0b9f4c357860447a1693dd14e1fb284aa6a651ddc7f2c942453ec6ae5d16634020390aa8ce3d681a2876eac4cf42157f48956f952d0f05437ca5fdfea4c132a5aee42189a667e171ac6c2003c828864100f90dcec8dbf1e11d574d008853961d7afb8394858f370b96f731b862a44ef43d4161aafe08b3d4ec58d23318f7ba4470269330c8fcf04846be12c291f85b38242913c36e496d99b5fc642893c76498bb09b2b7cb620e95955e4fec18df39e626beb790a812ad2671539172ba2cbb022daed43349e982305e404bac7ff698027772cb6f24e3747376a30662ed88dc797f1c3ee137aee5f33eafe19c3655df618c1a32e8e16275173dab15079c6cc88c7f055f548cc309087f30cb788516e69fb3ea9ae4b00b1a2a323c40e78bf93538be6caa0304a",
"spend_index": [
0,
1,
2939854918,
4294967295
],
"result": [
"fcdf47a1ee4ac0d669e3f28b02780f79e19cd82d966bdf50f9b767b76d59c471",
"f8fa3225821bd05cb845052d29b83ac971602c314690dde1b28a83dfdb9d475b",
"822ab57d856af2294bdb1f4609c36abe15aa2a01038d1ebb1bc6bea6e3bb97b0",
"bb3a5942ff153f6f57b3db493e78e3a3e591113a563abbdb18e2bcacef8b3773"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 7,
"Witness": true,
"Version": 1953367418,
"scriptSigs": true
},
"hex_tx": "7a056e740001098bcf013900000000000000000000000000000000000000000000000000000000d555310ffd7c01ea056fbf3fa34a33ea5845071d769bacdd9223b15887a365d5735ac9fa2aef798d067e0e48c80a6ce7adec80a6677c0a8fe36d685e7c97bbd10496844d28d72deb185934c6d20c84c5af23ddc9e10bf700b7b46a587c519a097e04ee57ed0d62e1b1a726df811d81d84c4b7726369c79710ceeca98cdd7bca2b37226eb1fd7818346590f2ef5d98d0b789bac830283e70926330912a20309863c3d67345a2dc35c49634df7b32ff3add43ef19b010f59b252bf286b28d91db3c98bfc0afadeacefa97b15f20e9a7b7f5f10e60216b5a2b40e72b2c142dd5cfa6e19c7293dfcd38a944b89fb8168f6bd13fc45d7426685c753613feba034cbcc46d6da0e9da4916bcc68058fcc291f8c68fa4fd07722159ff348c2888a6cb1d45d1de52be4c3ccf22de16fe6a3be6b46a44a5e516de79ea39e00ca62ea08a4b72b7ced5fba7b172b4d58413ac4b298f5eea6ce738721008f3c4baeedfbce01d31c20936b36274677fabe387c973044a927ab0949f1e70dd341a2e010647f519cd8020a8fa998e0da68ccfc000000000000000000000000000000000000000000000000000000003a158ab3fd3b01edcbb535d5b64a7d6996bfe17c58e2a5ebd3ff252642c05e2e1fbafa1d0b66fb4a28a56b02f0d6016643644b5be63eb3a5343c8cbea11710cae3a1eabdf122ac1e567c6b3d415016d06aab5349b0bfc7685956b87e89c7458fbf6b86ed302cff73dea07581398319e35676b7ab00df8b8c7a250fe7dbe0636f45cdf9865da0f36f5c613a60b4805c6cb0a45b3f4955839856f3e34d629eca4620b7095071884f6e07ee83afc2351c9b87073a80e0fe196826626230a61a2d250b4179eac303e627c462daea938c90e0fdc82a2f1620a640e3244f834ec59dad1195ae888c97d6c6028cdbe2ff1e185825d3dbcbc5e3e0e0598d667549041377bce0344ba166f4074168f787ffa1cf1e9ee03bb32382ed2ce2949f7b6ed75959f48acf0a4bdc1b154f580874a78bca650c38b728d19238e69170440273fc405399476b07aa086168c99c000000000000000000000000000000000000000000000000000000002ec4eb64c124b4d540d391e34f4f6a42457d87c5f45bc7f8c1c73bf51d9bd49e0295a19a76f17698ded03f2fc58ea2326fd623e4585843b105f2dd23c5f92cc350628a4bb731951234ce97b2a2b6239696425120c7c79d071b1e12e88394c72c0b47f7ede3283d8620a912909d04ccfc41a4ffbda31d7469fb0076ccbaf359d197a175ecf368ad278f10eb6945842710f816d50ba0ff0dcddfa82b93a926f0b7abf534c162915412eb37a177311ed1b4f3832f8741ddccdba7a6fec008eecf80c915cd7f6f23b893eddbe2905bf300000000000000000000000000000000000000000000000000000000deef88f50a4d1436c03c15c54a01e47ab0a19ce75ac398000000000000000000000000000000000000000000000000000000002c0ad335fd0101d18c5eeba066aed82cf79d250f693e64db9fe9bf370b6c7d4b83a73c61fe3e58dd94960b9c084720c4dbaa8e6f1c6477e341e8fec705f1fead295aba3a39fe8df2ecebedaa5ef3f625b9e09cc81bae99faf232326c4fb9574b4c648916a33ee2a9d513d2c581ab688a5cb2151fef7a1e7ef1efe1969fa86d0564a89396cfbc3410840ba73cf10afcf8603398494cc6238be2dbfcf060a7b80cf8590aa8498486c397e88d947ebe733b1e1473db3c7e35463d43cb926c9e226268a9185e490c39b4f2c595d1146d4545e283807225841a84afc241c1462757fa61f8166141510f6c0dae771ffd5cff4fa63ee57ef9df0e160132a99cbfa560d6f0094fb51db9a58e078c6b5ffbe28cb60000000000000000000000000000000000000000000000000000000043471405fdbb0133f2194de97ea27663309e1972d1124cf6d7529727a99ed9ca9b4c23f190710a5fedf38d07e8b9abe3753ea6559bcfc9ab1778d2640085e78db387400ba692b3a70c84956ac0dbb27a1c5a668a3230323970d19035c28cb05dea6f349e48411f85cdd607654217a3aecb8b5d9d027fe7d52f01b44eddcf4399cd5e62e2eba24eac0324ea405e9571c35b193ee907e45a2d3c4ba062eff6fc3196936a96f7a70a2fc350f72d7d5a0fed32f3222c8a45da5cf37707b3ae37ad0c2948e4510f20e83ddb12ceae3a607c631a82fff8967dadd85efe046fdf51361692a9f3cb0e0226e90309f21c5b76016d9c83c80a290188602ba8d1c85676b03354265148befb04e32737b81b344a0608793c2bb3232d18f560a607e557cbe8336e4aff395892bbf1d459e4ed3c61a57e19ae46849e63d1335ce19b656cfc7b366f89865403bbe44697311623ffb4c4967d190466f5e57d85ad9588a40ea9df468fbeff09bb1b30e77fb12caa074e1deac70d32e51ac56fa80a73b45c94a730cb5399ea80a0aeb6ca1ff84b1be8c6cf5d4ce1f639a26b640d993255a9a40495705af6f08088cfdb902f8a63cfbf1a7d305946704cf51f7328a470ebcab3414201539403560def7d73d885000000000000000000000000000000000000000000000000000000005a17a5aed9e7bfa067da9b2728b085c6698489ac84fce97583234b2bce8b025df43903db6ea89229b14dd458ff28b3ca944c7c03c69de8046dc43b8306c12c7b9d04ffa1b7b46b8bc06fe070433e98f679f4d6102bc804524fb69ca710920443b2eb018ad58c280140e188e7630ecf759e941eddc40cc6509e997876b4cc95d3b93ea694a53f5bf2154e62f45cc7fbc53161012dcf4a36d205137e6669079f24c8fe697ca9bf295190d9fee3c87e57c944a3d7f7967ea26b7d882d08a0af67c84f35f79312d3e65ff491ff8ca48ef9d52bb07d9508d4ec962675ee3f5d51c129e23f69f1eed2000000000000000000000000000000000000000000000000000000004e14f231fd4b01bab43b885e98fa91a306c49a83f2fde5d6b565b2e92115956494dd265dc32297acaa5aea6dbf1c08961484cded9936c3d454e959a1845d12d847c4cc58da82528daed5fd5d36049c38c5197026ebc3b1695c67ffb3946498c85861f7883be6ac36b51ba714f9fc6b128eaa06244f4a5059ec01227a7c96955a2aed854c3cb235b2a0469e3e9141501ed55ffecf01f112c78466578136349e942eb6f49fb7d8a8d02329990ef3b09ae966050ebcffcd18b96e82245a50731d483e31e7aa71d48e114849ea12191dc800189bfb49e1a9dcc7c066ebe4194cc10437b1fe7567fbce122cc5a7802fa2be59ecf276b80c9f736a15a563572ad86ca2e65a5f7db89a8c8386197161a53598d01ba553af7e3e8d4df7525ed51f0329df19bfe09ffc5e61ec8990dba96c0624f171415c31be1b4f22c241782fafb92bc1f3848c6cb62da62e8aa8e84ac189b4f9ee0868a0447d6c93b3df000000000000000000000000000000000000000000000000000000006231097bf5c68f6239ee9ac7b3241cd4e8e035d2eb5c2b47d34e9fb6dbc6f2632e09789715631a0902a22d6634f74de03b1109f9904445293102d332dbba8a33aaedf645aa6c48e180ddace3cd3c1089c4ed30ba45e650cbe0b974e5ab88a18ad86d568cf5e59f28d80a99f352388cdb7184e15b63b5ab596de74592d64136300639e5265f7791d779af16ecfe00d22599e6ad4722aa6064cc44d7300f6da03bbe4cff1d216da1908a6ec573e661feeeeb170ea28076ad16e33e60a9de378120616c2a7d0b86d40aaa6c18fe469bd52ad59c8a49f97cb7db2a7c59ac2338f971621ab2fafb5353002aff8908610d980fe9187de1da45a37c03f90a1754fc07c8870b9417662470c88b09a482877ed9c2f6016dce329daa87cd9a601fd13bb6517470081705ff21c69cc3e052eb9f945ef91b62284d6b1a9145624317542c79dcad22306be86837318d07c97f398f0bda29a6ad0bbb38f52345c92d5ea377b81c8b59cf2f00850ab79dc129885b1acae8388867de3c64aa5fb867c3eca6d9b8e82b750f40a248932e068e2c959bb5ad00ebb5f7ade72ed6e6cb7aaca6af49f20b69acbbbd1feba026730f3e96a57e4a199fcc2bfa1620107f006a3f7852b24b9bbd721adc92f330121dceeed778395cda3102b85f2daaa83ec85fdc422012a0c63d1ab193c9548ff5eada3393d89aa73e02cfcbee0197c47649b55a0f1ba0b53774ea7318f2670920f5a3bb16a2b85cdd41612b7c78514334fe44b732353ce9cc37f0662478269665a3e297ae500f5243190e3d4852aed0f977fd5080a149a6a9ae08c1db7ff2e45fe601994f20bfa7c60c744324b12ba6949474a6eac8fc44af2a8b5319a0736490da32fbff34dd1205519a845bb6d25e1bc7467456615f536e8727d1a7c4658a03c1b779b6fa8774705932fdb86c41d375d9dd4d274a9da287e9345111e2fc912f6ac82b9725be4b1d46998ceef310b364b05a0253354795e276eac0fb44a64f5978f7cf19ddd0918ac5639c85df690673d7b365ef4a438b3a81fea448fee96076571273649a86ef7a5b7766eaa2a072e6ad585564fccbac18d2fbf425e4ce024c2a6518250e84e346a96bf6b6abdc1a66114e7c03dda2bbb47bdc501ef2bfffe4ba69d28df907bb93ef009f77700e96c5e85b788006be37c56c8d4e4a396ff5df743b04e5972125436dda0b85be7933156edcf6ec3bdf9a72a8166305c6f5524dd7931d127470e56ce71327fc7a6abf1e655ac86c01e4240cc0e058b1be9c737afa12033425fef8d3a0858528559071649d47859f00a9015fb0b4eb7b2a2fefcd49f409e89951e3b4494f9a09eb7cc24b9696b71e226cd21cb4a4d80fea507b1f67743ab8f273fd1041f4b4324714aef580f7226529973958f8976560ef81002df6b5e69059d7e452173813a50ad6c1b5701c7ac55bf911cbd8ac29a650ab8dfd5e82d98d3b1d9b4548b1dd82264b246dc6736e242de99b4fdcbdbf2b55b54324a48de99c04ee4ba8c0ae86c3fdbab3cff0a01304f0296f59936178f54aad3d20f9c31fc82c7c9621131cfffa63cdb37852249bb8a2aaf89d8b55039b98a520b912f64bfc77a1f38e1eec65ca12fe2f7735dd12bf66cafb1742a5e32ce5943293ea0ce41261e56cba081dae2055acb248e5980c2c097b5d73886e877c490c6da67865c2d92aeb970cdaec3ec8191b22c69bf6ccce28f7c823428297f010cd4be2d024cbfcfb54e19e7cb70b543b9fdd018e3601f8567d2dc6a9a2f33ecf69db93a1317be2173ea699802907d2a638776c9f696ebd8aa823e733978fc9d3e72cc65c7db25db3bdb93c34ae2afd2e878b40aadab278c890c266108dcc127cc81594c9b1219a50143a2ccdfb1682c930af8d6909da98ac581c7fc09e7f52adfe20fd281422d38f6a167a22ac2eb389432aecffb5f86da603144aab6bae28b05e8f2a795b821d66ce1c306e87a3f6c306ae4c4ab6c7c43c99cdf7723856d43cc06c0c6ed5d7f11942428199d77928db18daca6416af014ea4136da02a8d3cddc24866a82f717ae97ac84588bdf716b59669fb1644a8b91b15ee6e4d27a1956b59ce0bc8e70529df27a965688971ab7f93c43299d0bfcb338550d49a717d58c6ecf0ba6061f55528c842575c8f2aeec23f1f08062fe8d0a40409611fb0280f43acb624e65cb72f8a6b46573ae016a194f92cd29d8620fb51341e716020081459995c6fda388e51ea6f7125d1c94ef66cbeb7237c385ab51a29899e96dd91f24d3f07a28d0375a733636cb71fc329089e1225827d75c1b8261aa583462b92baaeb58cda6c7fac91bcd3bce111a7d6ac21fc571889aa6d70e33e5c2dd5b5c9c8935d646842051496a40f418a660225874c9e9ebf8deb8552cbefcade8e053e8ac92ce39813ccea9d7a06aabc6d12b8efd4b30221de0e41fa3a7414119366edecaaaf5c1b6ac4f54ab5e49263e255fb42f9ab883f2ffd98017270bc88bc9f0833bb4a2f8ced470d5dc0dd1dc065afcd05945057a02b8feb229df5057ece018175b1314d3088de468c9f9d4bf2ef6b6639127ed2f914c108cb1a433719dee25de9bd645981f2c325682fa8ee611812ba947145c522ee8827f7fa866db908f350b52e30188b68629ff877db1bb6227de9fd3d4491d8244972a0cacec3d87fc6f419f8e57fcbf1ef274633b6f888f3a9c172faa5f8a3dba8265ed8da16f9bf5ce6f1bc34d1119d538d8a93b76904084df4de3d37b96682125d52b0ab1827108c779b64198e6576d250e37b9bcbd5af4ea7586068014762345ebbf3a76584a84066bf46f030bfdc08586ce0c124a745fcece664872076377a60aca14cbd48fd6c7a7c93ed1d576304b73e5edc101215336a9cd7381506b5d3d9746fb10c5dbe34c23b9570feb87a67b440f0078e45f58f18f62467c74ac3697a06511372e33360860ad76005cbfd3ff0f0c2a633fa7afd3cb3e988e1895b6d91027a258139eb8e8cb63b5385591872262162742b74cbc04edc14f1d62d67c9391f220931a12f7fa9b9ca7d5777e3b99135bdd430cca745f740000003bc0bada0f096e4c15561f7ce2ecc64717234d8164e14f61404d325e537cdbfd809437ddde0b3d2db9dbe1b0048453513ba0d697212a61cdb642ce60f308c109dacd2a862faac4b8a02b2996954629e6e551f852379e337e3f8f94b08878ab73f235b7de618fbc9891f1a9ccca3e05a177b0fd380404a17f2b6816e7195675490fc179b13b0e59b2355d2b89a7de0191d891e6343bff318d76da2a00c87529ece8751529b5d2ebb3c35539cf61b22027ee31d726ee33d55b1659c4952fca5bd9e9d37637b4f7218e10c78a4d7fbafc2d3d6fb10f5d1a8f9806551df1470752356531e366fa47444846f25f6a51c400e0b025cea081ac0e60ec9efaacaf6ed7bce53924931eef7eef5a326cadf0b8b11b304fbcc79f8da8dfe51c3ca95990062d9608c9d082aa9cbb6723f0f795b354ed37eb515875f8e89b8fd6c68b214e8b866947aceab79cbcb79e44bd46afa10b47a5542263fcbc2f76670475bafbb2b904df2352ffda001c5455c79d6ab4fc7d0fdee9dc187f07a06c50dcaed6b881f35fcc9ef4fa55ffc0bd3e8abbd9b1ebadb84a33d2615debad7e376513f3771e3035b836525032973e3460ced64b42775f0b227a9c8c94af423e6046863bcfea28056be47a0051343517e79383db0cb7b59372368002af6ebf0716ba5f46270f4da955518ec40c92208a152d961b12f56a7afcb81010bf22fff3bd252a51e2cc0ca03a5d5ab0a066d58358fa9b7370d28b4feb95882d9168aa383d0b4268b7fb33220bf1b34e273ac6d9cded7f4fcbae743b0b61a5aaf8103c97f6caca8e6a111a33e92f83cc4eef47f1f93122e0e69bcefe382f98d296082659fd9840ccda3a009df2928f9379e0a6d9faaf6b12151afe6542fd0c84043e8e6119f6fe85f264e6a0663e23a98af8d9d91618f4530f112719bd48dab00ba05fe96e899506f214a3025f9e7c5c91204fc5624216ac03e1e59e613e91434c4258c777bca28f836b457ed3110f09a24951dff70e2e654b232f25f89d2dabfe82b7b1a9f5b855202868b60585742daa4923c12a1aec177f9d5e9503f0e3a9cfabd38c12fa6bb7888892d7dcce2551873ef02fda301c8233340f2af2f4f18547ecf84016cade28842c060a659762867e8a3ab6633416ef03250021fb5fcb9917ae6622108ae2daf6723980f7085f45ca612d0993aee17cbd86e87d980bc746555b5aae1c94801b2e370ed4b18669f225d5f3e3bbae260e15ce1d4d000b431691f67168e68c8495c7a8495727e58493134025337a76b3a5c43ba2a9d42040687b7c89e69d660134afa51ddd4b5aa10b193ff33a7784badd89b6e8c3461c4e45ace4b742576767a7b01872f1d2f4cd1ed81ac921405637dcb69df9d716f8805a68524f66178987ef1d22c737fb6fcb7f69c9f62efa5da3fa4a57c6f31140211a162dfa15c2c9c9bfb66b7d2e4d1ed83ba2ffc77054f4e8f666b002cb3b6b0f392833790a04ebcb5b93e23ca16e10c4a7196e2fd2ee6234288e09f75fdc391a42cd08ae359927c6e59390f037b62d699f6c97160c97f591cfe0aa0c9b3b456a2f255cccb6a2f194ad4b48d402f9282c9ab70a413d70dc68f4579c49d8423330236f4ee0a1c4cab393179abf3fc41402a77dffbd86d3b367c9299894967b1536e8f0173be72b3daa9f3eb7b5fc6d48cad2a51038a52e45ae94cd51dde3c902b896b622727e1208ce5af0e9b8573e5da400ddfc13ce377622a02fdb3010867c1fc45591d3de4f3ff068cd23aa1cadbcc60989b6825f3172464b8fd1a1edb4d8206e7b29cf20c558b35812151a44368f186843cd98536eb3391e32c71683b0e4db1e546a9eb3c0f2923ab74ceee6651ca04f4c92096f885dca0faec18d703da056a88020b60ec41229faa6d3937447abaac80445104b53eec7f6defe7f592f8da374cc0184f374a9124d66c44d472344e9ecad7fa880973ed6b56fbf69dc851ca8723b08b77ed46eb6a1a594a1e52090f481cbdecbfa83af24c4c7f0ca321f4ff3bcf501c8d6d546e98bd7d403a8642dd8f771ca5f9fe077f3b2f0f170edd16159f0563cd992add3f525d454baa3217fa890a760fdf1bbca528236a0f6573ac5871078d7b31497934f86575f2898ef89fa9b6736a3206d39fd08f3719f7b2db2f6f1c494f859051064a3dfd60d6fb2ca5eb78e78d6b1f4320de131c5085f76e568b8ed31cf4284f894c61d3e132f2f41d4b4ca7973a0d0b4bbbbca63de88f54a2a491639cd0578ec20d58872c6d41412c1e5170dfb6f8cb1bf8834521d7e3fdf2ec91698026e55402646e8bddeb0661529787822ed988da572088e23569892d2eee4344d0ef0b0866adcd7ca925edcf09fdc2013bc4ded3f67e787daa64adc519597e194e7ffb72f49f82a2e26c1004abeb55f1cfa97155136f1d7456ed28bc1ebfbe69a11a1b6db5ca902b8f119a87287a7c0dae8ef408418f5ae205c40c4287a09ef1cc75f1dfba156c55ce2feeb6435dcb681c3e82c7033602905d2389d962a467e71546414a05b6b0bfb092d5d9b1c07371a8ac386d4f69d9ba589c1e406018ef5b8391f39c97c3d19ca0de767322fb783ad16c6e1d054fd7ed297c518eaa8a994d937457c5930c40ddd3d5efbf46393fd022da2e21d043f5c168270ce31adcc737db97da32ef103033f2e6dddc8baab30b47f59f18479922ca132605f808029113ee161fe07233cc33e4eb81af221c3afd2585ff08f40b58395cd5946c516035824076debd016ebb68344108cb282303d26dec5f9792c0b991c7a28c6caa971fc1433171b473d9c74322be502332206709b481dde8049a834ef255858a1a90f5512475d8abf3ad0b94146b85d1cfe10e2e90bdd38d035d09a4dfc313b4e8297a66bb116c6ae1c99118306c7a672dbcbc6a060241df912fcae2fcf7f2aeff5ee4e04ab6afd3ef9994d5e97435587cc4f8ecb5e7115a26710e9ceeefec4e87de6f75bbdb9a0a64e582de9299fc04759d70e49e420237f23440e6dcbdeaa70bf6e453b41baf386d62328c9926aae352f415868def8c1f9d25534faa94596ed1644b82ce9092836bfde1281148ca1e36ba8879a414f28d8a0a9907c11d9e01de3390c3b86f97d5b04355fa5e71000473532c17a1e71402e9e17b4e54552115d67203cea6c09aeef06d0d975694e3247b347100cc3c6ed44e79517330cde78b96f6e7c6a44877a96ef46e60164fea3d21f862bec96b5b78505f891bd3e49ef4a5616663ad21ae5f18e55dfcb3903cdccf2033945e67e8c5cb3c20a3b80c8e3860321a6daf65d9ef5ca7671cb585094e2ad30840d6a41f05f285d482ddb334332f4739493643421038fc649b2f6072a8d2a40cb4d4645a2e805b4d2f744ad280c4539ea5c289bf6a5d1a1c8fabda5050cf27595c5ea1db7b2f3045aaa2a356dcded4be22fa05c9a4cd4ab722a2f78baf8b4882322371a16141d9ed8f9473fa74b35a10a168e27f847fc0b30b2e3cc27997bb849aa5e5b34e03477bd30cbc6bae727933e3cb7ddee12e8d9aae7f264c74617a571dfd62018c0211dacdb985870105f1318e4a2a126b5c731ef4cc6ee8818922341d341110789689029deca3d3500d43993f85716dc05bf20bbfc6a73a1f340b96ecf4c7060527a9419b6b7c9df411c2e3622326943998f9f266d1e5245c3553e19ebd72c3eb1b6f59716aa77e68313b08bb1592c474a03c965297a572a6b82cb4806fabc3d1683a7f3116dcbacfbdbaf7342f3e607bc96d3b781c4ab593c8b58e7c4c2b45b91cdb8566b6821191745bc6ba8a2fac339b127a1586ce8776903aed2af57ee65c70dbc6b8734fcfbd7b0a622e662b98714670bde5b3368503db2b4ac5ed62e4a220e5b664b6edc44af2f5aeeff01c6cf0bc98433cacdcc1607cf9aab14425365e6445a18ca9365d0a5598928ec92adcde6c7877b80532b74a5fe02cd924c419f52f528cfc4f3fe109b675e95d07e48aca35af09d8e02a247866cfbcb50f0f85ad5c264e0bef9fc8f97dfc7db26ee7f395378a92e89693937d4281e81466f9652078a0421af5112145aab5f3302a988028a9b559abdb026b79191d14d8d56461ebc1d56f0fefc2f82923b362bb0cc7b5a4f3c7a4b639f298c00378b2e055c4f61826c511e486b1c806408f1dd6a11dd69757db9274d81694ca16f3e8834dfb75f3f206e9127d57d42782f23989f53968038a74737a19e606a1e504a852842a1c9fa8000e606743563e246ff039d335877fe0a7a5ea247cd5a579f375410680e642a7bcea7a88d9",
"spend_index": [
0,
1,
2545058932,
4294967295
],
"result": [
"b21decd167c0c15adf50de7115d216dc4aff160c64cd0908786a1014d90b5aac",
"3ba1e67c39d2a00e6cdd4cbe9520944d598dc4f2d2a2d4997eb18e26b910c14d",
"59096f4f95ea549c91c386ddae56658b2c66c3620fc7a810c8d422c2c38e5138",
"3e0b6fac06cfedd27ffa02acb67384b1a6fc0a0dfc765554d6e6037e1b2fcede"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 5,
"Witness": true,
"Version": 630616049,
"scriptSigs": false
},
"hex_tx": "f16f9625000106c4e8960b000000000000000000000000000000000000000000000000000000002b1a1e3d006f32e6b95f1f0fe100000000000000000000000000000000000000000000000000000000023fff7800c8a1eafd82c254a1000000000000000000000000000000000000000000000000000000008758515700bc8a789dc702497600000000000000000000000000000000000000000000000000000000e91c043100c7cbfaa15e276a7b000000000000000000000000000000000000000000000000000000004f115c500087853aabf66003ea000000000000000000000000000000000000000000000000000000004d81ccdd00b03e130405516ed0ef927f181fc84da3c0ec6b2dfd78386c3c30c7f681b1c545aeb71c650485bec2fa9426deda5dcae40f0fc556d8549d354a9df2f94ac0ae5f88a9e49367e76d94c75400ee35de99d9d004b93def51477c61074a123d8da4b8a712371a648761e3f45f04e7cf3dfa8edb9c03bc269c96df0fd9bf8cffadf6e7c0ea74022ef7664cbf0bea7e23255b011c1e38cfd0cf88e237dc48ba755cbed112ff4990aec47d8a96a1e054e3c37dcd7886101a3781c1ff1d69cfc2a0526a82b48f2737c26f16de3fe8b6fdd743bfcc57ec093264f478f1b60574c9371cc85ad8a791e77859cd92e1f29a9205ed1029a01b42eeae74b04e34a699ef29f7ab1302bcfe56767d93c5cd21c82dfc541ce25b32e52d8cbd024a9604f7184ed7690e9fccfbdb9c08c5ca6997e98785dd4c377c8090914d9fd9e4c6ca776712784a1e735766617d8c14cd9f47b6db4be3c8df87af33f2e7d22d687f19b4b1ea7a1fb2924ac07a193c6cd46f7d6317c8565e93e0896984f7826e37bd8c4d2b413b0e8d80fc376bd03a9d42a37dcac66d0d0149415486334d776e9a868ee0e79525e58a7d41be5300dda7efdd2ae7ee2e2449c8775d4de34eb01417273f1fc8abe8d57d8b8b4bb063539179e25e47de6ce5529c25e4daa85f726e2b70c3e031cea4dea81489335bef20573a516bf2ecd7d7a2e2dc9fd7f9e0db328a11576a625135b34314dae5e5910c447c423c6016629fac87e93389b6cc6d8f6bce7cc8ccf32e9f4d69c21761fe806db3a096fb2e1813c514d48b8696966d7c5d802fa319d1de252f37115d972e747a90ae8c38a3b0fafda5e543c600b9a6ee436e1b5feec05704e14c5b452d5996c20d4f1ead545d998d4874b4471b4613818c85657c335d3ebd05c8a5427408c7e10d9b8fb4bbc5c135aaf09ac75246d5ae69bfec927a6431957c5c25b4e6db4b958a7478e556bc4f603bca4d6fa66fdd28536df2cca8377cc554863ee273ad43f6d183bff1ca6f43bb17c62334149b7cc4db172cb9f15a19c10072d1e066f2949bf531961e7a16be98cc922be405b8e45fed5c2daf674ef9a51bfddd784bc092803286ef89d52ea27a6f4b2b1fb590026116d39c976deff446215876c110beee0d844924b417e143390422316026e26036ab67ba0dd5f6def8281af6146f0aab7e0ec62ae5daa701676d67c82c5d686a1cd6f3210d77dae6f42a3ee658ad95c35612748997b60c3b70cf6a4249406e5bef77344455969c45068d1364d215b11dfcb362108ffb19159f46212d5a2fd372633879a39bd16b9ddfbea2c2b12df4b792cecdfffdc6aefbc76f3406645ba75ccec13c8ef382d94a9db9002c1b1b4fd99956de17313ff5268792639d4cf40a122ff5964f5f1aa1f751f0e206e7c36aede988bfc2f94b0dfe180ca1ba462ff5458e12bcf97de50bbf10864f171dd3f1486f3a45fa469af373f409370f946a344249bbeab30409a06bf47f6a2a517314fdbd017aa9806a84afe9df7eced734f5fb11466aeb9f90b56f7282c6cbd538d1ce599140d622452e562053e76786ca50c2ce10adb2caf9fcc424888671d5839eb770e6640255491fcf8e605fcfcb3499354e607c89896b25b4703f99864f2402171ebf2326df584dbeb660eb8b21aceb0fc0c2b40694b0e77566c871095e038d67771be1e6dd45ed89521a41b4581fa836d54d13311372e186f1f44460782fb4f48cc1f413c75ccd6385e8bb698f0bb96ed0d5d11af73ebf6e62921bc42ffe8ad01390ae1c73c4ec7d2e613ea6ae0c275f03d0e98e60adf87bb3c2b76e174f8dd4a3d3bed6c31eb3db2434dde9308c79a1721ce8b386c1315526e33335fbb81582e715e23436173337daabb4d8b39dc0169743142a86272bdba71b310fce565a1063a87556561eeffe05c62d286d3f29c2769ea6517d75cdffeedbeb3d35b18a1785397eb36b04c050827745788ca8e67c4ca259b056d6d18273899d1cb7de2df7234b1b2562e700ece96619d9d4e348c0c2d96e4b0d4f93d9bf35ba394ca622aa83128b0dc0bea4f582e2faf4dc7f6d61aca21f99545386c345918ece8ebaef15f2e995f85b75453def81764fada70d29c4361362ce44e839e38bc619e8fc4ffd5a011389a5de99e441b2fe53b2f2e987c82b99ed01f93d17b9e2c93075710b7eba3339e09486732b6d5e3ac58c4cad4312b4f3c3e48b2d9320603c275eefa8c3023a3934192a813e60925df980525162b493c3787322ad5677ec3847d8ea574599b2a8a328a6869cebd9b66f54a478d31e8e7ae51d3e49ebc0148a5828cf30b234027176f04f105d1d78a0d0618079709808e73b86bd03417bc3525b4951c83e6c535d1b10730ade1935b97ee0ba5006fdd38ffb35151d93221d86ee2dff16c4353b057d5c5ef250b0e6414f1447ce6895c397d933276bfbef4be7ff7f65c3bda5736df98fa7fc34b48e174305970d11cc8ba0866e09e7e8f7d6f1f4c1598f6fc7e1b39c948d99c8b11e5b3228bb65efc9c1b5be37a485864022b7e987398164114475a920b663da3338b5acd34bece3d8d3037809fe55d9ddbb3582a4d01a56249a6049ee854f2bb8452b2294f9709197ff95b158a270b4e2bff7c7debd3a9e40ca669b65416cc6f1bed4c08ddd0b7184615a0cc9a957ba62be95ca7485f594af50efc6a8d2d34cc542558a6d791f14b0f044a7037e948b16ebc392e6425fae93cacbac326bb7ce94880a2d1619148938388f9c47ed37ba12e92cce581049138a9a59dfffbeb7721c84ff404f4c72b6388ebd19bd1fb012e5e0b07b3af2073fe15b477dce1176f13cf35e418bfd7d49c55f6d4ffb937dfc1af832aab6cc36195e7609262c1906a408db52b9bbec2a20874a88f472446c6c9817c039f254b59e501787b46e76a8f1d7b6f22023a864b511c00d7d4ac18c1c41c6c80002fd9a01a804d8ef9ae0b1e5a6af28461709bb34eab4b9999b4a26f50809b900df6e4fd40ecb7544b3c7c7d36fae686a0273bcebc4cc554ae6a411f7f3b4fe7b80e231a39caad54811095f0e80eb6b7e9e6e4af4b706180f0114326635993b39a2e203366d1faaf274496fa53356f358cd3c10cfda67e2abbe15f987285d5fc16d5410f47190fada98c4835b846f30bed526d65e538a66c6d271e5785b683fee5999f09c765cc27c54e7f20ce491919d369f17f4d74be36543ea33d7d03a0bef4e83939334af24968e6df332facdc7cc18b826be57eeda8cd4a8af4c1615ad15f16933ba0f6fba9bbe3d708f250c99c050d7da0973e09c7c7ed9bafab29f0896fb8238d05be5020ca9f7752957fc2c2bebfaddcb50e206baa36bd1ec0d7e1ea86f366b1bbf4d37952863bf58b2be9db7fd75b6192bc08030189877869f181f53da3e8e5a77825cd3127ee3a15ebe0b9921ff2d446ff3ab0987dd3feeded5b28ba6a75324c847c6ebf4c2151381fb7d0a26973b836090c8ef09f7b8b4a629bd69ae469faf3e7dc3ee08adf202d9255f6fd3c9aaa3e3ece03ec10f3accd737f2a5f24483eb722432c411ac33b0c1f001b6e20424f4dab0931ec4700cbf5d55bdd44f9b169b0b4a07a8d8003aa65d3b6ea489dc014f6c0f9747178917c2820d91407ba38e1026624103924ec6177e3236c72d3a46c62d34d0c19b11d85ed4aaf56c7fca4fc2ea0c04c3cc490b492bdcbed3e7adb16a61cc419d9adb3fe02d10f4c0734af90fd39b72d717c8ef6d2e915278a8b0d82c727ed1198b53a0981f4dcf370ec8a0cb9a0e81c8c46bfe1843a8de737410aa44781ffa838eba7a51f5e935f7f18334a30032a105b7c92f19a070912366321602b639ac402e9292701f65045ae24d246864b5b84594668c5f450d19eea704fd8301168f8b6a219e8b7975688dea4b79dedcc8f6d3b5f5eaab93c545aa1dfe102ebb5dbdd802940513c720ac0976743b3f6a55887e2c8f5073abaa81e30e8ab212cc2b988d0851a57f1ba08a204fd1549de594ed0f0e7475dfb6ec57d88229e6f3e4c24e8d87f944c8b9edd6f305c3ceabe569c05ab6d3c95126f95a2297f7494689135e11689c3cb3ef46ad912b681aa8e1bef2c9ae6f2b4a753bbb65bb2d9ed71bbf110675007989eafcf84ea77c3a182c09cea35f8b10ecf9b1c6ecd21d1ef13fc2464bbf933e104bc0390a869bba7425fbd62df1bbe72433553ee6f5bcea01cf168483a7879c523c12cfc0ff3e60eafafb18599155f80856087547af10c44135f867383312f84918bbb23e8bf212420e2f771159e4d7735005082843c1d3be1404d4260583179941821a85d002e955e0bdc669642c5a423db77888016249fbe218d55b8312ff9fc6582b90f204ed6d18e05daa47d74bd59e215a89857790c8fa5ce51af6852f8fdc5efcd5556c99bafbd6b3494f40a100ad373d1d27709aece45a9ed089396422a331fe3e1cdafed115d662616bf5ba7f6f16409a4575785f8cb2d7332d7c3a43d08a4fa1ca686f06ec1ab8528b822b9381abba09148858d6856a3f7d163bd2ade4b7bd7ce144a81e1bbeb694c9906d500bda5d3bf97afadfd90e4262d799f14512cc75f06375d5f5eb8cfab332accc4af481453078270850b4ec9edb4641e9415742a53b8ee4fd06019d5a793b440ba4d6075288d82b842ae6c231c73ee48f8fc1cb829f6afa764b64594fd6a790e1daaec2875c48775382022b7b4e26f67d73ac3d0e35f44d66c83c5f68537ebff9e1f72c847b2584e347faaead6a66644f49aeb4b1fc7cadc77d64c47353b01e078b0602ecc8f59bd66ad2a5a94cf43b38056be6d8ab9c2619f55c87bd06c9c57121bd499ce147878082868bdc47e2e9e692328bfde5ce32b46b7ed4ce8541c88a39a56e7e0af8577348d15e46fc8d74ae4b6c918dc51a0863dd8438efc702725c764e1fbc1cf23cc70b02033dea863637cf6ae9c0ca36c0a77efffdcf1224eef3148a2a3ea5d36d0e318c7a5dc6fff4932f4a5ad146b207a2e217d5cb99fc898815cc2d8ee6c94e838a9b235bc7f6817abdf13bacd83d032c86f3b8ef0531cc3bd92bd65de0c22e4419f85264266051e2811caf4e41ad88f4788e23dd5dbbe2515b9be400fd71010ed5a0dbfa116f50e82374ba2b84c250ec4a79384963218b66da1f33af1378e24bc1db878dc6e10c5c70d7bb307cff4972ead4a61d2613bf7ec6b5289401f9d8b8cc770b90ad895c454dfa4876cd1d7e506fc68551c04697aa3fb29ab065e3206fbf9a80afdcde05add51e1ff5ea00c1c78eac1da84e3d7eeda5e384f10b883d066e7a7767b25db26142d3d8d0438b71475a082c9cf7d8d01d4b71308b4455dbc76705b2eea3fbaeb800f3639e2f69ffe7dad08cbc008a737a0be98c0ce0e6d6a42ebd2fe5f42d2348cc464e0d56db295c813ae3a6ba8bc5589444d25cbb91f2fcb2c50d2e03e6941e61e88f1c6dffc34fe3298072df780384243cc27c95a2aa7de72d321d4b764750219936557abd87b7b2a39d5d33763b9f6567f9ed24eb951beac74cf105d6b61ac94d70bb2c807a3b75fe1ff50d5a381ab676a296012fd5cdc2258a68a49a8ae2b515c4f93191ff3bf0355037ab75b14798ec54125b52654942dab831fa76d82a47ce50e251b82a6a4ca17925ab310fe492107607cb0c765819bad43e09240026ff932c385149b21d1c1559dffedd512c2a0b19ec6a2a1b37412135975ac0428020723950088ac508071e4af80eb96bff1d34a9272803fd360169e10d734e8a70ab7ac002d81118dd34fa4ce154d3e80fe6fd5c1609fed97a6660ab41edc364d02435152986a9935d293f58995a67bf17ec6a7ceeaa804c3e626ff779cbf384f41af72a4f64e8eb451ad6f77f1ba89df42708f57db978a78df819baa62decad76c3b4d90abfec7ab4c9c5c21c6db7825b971d9f4c2edfd4741f7c709b04a63a694d3881a2fc721fc1753a3de2de0e616afeb6426a66654246f70494317cfbb590c0f6409545ff2299d2ec635e552820701bdcbcfa97116bae779c1c5ba922d4614d6f1c57382c6f403e1c9ab1d226f8c112892c27ddd40912adbaac96ee6920d8bca349edd94c565b7eef7770e6354e63e6bf676881b24b5b50729a0c3f44cf9ff1779686c0f9fe2c89f746f0dd3d4d63770bbac847d680eddf2d81cd9f5d758b4469d73e0db38e6bb5ce6b7fec6868ab9d5a3d2235b8058b11e8371878e1fa8e6764b163371f2cd549c475896bb4b9ecb2d70b525fdd968b9d98e56d087d9fe9f584b056f098a65c0ace43f30ab9aba828a912432dc5a60df9c2c8ef5c4edde71d6b73844130434965d239d0328085e3da928f0eb35fcfaaa37037189b09c8ff9375367c5db5c6f130a4f594798671c53bf5a8e975d31d6f2ed8443f357402caffdb157f9050fd3ac530a84f086ff630e4039f9e1003c9530a015b29cfd88499d2f29cf682633c73aacb1b3da3604990ef08d986f7911b92f23423eb5b762c2697f559a5a8b0f12d51",
"spend_index": [
0,
1,
610513232,
4294967295
],
"result": [
"b8c2674bc1d4548662609e349a1ecf62051c325eee442aa92e00cfc07427c5c8",
"a860261a7f38b0ab5fd7bd9b9ea5a970dc25b9bdf7706c3dff60802bdb0d69c0",
"0447956b7c977512ed421e483dde6d916cb3e6932cc0c46adb9276d73517c84b",
"648f6285ea779c7305f3de17c8bb329fb89716855eed576d1420654b262b2d9e"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 4,
"Witness": false,
"Version": 1680436768,
"scriptSigs": true
},
"hex_tx": "206e296407d438dbfb000000000000000000000000000000000000000000000000000000008d78eed6fde501f48b577503b35b028206809323b7198b8d731b93b79a5aa133c23bed43460b9f95b3ce5b8a990d3bfaba0b89cb471379f065cbedd9f3bd3008b96139003e82aa700236cb95591e86551c895eb35fc6fec035006c059487ae12401dc194515a83255ea54ea0083477e7f569aeff555858287d30295d361cb03c5c2d37f68909b571b5b2ecb29ea966ffb85a69432992eeab288120b6b0139497c1d6341911fc3df5f0e914a86c8375f78670ae69106e6f144ff35eef7cd840d6d03224af060c5909427c1549fa6b1270db86fe79a4d13cadd7c77ca30512bb18f63d9567f05b7e03055dd716732669b808ca2abe4d0ac6e583ba23e8f9508d629f71652b5be7e8d717dbb8f0b4cd91c97538e187a6f920a252eda4c1f5b96c44c189ba9fbec3c7016b1414bce1af8f05002eaf384c4b046f52b4f38461760261e1d747437583d804c9eac273f375444e955383c0fb914e1e85eb09f883da326f865abfca714b6013e8790f2c9a9732781b2d3ddf9b1a9ccabaa31b02b0644489800b6472b7df991a2d07d18b9fd09f7844274137ea612e9d41ab5cfe8b639c344daed18db26a04f2692c5ee90098e1acfef7f4e73b8cd3bbd4c88c252f02858f43844d4dc564817a35a9523defd41ca995d198ea29e8aad498b8aec3a257d88c76694a92ff7bf1845b260387a2620c4092df1ed20000000000000000000000000000000000000000000000000000000008cae535230e35061fae2856f238646642efbe966618520f45ed8b9c1b286ae4b7e1329ac914260a7f151eb0d0521d1400000000000000000000000000000000000000000000000000000000b749d8fafd5901c299355f926b1694a1ab345d44fed8da1a5eb67df88cc11cf9acbc3ee7e821dafb2b21a4763b1c8910bca006f499db09ebd90221d036e6d09643a06247a88e6ddedff4c6d42af78152f4c3bb35e4b5eb6f11b9b26a1abccbe926c0107bbf0067cc7c82e2de639fc2c927171798a5ef1276f316c800f8e3a2ddd7b2a1d10b388b45ba6b56d0700d51ec680f796572922d3a303ec9b7d12b3abdf2f3f7d500c6d1f120b6e073d5c2c69fdc78352259a25efae6f5a13bed818507c50120f4892c5e6d5dc2e11ac6e52581079a66fd62f83e91c82c8655d27323e6a945b576322a173f9e2d1acdb2b032c378f24cb0d1fc20bb44ad5ea1aa7712a50cca3147578df58185e002564708fdf3ca635d742f811fbd9780f4b2900657ff96e842173eff864576c23d9dfcedfee2d5826b8e4881ae39a81712b34ce0d18aa64ac075700ccf16a06a85183e1ca36036432978187fbcb83b58720b1696d197b0e8472cd238d8180000000000000000000000000000000000000000000000000000000097e6255dfd7401fa957a082e9495119fec440b03131638f0ee91c9f4a05d918a96dd588e818ee4a8c287fd2aba49fa4f658410813a42024e302708f185aafe87183b08fd36d40257db19fc4ffed1521e018a845c8f89f51e7972ca7e98ab8d401308f5b4aef15168eb9a4e72dd27c836aca7512a5ed1eaa7b01549914b128afbaf8c43d40e598657dc42b73de1134e1eeaf60590ba2ccad9e2bc8918783d262394e5da24157b648f0bc12d0b05312450f93ae2f5c13ebbdde8910b3718786d339718ffdabf96ee4294f6157679806ee824a0ea6135ed285fd7decd81ed64463ed2d5e962c4e4d35b4942a1fc796df8d127f6e81b646eaa2ccf34b7c9a9e7db4938338b40ac0fb9b318ac0fe3aeac28a95e1fdfae2bf901ad71dd78050260939a30dc4d4c1c70d589027ecdb83163c75daeddc3578d72e94c8e40ec158072d2786c21c8f060cc876316e1abc51d9d1bdfb0f50b70350b63a3549f919f08b6ae614dc7915dffc029e602dec03b56fc74cc79316752e1201af171840cad2e8a3d62f16647000000000000000000000000000000000000000000000000000000005fef348cfbf8ddfd14a1d50fc4712872f54ff256923f6a60b0b8b3e3ebf922e0a782162ad430f0238b1ac74bd0df25355fbbc7f4444f4d63f8b3d9c1e4bd0ebb4ab8647a73a3a399144619c6c5b94d311fb2fe8a2c08a0b67ddc713bcead78d0836ee8dff4d45065e8bb2f10728049b37d16317d3e680ffc3868cc1115e3487cc3c5cc399283782eba958e49fcc6f46290b71ddd5a78f3afef988e81bf9df069e648506b374a0363976167c8c32a2c7afc96e5cfd4dc00280eba34ca793880bcaa32591c458999a7942035907a8b6fa75d8712634fd86e2951baa5a1711ddf66304d40dc264422989d7f900254507f5a77d50d0f3a472a62e5608d835c510ba1e0614208be966b270000000000000000000000000000000000000000000000000000000051d91a6300b52ac7197f6aaa6f00000000000000000000000000000000000000000000000000000000ab3dbfe0010ca1f898b70432ed23ce66f7d23ec864831ba1a846f6da004e9e0ce5a1ba0f63506e3d163c543382300eb4f61c3a670bfd3cb3062e48be9c4742edd8edceb88c5b6b5f69160b199b3b21b655adbff63881325f4198480ea355edf71c7cb7f728d99ff1f0c580682d21f9516087c87f667c88de87c5004d8237140c1a0fcb1c37c4f273c2f2a7a09c5539c78db621296ef6b1eb31f00e4f3f150b65fd14fe8ebdbc552dc07edf24350ca1f4d68fa286625f45036b9b9a8ff42ab65b99f4ce76df1e2837409b8dc2767bc652d656ba3d191aa00e64be907cfa43962d93036446c817419f6bcfaeff696d58ca608989e1a3bc7ca5852277179093ac0b779ca9783d16c8e43a8c5b7a6a2d6545fafd28eeb98c0161ae94e0ca8f9cfcc97b1fca8debd3f50d89a237b79ccad84a7dbfe2aee692714d786208ede0be7db771839125aaf02b92db0167635d9ae671183e04d7b65ad00b4d8a04be904adad6092a7c40902b3cfc8acf018c43eb004e06a5812880b2f9bd5ffbb026820442f8cae0ae3a37daffbd9f46e28354324341cd7711debf5fc6559f79cf08f4e3b17dd6f24a1b201f1a6b7cccb73973d43e49ddec2f805cc82322800378dc0ac4c1bb3370c3c5dead353392b6a28fce714be2f199428940ff5c36dca16c83df719a321c224bfcee8dd44d350a1dde8f28d5bde147682a1c2007700fbb74bb5468345de4be0038928e46095b77d661d3f043280fe4ec12bde28ec80cddff8390254dfeda56b469b115d69c3d436a4157bd74d156bbaa1260c7617b84ef7ca3452f4c42fb0f97b7f08360a045392c5fb25c655c9846002ec5361249d67f977c152e32958e0cdaafce59b8fb2db49d969b1f579e9b27294e39af7d42d790eb8ea8a3820e297de620e77dc85679cfcc8cb9a19e1bf9ffbaee0219986aaab28782a5d454ef9d2fab7f20515f4e256fa0bd5e6aa691adb1260454999818a428d99446929df799af5f1537d222a5726d285d4fa7418dab2fd667419acce176fe0ae2be3c11c403dd669091175b2399fc56b77369a5a96f4b6a45f8c2ba5abdf7c03b3410d1a4a7107798fc0aad0558adaf464991f32c3f97328f0ab9d30bb7e1ced023312ec79b08ae0d0fdca0ea7ad81ebd9384fb6ebdb8e14ae73fb289c574c1d0d8646d68925bbbb264468bcbda53d10b06effcd364e097",
"spend_index": [
0,
1,
1976281,
4294967295
],
"result": [
"0257d88b3cbede09ba92c5700e93c7296b52eae72f3adf01d06d80bf88fcbc94",
"03ac0c3bcd9354831c7615686290c172d87bd2789d23dca1a7b9e22d056f7629",
"085b051e1d33e462e14a21602dd67374660bc3423c83eb2bef7f8abb59531d23",
"4371e62d4ad87e48e7c24c3c51a98c88c430df56b1cdcaf04b31049e59a34b0b"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 9,
"Witness": false,
"Version": 950103983,
"scriptSigs": false
},
"hex_tx": "af6fa138040b6b6292000000000000000000000000000000000000000000000000000000001b87bfd700ab3ac83175fa99a200000000000000000000000000000000000000000000000000000000b565e13c007fc58c1275c65456000000000000000000000000000000000000000000000000000000004057a3dd0041bdfc854306659a000000000000000000000000000000000000000000000000000000003cbdb3ec00d93c4e9f09e3682dad388aff31c8f36c73a460087cf5cdbc12e40ae50a4e82caa1fb397413688766ec4c8f55c19626f25570d38773dbe49dc155f5c322f7255805d3b5897462d88f6e9699d7d84217c695bc3aae2240c83eef904d5aac62b34277700df977dfc0e7e1ea82f89856dd062e1b2f557f2e1d7e1b8de18db4734173a0a48ff259a2580f6ff0d33ab6adde19663d052625b6df5b502ccf630fdb6fbb14331b1d129546478302462681dca5b90def6af819f797f2bd49ce6203f6d9f9b790cbf99d9084d6182e053ce81c38d186b33a889d2da3664638eea3b73ac8d42372d1821fe24ec2f3c687644391304f146325c17f459742387e4bf571a27523dcbb12d07b2c8021755618625e8b88c4e482993686a1e0d1b2287adf16739481fbf7b623a497fc4dede419466fd6810a1d31737cb186abb3b4fc163df1a7d12e59358d1be3eff1d19af367581775fe854c653f00dfbb9f6c23606807ea2cacfaffef8a1805cd3f77a96e784e89db1df038ed5858b34f1da70be1faa3ba6ea57341a683b19d2de28e9b893d11699b0051b909d361c45c9c159d84e2dc22c95b224eecaf814d89b00d728ba0ad881f7dc842a240fb9d24d48cc2bdfe954f821e54977787e8f9b5117b26ce554537582a4ad824b550a34c6e91ffd421446dbbb7ee3ea648c7a8803165b81198b1363f9199a3923380609fc18be02ae6e0924e70b844a917ee65f7300227d67e1505d401e614802e1c3cc238b1eb81d6c63bd358f9248ae0ace89f818792c861989584c2873e0a54a3f2049dacee4ab1ebf0f328943e64d43c37e33966c74f15cb87c38411b9f5ca9e0fb6df06d7d75f50373d0df1d45b8f452235a6932073d87db92ad4abf2c971decec7942e0771cf4dacb1422bc8c59d705a15c1b6608e0f042decbd74ea89c881c2acba7c82d419360cff319155ea28037a9e9560512d640dab6af8f795b4580cb8fdf0adfc5c86c9c0b517f06fa48c468316ffb388bea39404147681106dafa1f551cd4dc50dbb0bf0c8acd4f4360ee36f5f0e85e80e591271e5baf94ef4c73cdacca9775a0421caaa130d05023d9d234fc0ad52962ed462c9f462fad446c27af24df2e9a8eab5032ed8a7635d6c20638c47d602a0ebd123d9fc7bc89283bd7ef18fe9365cd6da2c653f42c451716627bb1ba7bc8a909e3b9b4854f13ec801d976ba8dcfd629691b588c7909248870772265bad8a4b448605d4a6aaf417a6f513d8e1390afcd111bfe298bee9fcddabd29844dd802cabd53de94f679d9edf598923bb36bf2e78b8f208a82d2191f4ae768d2ee3599f9629d5a8ba23c696e1b96a173828478f7ff09bdbdcfe6707ee0721ddb15b1da9d732702a6bff634940c7fddc5c2cfe2b982c57184c4d8edebc86b84e342d9cbeb2357d21701956fc0f6ccadf87c1e0d5806f7ef10156ecee393c89d322a7b9eca24a360e72ad335db72696f80a37f91a771e4458613c4b761c855ae8305ac7a6f0f79c886222fc148779c93ed55603ce3de2a5e7fd33226b96b3988ad35dc6f6a3d59840c2708ceddffee02f3b56dd112692d863ccca02b3e06c1ac331e6da90f1a1b186c708dac6611df431bf1db9c63e773535f643d571848229379ba0f5dcd592ba21fed529f6e28489fcb8cad98b75bf131b8a01569a3ce2a31415f9ae2e6b1b6a871b1fac28c8b1369ade9f230cdf6569b1e41f2b10ce3b31d0e5bbb16e6d2ac517534b7dbd5b61d0d9eb4c7393c19eab908ba7e8b36918f4b9b4db3cf90357c735cd57c1e3375c88554059582a77eb62985ae3a85ad8e51cd8f696a7750f2e983b0ad6610815ab81ac1f917884ca4e52a5f869ee0fdecf50f61dc154426f137443673f94864d2d63017aaa4fb6e349b260a2084d9609e5e765a27a9d11a49f4aad6205e497fde446129126ff6e6b56922dfe564876cb6da3f303907d76a28210a73bf6acbc41cd04ed13a157e0aa6774fd8e52d4c64578371f0c04ae3902a691b8cd208f4e9ef0864ff94a5f931a6c814fd409993162d6a5a371463e86edcbdf8fcb25ab537a93a3537988e85a756858bafa0e11b8b0453c80c34a0274c631336d24e8d3f57fe9539dc710312643957921377e906e1fa14c1591f98600a673602f3decf2869c5f96e96568574031ac58acc342f60b8bd61d1d5f2c1eef794e1561e6e0d180702f05d0aecc55c2524507b5cdfa1391a80904f72f65b814c206240e5c792ce066e8525f8ce59d23cf022563b661de18ac59fdf8e1539b2987142255bd67a7e1eb6d0a9cf6b84f16f9fe965d22d9d770ca7ebae7fdfb34a232124c972a13bf82de56a54e1f90245b6f4405ff4ae51a139aa26cdb4434909f691d92219413b440d0f4a03c8ee5a687612d54d13fd67d1e034d52b69784e3f4e2167d2954ff67d9bf1beb6f3bce0a08d5c8d93bc4970a8d9d297b0fcad08c1184384a09ada4d263a7a4bc7e9fe40126019bd7cd22ada58d96534e4fb5c27964e8d0fb564413652416d60db4bf8c1e0c97f45bc175a832625a87c5c5be81a06669f0b560de7ce76d6597ddca1f8b5aaf26c392ce1b966b661ffc19a8005d74c18fb8cee5caa86faec3c381823ca2236177b14e4bc1bdd44f8a032877a78555aa8f1e59e540e708229cb3dbb305007b5a413d7f4585fd2be77",
"spend_index": [
0,
1,
1718455096,
4294967295
],
"result": [
"e3ebc01ab7898e0d00c74138a301aa044ff63406ff2f367a156ad55ebfe6d7c4",
"4e0ebdc12eb7f1792a67c6ada5542b98a2fbe0b0e38c65f1ae70fff4b6e3bfac",
"4a2e99bdd2746172270885d65bcb4568970c901328a1ac3304833faa79298991",
"8c54de20a56dc2c75f8f660b8fb018078e13662a9301e1e8a9e1bc9a0f0e721f"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 2,
"Witness": false,
"Version": 1586157097,
"scriptSigs": true
},
"hex_tx": "29d68a5e02411bfbd90000000000000000000000000000000000000000000000000000000030be800f00b25eac490c0c0530000000000000000000000000000000000000000000000000000000001fa4d1c8b6cdee099d092f7d946b9d148e926825e4679e07b0d4140d03e9859bd32c1a114029fdd03acfc9e06f885e011c1cd05db51da8d749a7177e0cd1e63d8313bd283acdc936feb55b92fb85d810c9bc31f0cae6e05c829e8e21c9cfb9926b81365955a200ad67254dcd4e63a912ce299edea17632dc03cb74762498082be8511b663d7faf3f0082f888ec42b16d059b29e15d1b45452073cf670792399e87e7bb05ba46116d587adc6d28398642c551ee3509544455fed8533a77b6c40270a6aaf306437c7cc8431a2f8ae89088298f2c16e31d520b7ee58d598ad484cd0856bf7b0b402e5187d800089c19d9b32de970883542e538368825c5ce0f8094025740735050d5cf021f99236ed3a7493f3889abb2b2022d5e549ce675553af4226b71d326923c985f2a8ee829c0d76f7b72d5b46598234e940e78144d3f8283c93df60bc1b6512fd9d86c7bbd163cac7cbc548fbb748277ae932021f05d22f189a71e7f3a7f7b2cd7f5188ea388b33bc132b9334381a1bba098947cae20e9463592946df02e45498a327fd722fc5a5be5d02335bf26b3e64fc88462087b70df7806e6e95dc2a7fbd8f4734d82b39423c9b2e2e30cc1a5071b21268624e7e514c3e05de40dbfcde771ca7dfb51dee5d89bad14e56b057c9c252c02b8d131371d66ebd2de85b1e83a712b06f21b1159eeb3ab27a4ba3506d0d999456a5e5f2b5fa7b4f2384f2e66424da31c1cb882c0374fe1a14325babaefeb866a82da2866e0af202af0be768d6ff432a5765e2d38f58df4e5ca6d71dff7090180abd43eea4e0a4475a7a9ad2c7fc16aaadc8fd3837858ab5c33d855e264b83de5ab8995471dd27a5fe8b858",
"spend_index": [
0,
1,
488532427,
4294967295
],
"result": [
"511c1af7d5757ae5003bc2a03fd3730b87de910bd3f92d4263c57aff3e62141d",
"4699fcfb1fc34fbea6619c9f1c07619a0d4269953d8fbd638d58492ab55e4558",
"8c92f14c5b5cef4177a2b0a19ef4bb320e8f0c09c63cd1b8dd4b902065f5bf1f",
"50f7f44aa75644e6fbcad666a8b7010096fac5a325b764185356eb4536bf9b4e"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 3,
"Witness": false,
"Version": 1533286556,
"scriptSigs": false
},
"hex_tx": "9c18645b0a724c895600000000000000000000000000000000000000000000000000000000e3a813a4001825b82541fd254a0000000000000000000000000000000000000000000000000000000017d9bb5800f36b8312fd3445a90000000000000000000000000000000000000000000000000000000015bb76970047c67f8649de677e0000000000000000000000000000000000000000000000000000000095fd92ab0052e4e5a60612c9dd00000000000000000000000000000000000000000000000000000000c414d5f3000627a6afc3d86094000000000000000000000000000000000000000000000000000000002b12c172009ede9e0076466cad00000000000000000000000000000000000000000000000000000000596d0f0b00566218498dbbd45e000000000000000000000000000000000000000000000000000000007beb01e7003bf7319bc6abdfbf0000000000000000000000000000000000000000000000000000000003086f11008d331294fa7246ed0000000000000000000000000000000000000000000000000000000038ac0ae0002eb27611031bcc3774906c3e08c88b5d21712b17491cdfe047fa41792d82f2240ed56ca69bdc91cb9d2253ea6bb7fa58721106595a14afe68777034b97aef9da1b2ad61e89bf0dbc7e099772c98733df891f0c8ea54f0e18b048fb92fb09cee8c8db12fed33ce9ec4419c210ad55b3ffe3ae78c58674da35a1fe11ceeba8894d07916e8c954e75d503e682d75b727eb97397c4484ddd1b1ac1687d312bfd7b782a175d54bd72c03c7d9f4c96d5e92788531026afefda23033849786507e380573d748e051b7c20eb351ba18327bde4eaaed4581f45fbee6b296e6ff70841c82325cbd9993916e0fc9a13773bf56a6d474b4030255d81a98dff2add45a62d087b6a3fe3beb5f98404fe2a0fec6e02a0ff9fe2882a1f6d0a071010f874d453a681523e7c5af75f01fe41edab2752a933d2c9aa6d21f9e444a81fa20137ec17fe835e2ef154ea09b70690251b474c451a98e2e0479824f2fbad05798d254d61a9276869910844a343d7c2b6052e8c7bc83920b8fbbdbac71073e2e0331c74dc0711a98da61f89c09c9f2c032b0b651e4adffdccb815bee12be6ad65fa09b3d506c01484b2fdad8378806dd186b1a15c6bc8f2285bb100c9e8cb92954902abe937185c26095b8e83f07f0fbdad0241305d5f9d7fcb9139b78f2eec323aa6c3a6b985d13a0856d815701380628fe00dc33714646b0747b33e1798ecb9c2c86080c98614890853fc6f2bd5222eadfa8772dfed788ca957e263ad79543f3ff445928517ea74bf4d940dcd3f3ade13be1610e95c829ef0d321e10e74d4870b3ce9631a3df823c3c77f3da05e3459905521459e56f51b24e1d6ef84e8c7d577c33a9a0af562346e146d209bf30748646d0e93253233cac718a78e861ec7573b9a",
"spend_index": [
0,
1,
3984766173,
4294967295
],
"result": [
"dcd0a0e12591c98a2d6a8881c7a303d9a0107570f391206e6a691be2832bf4af",
"09a35802c10aabbcf77dae06741f299bc2f93ca5f25977c83ed6a7d192cbb1bf",
"9d47029c60a2d62dea9a544428c76c2751a966454d2098b6607356a17c43c52c",
"8fe316a21ed6c595b49766a57574a1bb2c00a0c80a8ae50e71878e48133ae35f"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 1,
"Witness": false,
"Version": -1046185967,
"scriptSigs": true
},
"hex_tx": "1178a4c105c301ece100000000000000000000000000000000000000000000000000000000d721b701d934658ba935670869b99e74e137856c6665b704bfbbc3862ea142f2d79c4122ecd05eb4396928ded3430de337873293fa17e094f4d8448a497e86ed07f4f6eebfe0b504b9f0d9bdf0f69ce456aa44e0c557d955f6620dd16b66775e59e8fd6b020f617ac6e68d3e97200c2802b98b302e27027330ad80e19121204a3d94714b122ccde996519afe725cc1e42df805c8e7574ad1f22ce770974957696f4bd5617e1b988d7c45296b8eae5aa2ec6154bce5fe68ef98935594bee11994f9ca98162dcaa7dfe9f83636eb3e4e949443051d46170e324d4ebb015db901a4e6fa2d94d6ff00000000000000000000000000000000000000000000000000000000944fd534689d714e39b73e63bcc0ed267209de8654f17acd985cea178682a69d6f3e0388f49ad04343de07100e4a55fab139497f484a0ef432b02ac4aa15ff9af6a79c11e6576097fe0b5a527fb7de2730180ca5ec0a685ba00400cd6055fe18c0fd3bfedef32a3fc2930b7d477c2c228e26c71067000000000000000000000000000000000000000000000000000000004fb2ca0acf406ea8146daca89cb2329113acabcb1b1353bb26f791f8e660cddbbdea6695ea5ad6c2ac5429b96a4295d230f458af28edbf7f802e4fc0347c529006ff619457bef327dcc8f14b1a703f8cfeee855243a555fc884e7b42f1914c3413bfd04e9851e75e69a013b7ae527cc09eb38e99a9969252fc5132c6192a50c6938141c4e1d13dce8f5993815ce71a60ea69c79486e6edc94c12a9319b39818285740c4c4c4bbdd0780854e61ed2156b0b9c3539bb73b5a94609875aaa141c0d2b45f3c80b04949051bfb9c3f4c672d55a4f440a38464b525778e5500000000000000000000000000000000000000000000000000000000061775380fda10154519ebb2b3f6c9329042bf5b66e15fb04a7378fcdff6dd433b877fa30d197c16a34f1e81436100e40ba642d3705bba492c26d941243536aa945ee6227fa884286cd16b884a810f1935edb0378eca6be19e1f307eb4c25ae28e483eb3c17eb6646e574c90c0a26144b028dd12b311f366f3e5ce59f203a958539af8895fe980ad89458ac205cf5ee2d6719abf1ffb5aeb699bd85146056b7e0e4db8af5fef6086a225c6e88070cbd40576cdc39c9871c7a0bbebbe3883786ce480f5dabb2148b719dba4c54ca00b81cf4b686f140e02cf0ae365b697596002c2b01513914c5bc42f428056c6739c682737884a34782051ae0ce2a85a8e78fa1cbd42027abb7ad79ba5a8aaac04688297addd57062231eae11afe12f43a76c5df5b6dd2b19cd755de1d1112985ad1a7a3a4ce6b13894f51e67f169318d982386b66f10ff9c76f81aadd2815fd8f0f1c33413c2b039260efbcd68257b08ac5a469e8c2731aa7b91c917d9933d24f55c4f568e74eef02108397515d71ee8c4c927e949ba54cf3b29708491a2f77f9e59b232193a22a5d87a86bd47e3f6ffcc47452a47bbbecfd307bee555d58e0a7dc7660000000000000000000000000000000000000000000000000000000074ef9b6e04357b907fc2deda330123eb094c8e8cf937c881fa5c430bcb5330255390144b8bb4870fb37411ea3fa4f154e0f91e09a1cfc9d7d1d6873204ac700fe3a9666995c60afa111d67e1dcd83a687544cf2c9e644d7b34bdf57366e9ab421bb06c43688f4d1c61fc3715ee013ca7ce0d1fcf92200efc00434ff1be2d1e649149c3fb0e1c2234615260775a6074157dea4d1e93b8b816882bdc6ac9ee8b37bd9eed50984814e8b8aa86f16e08868680e370941b1692b7cb049f70b0216d689dfd61da7584d1a0cbe87dbf482dd896bbf1911cb370f50e4786a61964503d465ae85e",
"spend_index": [
0,
1,
1911039603,
4294967295
],
"result": [
"ee6c9fa448ddd575489c1c6605fbb7074c8e4221b064d37ab411e9d40e9b3958",
"824e100dea2db58dbe671ed74407eec9457a11f9f1636def3eb7221133cbb77b",
"37ea4a8607541460dec37f853aef9bcd1907f35222beeb840fe5fc60c0ff153f",
"02b79621a4fc7bb9dd954bb7529425f3bfc3e30fb08a9e5919eaf0dbfbf51545"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 7,
"Witness": false,
"Version": -2076899950,
"scriptSigs": false
},
"hex_tx": "920535840a59faca3400000000000000000000000000000000000000000000000000000000a9e8d77200c50866e0c98126000000000000000000000000000000000000000000000000000000000008b19e6900da1887d7aa74b60b00000000000000000000000000000000000000000000000000000000d17f9d8e000d3461130ea4488b00000000000000000000000000000000000000000000000000000000692258aa0097388421766867910000000000000000000000000000000000000000000000000000000022e24c1400e158e46061fe236e000000000000000000000000000000000000000000000000000000000f35b41600425339c4ad6e6d2200000000000000000000000000000000000000000000000000000000e71b5205005eb69b91b3446cef00000000000000000000000000000000000000000000000000000000fa113b30001c1a31129bddb27d00000000000000000000000000000000000000000000000000000000af19a36e0084d7798bbbcff00d000000000000000000000000000000000000000000000000000000001bf81c940008ea6d2007a78de3263d376b5bc87810e8b9bdf0871b5316a7e3ef908fcf6da2f6a2b9f424f903067212284e13c7484f0393dc9bee801f78c18528ffd4717f5af3c481622baad5f08d6438da707cfd0ff5ce38f2900a97816c410d7f03a209670a248b882e20030b5da281c886fb5e2cf5977ad0aa348d7eed405783d49088be3267e13d0c8496b3da2f17b50a19b6acc5e4286caecd30e6b4b8da7177923b41e5a55372260fd7e1b7576cb2606f24333db27a063545f0272b7d5e1ed92040bfec70cb08a21dec01e2c978a4d56ba03255009476a1157ff8d4e465ba1300c8357e6ea7606fef3e35d16fbf5aa62e00d39f17ecfaa17ea3817d408350504dafe86a8438aad424438619ef56bdb49c9c75b16d2b9314c478579556581289453e501496b71a2ac5bcc11e897838bba0b43b782676a1f623be98ed73be1dd78e6c0310cd9b2ce30412880eed4c7ab384f49c809b508153e895a2a74d23f318dd406d402d1b1a9a895e8196ff5bd70407bf13ed8d0f26806391e25300dfaeca3e9f699873cd1798f07a73db45877dd40866eeb01bb61cc9b14aa35c9443a1c5040068d27591d48bd1bd19ed0e35220e312ec8d2e86f19d247cbe312604d1085744923d1dadddaa82518e29bb62b8a9675fe68380e65c456ab124eeaafccf1be563c928b44a29cded0976804a71528984a3094a61100bcc4bf8a06507a2cf699d751c48342c8b1ee71a629281d029e7947a59762dea77b82f52988c418890d2b46c4882d95e820d902d28430d6c75d712e3af9cfc3a4a38b750893687ec2704dd52974adbe611aae0d59eeb5453bdff8065a663ac66a08cece2637773cf8cec3e26ffeba500eab639b254cfbab32f0e1c224f88ac82d742e518f0e0fa9652e1ac2c278c88ef2ffea2c424e534ca1b6c2f1415e9c28435b3d32027eb4c7004db3fe710d99ccf7e1118e67a40ae1808e00126daca873e14e729312b1ac6f656cfa0428551aea725b4d73c6de450abfc540eb757d8faa56e7dfb2031cb25be2c43a50b73984ab718843621bffb4e46ac17dbcdb88fe92307dfb25b68943a79352bcf697c4b3834aab77a8bccfe5c82427d1bf527bd948a526217b8795494ac40eb7779e952686a98c7690822648f5e51ef5b930e0ff50e2c7b12386ae7cbce573ec0c0424cd7a415e5abdbefd943c750077a2e0dd4dc8db3cd669e67d95ced6ce4aeeec807dd04adc444d16cf798201c4978e9e5d31025e5879f64c7442d69599fbbe5c5ddca1ca6d1536e0e720659e94abc72e356b0aa3252fe09ad38139e3424bcdd515647877353adae83b439b29581c6e54c8fd012f3cc61909200781e2c4286fd38cdb551202e8d3a52730424d85cb006507f405162d1c66835ed25bee89122fe3acd80e765e3b0e2664dd769ff0ccfb3cc4e0adcfc9973c4b5950bbeff23d1bd174819a2a05aece181020baf02cf9b354956864596723c4c5637bb1f936c5b8d8de9344c8d733db7e9660e806a2f05ff14e92a8bcbe8d5f23c7749b4e96328f30258c0a6177a45a78da8521cab5bc8760856aa17726a323bd7ebbca1de6c920aa240a2b276c6062b1834b61890c2c1863e2a1adbe800d8760b692edd6762c4a6e23a8525094d0da05c34b9bf454e4903fd96f16571bcfde3870a330482439fb9615934970a55672aef616758ce3c2eec43dd516c10a005ae2a88072550558ca99760a8a1296fbe87bc774e385627cb8bb2a8b3ec21193514ad93baba6e78b6eb2b1f54c617695e40542197ec16d1ac99df4ed733fc8466dfd3a5c4c3f1ddc011f4b45d478c0e07f8933a3529b657e9c299ac5ef3d35b60dc9331a933599f06fef18492dbdba766a3860ea7ed268217c2341baf40b3459eef3c9ea382ed7ff18dc228d365e4964ccca1270e5c46bd381a4f151b8084c64a22e83c331100419430963060ad26897151a78e41be8688c739c86d64cd19181ee1a24255f5bcd5f37f15c859c04e85211ddb6abd218b94881e7d626fa288d7b92620085bb9edcc11c9d85303223af824e59f112350cb6af413b16b210c8627d2b61c60bad730f6c7d41db",
"spend_index": [
0,
1,
1039465161,
4294967295
],
"result": [
"a2a16cac35e718b07027623e243e73ec51e6c6465302cd6a4183dcc4468aa8b2",
"6ec7b9f66c1dd580207d465450f9bc88e9b89ddb6dbaa8217bd4d818263977c8",
"e9834cbcffd8ed9419d5f0dfc17e3d23d1676ee29097822792c75ace48dfc38a",
"f15f04bdb876303c6a20581f561bd525b702fd8fd073a9178e405ed42b9683d7"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 5,
"Witness": false,
"Version": -1778983691,
"scriptSigs": true
},
"hex_tx": "f5dcf695093fc181e8000000000000000000000000000000000000000000000000000000007e2483b3fd1101d6690001ecc003832513a53dabcc55b97f41ecd703ae104fe896e0456647f35bd0660bdc3a90d8bcafbc654f44512481794cea474dc3d663cfc58b213c0d57ee05a04ed9a18845a52087b93fa91334b891e42394183ed2ebb43eacc66be1fd4029b5528cd19a8cd749f8799fda3c7a844a26b6463c310f0ce6b20499d1f0e2a9dc12a8167342009371d688e62de4878a9f4fa068aecccbcfe28e59a5cfe0b1158ee184c36bd2a5afe0c26cb430494def39b2eec4fd0ece252b427fec0bea90e5cf595613a5eed4de54b35a89716d44a2d8a79fc39426d57fb67da6cd1b38c61d3a96b838495c4f5aeca6e9d43eb0d024014151c144bf2067bf6d31932ca44c954ccb7c562885040113c920ada2ade923e31fc0581d7bf73097000000000000000000000000000000000000000000000000000000007ede57e7001cd7d0d128797a9d00000000000000000000000000000000000000000000000000000000f949822e5385ca0bbdf7d3f0882caf0d83c26d2036dfa0b8379fbe6c5dab138e30dd7be61b5d85352848215842755713c53cb73b04109852e9806c6794cc26677de7a4cd06d8ad00b1c8365625f2eb9e0e62f57074160bbb2d9c678a973b77090000000000000000000000000000000000000000000000000000000040141ac2005946c4007a4a255800000000000000000000000000000000000000000000000000000000d6f015e1dd5ffa5dd907049505d2988b546018b952e3fb159d4de638d9489ba60bbcb7b72d88f114af486e6538c9144974214c22996633b87b937fafe846616a5cb843b630d3d69f5596b982f3160c3db7b086261310491f65e9350d66532561210adb31471b6d33021a10af85eba4496e1d5b780d3d730ae304831fe2545ad6bdc1ac463342719a2a13ef89bafa5ed0b5e36c08ba70f0b688dba8e7ec9192c9b6896918c9038176b9a52006059b7142789e1b587cd4904cf8c0cd9cba8a07baef19f6b060f13a427ca073e61f05918a7af7e1478771f2f7a0cc81c519d4173c972850226edb725e0c1600000000000000000000000000000000000000000000000000000000cf75aa3ffdda011fa6edc21e87d0b325c7cc142958b9b6613e10da0e532fc462cd39eed889b95fe26e020b4a10137ee033049364482e0c8962ef7ceed30cc4fe9ae6d153ccdfc7a317781258c53b0db40bc2f1d43e5089728ac926f2daa82076275f0ca2c5bbec79d310aa63319cdb6c39ac20a191c24ab5d755f18d4379ba40e0496f425378627dddd02946e82ab8268db208d64d642ed556d0328ca41ee3f4bbe6cc17a10946976da05ef023cb10c08a5a97b29e79bc1884540356b5c92254d84d1c551a2fecf7135ba82f8c861b1aa55cd0f56301e40a43cfc933719cf67e4c6b0c36f9927e96923b944bfc202195b434473d18f0f705b1d5c19e37922ef2f4cb50273b840ba5aafb90fb7b2eb9573da4514c4df6534841f945237a8570100e723b111dbcdfd2b5c6e1d6ba2f9ba9514888705f6dee8b1ba37013ca47dfb63504d6d69f7a388282af904cc216975ba9da3ebaf854da5c43e6cccc208d0d54d6ce17502b86427e8bb52f4115d077a0af341363b5946de9a2449818a4f59159d75087633fbb1bf6e5b022795a9217583e54fabf3170068904d706fa329fd9124d2bf1d72f045d817a510539558e7b2551c11925b06101652b42377dd6482e447b7a16d2c5284f706889811766f0128c367860f617bab532b7bb2aceac9625df264290857a69c8d3fd00000000000000000000000000000000000000000000000000000000c1ca65b1004c9762cc725275cd00000000000000000000000000000000000000000000000000000000cf012455fd1f01f7655f0f0ab2cd04fd4c9721d2f06cdf394184ac47a9011c04ce52b65be28161cf788f3ea2d192fe7b4f4230d3dc404c449ff4a7a29a64121844c4022b54cd54969f763f46222d0e11ffa3e66a87d535488af9dd4052abe49c289cbfcf7d7f649f0e27705e802275e460253a29e6ac2856488aff974ea04e8b009c53ddf849454a219fdb3ae9275b6156fde5870cf94eb37796c243dbfbe231a886cf42343e5f173b9a618260e062f0a020dfce2ca617aeebd7e3be3e586524ced4bfa21a584f5744a84c609b715bd912efe7494d26904c8e43e4027df4d894fdd8fc79c1965cccbf9bc697c7ede9441715335dd3b4666989a9ea75e76a1c3a494fdeaad4848dbe2f04b4131b3a579c3914a5c5227fb196c837adc7bf21a423cff2cd8cb5b71d078639df7b550000000000000000000000000000000000000000000000000000000000dfe9df45fd63019188e354948cd4b72d16860c58deb309e252eae07e31be10dc9901b268080e54a875f645cec2165e958f00b2d8ef994a7bd5832dea1496ebae1905fd46073efee82eb1bef614aff71cce2ecd5029442773ae07ed35868df68b80897c0a65b6b61748eadaaa9ebe4d2d125438baac1a2ac78f3e3119e7a8d5f0d2b4a134c724b5126136ded6842faa8e6a4abf6edb4630e4c878ca8d1823ea01bb9fef5c9737db5671c5f12bdf5aa8615d19bde847105237130bd3952c426d5cc1de90905e27a96cdedab96d44153d215bc43db1e01c2a5940cbc371628d3ad7fbcb1671506246e682416ca0fc5e72c2c5010e9f3270ad3e9ceb8d0505db9f4ecd5342957d5372ede3675584ef74ca12dc7ae5df95d870835ebe6376ff628b4a34541525bd7d5f6271ba67875d7cd5b3654af6a91cabfa23ddf0e3a3816b214046b143f075c9f58671ff9b9b730d606485b6304db2d140851448777037bdbfd60009b7ab63e1e729e607322f398605d7fa164923530a5fc830ba0382cac05055d663f26fe99a2f5dc7df97ecab542daba3e05dceb666cc2b73dbf235b9db9548844ede8bacc71194ca9bfb4ac6e8a0dae54df7dba17332cc4831bba6561bcd4f7f3ec5e92b634390e1c135cda417c587ac97a8dfbe295f7f953d5bca200891b39f19c190596cfa5cf90ee33cddc893ee9a79fbb836bfac4cd0e594036da081013cab6aadaba86b43b288c4233c3d8b4f42a236cbee324c7ed9cd1981c85a4e46986909b8700c08f7162ce886895d49cf471d1080adc7be83394d1976425eb175167ff0bb6c0ff820c833b09daf471a0a20aadfb9fd93fa8d04276f2e48adfcd3fa7a972783199b63e2669380c972f3eb280424ca5887605032ce9ade7fde8f9c61fed04ad62a6b85a40c2c473eab56443a2f3538681a9a8be50c5b4efd6d542882b6fa904969fca17f2f63ccc6da45c05dfcf3d52fa770c2966923f5928360e2ecac4843de70f57fe214696c105ca61e96b1088843d250d3824948529f2a0a77a59d5d4151c03b4a47324904cc2941cf40e49f6d2a20601d4108272605d3917bfb294694ea3fbbd14411959ce4cea3d2f2b68bd5d55c839c0ec89b78417dce13986b76630d44979033fe9f899c0b0d3b88efbda0c5db44f6a3e0dde8a345f922c003c3509dc540b74ddd4c88fa65866b5c465bbe0b2ec09aef7ac70dc67dacbb44d3ccf05642205c3c927d0c545457cadd75aa93e19aaca697e46474986cf788194555e921117731633f8ee7ef0de7143a62dda72dcfe9926958d67c5f61522f31c8ae7c0cdb228a283b5dfada72b94e5e4427647c083e1d45d00c39bd17a78aaa8e4253950b5f354b90f26376e09c8b87cbe96d7ffe53318842b2ed13a3a13bfd138b1fcffd711bf074c8644c9ed0edfcf98e37cc6322f97fe7dfdb3d961e7034687c278a3a03b039ee63726e2cff8f2a14530c639800cb6e3c05680ac03763ba60c4d39cdea5bb441856d487bdc57fc87e0ad23c5c45c117b7fd0f52f5847d26328c55865329a37bf00c42304bfab148191bfcb5acab3f801cc9726af71e89d2033af0d00c5f28fa28fa10225b655cd3ef0c5f49452a392dfb13db9a0647b6eda1c8bd8e4b2dade1bda2e1888fc7e503ae768f3ea27e5a42071d06315efec064371582941157502f8169a444371949083b92bd798139d5cb7e4fc8c440b761cd8bc8fe8808dc74c0c05812bf49f97215994efcdc6e3cc953cc5acbc4e40138810e326af9ae379af0d580351a0f1052c50d93a4dc759dd2345be179c30f5625af069b5f5c4af6ef956bf3610b5f7e6e87ca462b6633cff354a9b74139a3c7297a8bca323ee234f6bf639d1b204aacdd9a18f56e4ba086d40b0dc800a79a80e4b81b20a45d3871d6d2b7e002445d7747b261cdb82704357834a7025663c5a6ae43c0f21ee3b8547af8ba31a59105b25d6a4b47fc46e124a6b92d6be05a7223483fa9df16d6191028",
"spend_index": [
0,
1,
3001707671,
4294967295
],
"result": [
"930292e885c283bebd8ff54113a8eafcbb7ecdd6160d3fd243bcfaa30f60cb5e",
"c446abcce18fdabe4b288924b4aef3a7ed504eb8794000ef1cce0ffb25dec6ef",
"2526dcfc4befb9e6538e5aed58471450ab49c9545e65469894db81347276809d",
"4b1720584038bb4e9feed7f86aae31af7f1420d0dea479084582a0946d7d1706"
]
},
{
"desc": {
"Inputs": 8,
"Outputs": 5,
"Witness": false,
"Version": -216890641,
"scriptSigs": false
},
"hex_tx": "ef8212f308a82f1ef100000000000000000000000000000000000000000000000000000000a4a996200000e822cc553589640000000000000000000000000000000000000000000000000000000017ac8d47005aab030d2fe79b6c000000000000000000000000000000000000000000000000000000008b7902aa001f25512aff3f4cdc00000000000000000000000000000000000000000000000000000000b2f03dab00e670be7b3e58388800000000000000000000000000000000000000000000000000000000f9ef4a420013ee1575ebc610c600000000000000000000000000000000000000000000000000000000f7f5ec79008c90fd5119b2920300000000000000000000000000000000000000000000000000000000404681a200cead0795af49e314000000000000000000000000000000000000000000000000000000008aa15dc600fbd521f10561d44a64b3e1963bc8df4f61fff9222beb129db5562575437f9a1fd8ca574d8807ae99a9b5cee236a626bf943342c065423e161f267e0027b3feaf36f52719729a3a0ef7697c4409ea4bcf412eb5fe072d5769b239597e45b992c9b4b7a5bccdb37fb3d467b27af3827836e651316cf301c6f286af4e0ffeee5d0434f28db1c34428516e16af6e4ae82c30d56e6c527875cfb3966832873ac00b5c7fc278f3b7eb9e5b05e6af9660e4e4d0f62bd15aefdfb1ff37f77b6d37bdc927a191be7e7959eeca3a2989363f5fb7cc33be81cab92da130f382dbd83674c8eb2acf122ccc06f14677382748ca1277c49a9b247165f73afd00f18ac30a4996825a77a2ad87b86ebdfb7ad14ae2dfc081d50719cf78837f512d5d0bd2c7ac651b53c3fe33ec06952394ff36d6dc5283068151f893047ef6c1c002b52e51039c64d15094a71d39e4b8ff85b2f6f3c1e15821d03483c0d95092f3dd637c98f6176ccae4e22d5182390447b35a92e728576174e7bcf93a81dca7a7993fc9e4a465756fb6e30687858bed579fa3c5000d1f37963fe5d6e62a638eeb8ec1e3b184e0ca2c016113125cdfb46e57ca2082da3fc8148741c8961ab884272045a0768366cb05fe8216a330fc28c7e9850435a8dbbb4355b5bfbe7d078db61c33157dc3b615350e23bf487c372be4421cd89cefa10e365c0188e80cd53ca6b87b9efe6a0d04e6f3eebbc1b2b58fcde6989533c6eeeb23bb2411cc2b01f1ec28948fc8b971a753c30be63783cc33028061fab62ba388b3043f66fc544f9c4ee231808fb56a4c9ea308c742ebeb8b5146e2b4ad972945baf28f6f4d74b275a72d9e097076af22d97e65d08fb0e0f9fb309df5686a51f839fc417a72bf2c49c9c9dfa03a076a6dc81179ed1a831760ea97d2a2621a69b95f603c5cd08a22670408832654819c406b24a88c2d13062ea6949445ff95e118d7a085f55c1787320bb9a4824f6a72c0a5488862b9191873ca5e91258ff0d175df136f0aa8d13b2a7e4369952f7c2e8e4d4b79a0418ab32a6fe8ef92d026545c25cf997a4da4e39c6322fb2be30c818f115edbf6df5e3afb196420fa6fd2068bfe3e111a6cde0c296cae0ee7a54a8c4e15adc38ca8855719d036b27349283359591e9cdd00208717eb8cb42ca8e2347198d321c9683a2e017875ef3853221fab31c84cadb6436fe3cb56c1ad93be49cdc2490cb9968918cb01b294d2dc694b254ffaef397aa5b83d640d06cae8ea97812285e57c3580bda02213c481907a4d917ec7ba2d635ef6dd58a3ccbe451d627e270270c0d86857b7263ae758e0a55b4bb290d48f8588c0614a1532e3b223dde1c837ca086e6753cd6031102bcf57b1b452646bc6716e3a017c9a90d0097333647d7e1bdeeebd0ce438000b026142d165ab676b691175cec7aea89e383211d9b6034b4f284ae651424351bfc70545b78b263c7988ff915a1907ec828da7fb",
"spend_index": [
0,
1,
3359567509,
4294967295
],
"result": [
"685c624863f861c67e4a8210849c73759d3347ba3eebd7fbc562135f7f47672a",
"0a610c39cc9ac49b0a7cef972d2162fb0804237112d98a17c38f8386ba3680a6",
"9a6ac014df6a98749b0911bf326f7bcb5acefd7ac764952053e924760d3cf15f",
"ae96a56a28816b7e586c0cc694d8d8c15004e2cf87f1e06b68994999c4dcfe3f"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 7,
"Witness": false,
"Version": -1883448568,
"scriptSigs": true
},
"hex_tx": "08dbbc8f022f54e72e00000000000000000000000000000000000000000000000000000000877ac0c9fd250134ae14a0b9eb05820f80cd61c1d7a6e6a729a9c84e4e2c4e8b61a41aa855ca108a0aba3dfe312988c96136dcba486c17ed0c9e100d1be2520d34e2989eaaa57810b12b333cfab0024f5733060ae2a4dd79528850de0aade918c188165ad60ebd5669288d078fe6b78b736ddcced05873d14775f648b93d319354cfbd90a2db807fbe5f251c4d654eb82d2496a17c28855324da8989eb9386b6e50584a1681546d4cef79a012ca3482e8cf9590f885775db885ecb22bf1672f7952a1349b31d0c95a2ad47c13183edaed9618d50c11f26d7229970d1f8c4bb9b7e8b29554ca4704c0028a0610cebfe85995aeb69981ce506959be35fed6954bea67e9537618a7ebb02e0d96cae21baeb41d05bd2f2f2cb813ad444360714c7729db5f6b316cb07da13646b60fd0de862b92bc0e900000000000000000000000000000000000000000000000000000000f3b39caebb3e523c4a7eb0ef24bb945994e030b77a3f44c82343d4581ee2374e0124ad3758d3c388fc5716f0d2990e263784eda69cc2938631dbfbbbafc2de8aca297942516676c0d33b92add38756225130848ec9f6169d3fdf3ba22a82443d1e01c61022fe9b748b67b9facafa5b35efb5f529b57e771f63fcee5b9122957f56ff47be42e2870bf093754cf096025f219f3569d400dd159c96bfe4f1807f638325b53073ec6f8230c230036db0f3ced100f422e2c708b2d507e3a27c907faa9554fb5f070827e935bf9e865ec818c8b59b541e199f7c7cd377a7297625904ecf0abb0a7756b0fdbfa7e3b583f90f5ade635f885f80713f318c59677f090f43a75d9681e4740c9e1516eb7670af9f50b842536d6d7b0121f56be4af5e9abb7759e584613ea51bd5491bb221bff5c3e0c8b7d2a3968e184506c4a2af09e53cc24e34e300918f8c2f9146d7be2bbd6d25945ce8b2145289e7e7a21f84b4cc4a102fb597787f15896348784b717b2e950619c69d561a71c044ac13397eb3cc4839f3ed9e027c65920bef596251b5b80e90ca7da263e8bf27cf37b1c1ca887cc8bd1646a1308e578410aebcc9bf89c58a3f3317605755de0279f11c6e21c6a38eb615083fbd914e30f3241fbd734fc3f96870bd6ce6d39208fbbcecbff639377038fd245815a52cb4c842cf3b3307171a574fed4567c7f57e907663a3dcd8cc2404f8051fff2dfc11f941043d8605b11386f3ff7e04b59976895688c544a199b323bf6b8e7b023c0796ed8b36f5e4bb1d5a12f9d26ad9cfee2fc4d69d1d95e2fa72c25adde053f7e85e7cfbf6b916bb0ccf993a99808092cda8b14921e2415bc65d30a1173dfd3f830a6687cd9779e97fc8be7e5034ae8ebb00370c0900e0305338651f1a6dc93903ed946308802d38d455c3a137445e36c379e002eb02cfcffca370ae2d9961c6ef7d424b962f455f3ad22bda3cf12d68e081207f8d1565e9967014a4a1b06f5888fde8682fd7fb0432cef9a23bd2bea7c26ad9bf5d38308c6ba2fdc9c50b9588a9ce7e2b92e81b5c6e761255b239a20cb2963e691407fd69faf433063e0a35514e36fca6792f4e65c45890da1ec231f3d3b4e75f7f449bdb8b5fa0182443e110ede564a1671027af992f941dea938e5f7da5dda4ab368c575848c864d428f8f146cbb1beab77c483b4b42c477f817e343655cf3f376cf59e4a4ff553e006a200f5e749eebc52f9cd53cbbcd1852c3facee3563181dd7be278114fabc0d3c11e91c29ad4e59057ca48c08755c7e29c02a85174c118612ab99fac76e1d610635138583d0750cbe836d146a156c7c606fccfacff44b9739ca4c4aeae943e07819649edf8278c55e88e3b8b6e74a4ec077ff5a8e253cab1379a13aebd89963f2314d2ed655ede7f71d608548bf3d965c4e168cf13b1b46ec2e1aa2e006d13598801ab392042865667e7e150406c851c1c869a8b07188d4ae8adbb37ec9041f2a91112d95b66b90ffbb1d1190b4d7d1a7a3318b4a550456c9a74dc300be42359ff834542629e1de45a096ca923a5af0f3f00f33ca699a14c6c36fb0edab108387c6dcdb0cedff8341f8882571af05184ebd9846a1346b80e8fc7d28f69d9a020255831203650b9e91b2577f22d82ca5367509ea0ae4638a4dd0e53df0c570681934e6d149fe397c742750f11ca91efc8864a2fc807db1952c19e9a974f1b597a4db66cf4d371eb579d78aa154829799c4320b70ed9ef733d4ec9e33266a2dc84e9bc1bb0802bf456fd27500fcbb02fef049ded55990f5dc193ea804b498eceb99fdee7832d3b2a560587d96a71e656994cd0388de4ad2012150dd728b288f9e756b5defac7f56f22e770f450c52ab73649b790ff10e9190dd0f0c45a3dc5569bd7bee562e67e9ee9a4972917c346410735954b623547cd7336455f0d5cd3986931353352d02811e75e4f3b7830f7dcac8fcdf0b515918d2b94f2666a7c58e0d8d119cac528006cb0f30cb7bcd1016323f7e7906d1ed5aee15e826403cd3c744ba008d1ef7a2e14cd8d97ed77073d851c8d37c096e1245c704af53c461e561152877945c9be828a1ea32094b9896752086a5c13e75e0eec5ce591f4b5204e9f84fe205d6328c693ef23211baf1d562b0db2fd75a3c5f874ad5a12630597dd94091905f69f2b3319dca7b82b23e4d97f8c84b05dcf3aa0372b64702708a0bf89c3f135192f07685c6093088a6c11a84423a95d450710f5628031be2aa82f2bafbb20a249d8d9211fc979e977895f28bfdfa3c7b74b41aecbf74f150561143cd019417d4cae61e1fc16330948eacd2aa926f0faa413d634a2c496294cccf",
"spend_index": [
0,
1,
3425086302,
4294967295
],
"result": [
"c4ff54c5b6bdfc36141f3e24ddee434094858fb57bc0d0249c70d3898c65ddad",
"209df5582d0e9a7e694ae163ddad064a842b7f98547fc16c7273f1caf2102ea4",
"b8dcc1666c513171ecdc329d3041f567ceb4045be8f728fe130490774cac4aa2",
"6132d4ba22d464e4b5437f79b7e4155035eca1d50cbb8822f2cf343f293d97f0"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 8,
"Witness": false,
"Version": -2124013575,
"scriptSigs": false
},
"hex_tx": "f91f66810631a91e3f000000000000000000000000000000000000000000000000000000006456780f00e54408763610d8c7000000000000000000000000000000000000000000000000000000007873c2dc00b49a2ef2a77e0151000000000000000000000000000000000000000000000000000000006d7056ce00aa6eda299fa9ce6600000000000000000000000000000000000000000000000000000000abb7300200709c29b21639f50900000000000000000000000000000000000000000000000000000000c26433e000c6b3e924b4ed2f3100000000000000000000000000000000000000000000000000000000b202ba1500b43c304d08472ab497abd2913dc82c05bc0c7df3fe622241479aede78410e9e0fdaad46ead2cab38c427309fc511f552a2d31e1249af40883d99d1bc8a74992361b8a3e2ee64b1af943efa4420caed82c1ae35059c08d72e4cae205ef4d902f4552831651f31032f957c739aa835bea3968c67a96dd150c6a6267b4f6583502daa96668012c19cbaefca3432c240ead9f5d41ece9275c809b876501564b20cf4b01b084ebc87ca4bc53b7196c52940175d2009ab269a4ff710fda09933a59076511c40208a873da1d9a1614bf906fb448ecbe93bf67f417f21fc46bdb630c8088bb17da2a0ecc3077fe5c3d8ab5900eaee042c40fd71664607164b0e6255e151f125c6af0726d8b478c8bafa522c8ca8edf1c151aa84f61614e861f5ae9a4c7efc1726fcb4e0f0971b87f55c14d64d78d5b07248f0f8ad0bdc700a89ad8df8e2b446e2097a6c96c3f9f1917bfd64042c6f042a69219846da7e074ab3d2015949ca28d1df0d205136abb6526b8ff5889bcfd199eef182d71d1d423d9f8cf44ab1649a9a1ffa86512973a63d0584ee127e8cd18554a72eb9a91a0f19ed29b0cffa7598c408ddc8e811cd35f685545644c8975428b075e0eb87fc1af9004664ae0edd8484e25ba8d2bb1fdb028ce63c738b6c27ba304cdf393c6d77619b929ced4db5702750725938addfca160eb66385d1874c2ebf0827bac548b9998f2c4b19744584824e0bf1edfad072f2d30a8530109cbef822376fe7c2e7f7769849840e946bbb57070b31f334593f3ba0bf01ccdda6b0c390c42c4dbc10b6d4c77204322637a9841536cf46867fdf63801ac0e6ea2a19a33cd15e944c12d3fb47702b3c53f3800bc6a3a6b38d3c770a0d4997414afa5eebe422ec2114d6e8512f67350c14c823e4fe85bacab8814cc2bf4509c294f69f6592797dadd9493a06255d808bb882ecc1bd2a997d499a3d2a03ba208f4c252ddbcb4b3a07effcfb3faecc09447014489a2babe90f00c4d672ca58b959fd61c2273d80d22c21085c17a182388877c9cb0a18ca79b26126b8244a0e5f09892acaeffc14df529febafe6046d4602cbcc1d089d97b9d9275a914ddeb1e24144083ea3e4107bb499b5c1079927a2e46892d54540b783676f45b7ae002181527a3c71a35cfef62ee769b79a41805a6a70ae2c79b05a38611bb0b82de3845eaf6879c8780514862fd430b98d94d1838bfeee12d97aa2483882d8ed993939a93310c2d8822fcd9f72c4adccbe3577f2989a40393f52c70fdfed7967272d3c12b10d6d695e36f08b0432ceeee160db1b775be0f812e0e6898985ebcd51796ce9dc3b3df9bfcd13df766eff953e4e142c381e7c3f32c1cc77e4726ec586467b474bc6b3634409fe14831fde7dae12cf7583f9ddfbe98144d39025b8e6e7f69b0dae60bc0d3f4f7a0029eda87e8f26c3458977af84ae4e7fb6c0057ddb9b48d5eac73160459ee15c7281bc103e9bc72e6389830000c85fb913f2dbf8a1c92413244216f9ff4b34d6a34a2281943f1a343b8aade6cde15e15f4228040af5e546e45da72e1b1374b61a143a238249400e2f5103e25824645be9d35fc74b5652894abfd4174608bee29552b7b88096181eb342424cb0adedc7285add1cc4253b2d76aa112c5ed06b3a103f982cdfde19ae64b913826bf339a91c4791d3824de23822025b7c279aef8c9853ef0cb43c180384c073fd6c76815692659fc15295eb62d1c626f981b903fec6fc6ee0c17948041726dafb961eb249a8a44743e66eeff36d312cf3c7c7fc875fb7b42a8d993c3d49b2c90f5703d0845bbe0ec37343e3b501f56a399910a9cd2d2da42d0214ac553bded064017ccc4c07cac9edbfce92b22a7661011ef9f49c1f0410f2c4a7883319b6aa927ee8db5bb8038bcdaca74f158969a6f0b81e1a00c1e7f386db1ecc07a31576fa76bd2c7f957b926c11ef2ab6a1e8d83a07d37acace1a852cd37a26a5d490818d045300a54c813fdda483630fa92fd9d06af62b3a4801406b2fe7b5b7d6011a57bf135754e05ae28b25d9a14c7404258259b99384c333f13dddc28aa41b9332ecee74f58c80d774dc5e784e4d9a4b10679f6947270b56c5f6997ec141de775b4c53be5abe6af8b522b6b7eb1bfb1ae737fff7f4b5779f3749bd44af958ca814817e5bca716083cc36dab89ce480e6b799d43c4a07735bca9526afba1240adeed6c5d4d2c277e27da4246ee0d7969dec01f1cc026fafebedc9aabc47cb3946b986d5a8e31f1bf99d483f4cd74f0e7113ef780e694c31b552b63b1691f57c02e7607780047161b94466bb0b2d46e25a405022d2545bb2749acc82bedb6c18130d6869bdd0c8c5c72242226933c08ebde16c6",
"spend_index": [
0,
1,
4231503344,
4294967295
],
"result": [
"07744dc2bec2a557bd05022b9bb7e12b5a8649fa00963988c524781e0326c47a",
"0b270576e396f0894e3d4217f9ee7c85937a63f0d095fec74174b0dc3896a837",
"964ada7ea73231c728f3f60706e0010b67516e8b0069f659440bd2fd799abc71",
"086d75dcc9731576f388fe97b6fa83d562c8e51742b18330d0856d3dcfad907e"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 6,
"Witness": false,
"Version": -2095044500,
"scriptSigs": true
},
"hex_tx": "6c28208307060ac1d90000000000000000000000000000000000000000000000000000000096f5aa0ffdb4010e3736ac16944cb0bbf50ee66da139409dedc362041859ea64545969ae391984c36ecb9734a42ca92676521cf835910bd259641c74217d715465236a1020dd4ceaf6a6c81f17f0e05f7bce889c3fc10e97fcdc10b3f298f3abb7cac2fae62584a19cf1e328cb4c88dff31ffb5a8e108aafe752f3de151f06516439896c80bcea4c79f71c68a335b4cd167f208d21a997f3640ba9c373410e9c003af59c718728d1a6d849e1945e107206aef6dd4d6d79d7746aa8c50ea2ac5bd839bb24ca291cf37aad53e78d52b0b05b154488f6d1103c50adff728703ea3f4542e14b4b4cc989f8105bca92e67b4e2cbd06dee29a638b514be844b38357142525ba77d561b5bda9811c837b73089bf6e880df1fc02ebd64765b7353aa88e153a2f19babc83d4c060115919f729024a01e25f8bd1455ca6d2a76abda90c9450f4a7744e3964a7e43a1dbbe2d8eb3b80c8ede51a099f0e1bad4db24ac50239fb088156666c90a7dd6d1fbcf38f7c1d3b5cd12727f6afe3c57759b787045bfb2654fcd66e7302386a87325c7506b3342aa7b45fbebcdbb8eb0bd7388e8eb55d078f33760f9737092f2e4cacf38316e9e8033cce9b3a912124f651eb21fc2335847e6ac000000000000000000000000000000000000000000000000000000001fcad62927cdd4fab9908abe626c449532613699ee4dd4a1767012b5da4bee04483c2d036f73ad64a7a8f0c9c549bf7e7fbfe9fc00000000000000000000000000000000000000000000000000000000f4fc86ae37006902b4eeee9dbb24801a0b38a7d194d773efee77edd3f553299a7be77844e580900055aa410fd3a6b92dbd40c0086e458258aade6a33e977b7a65a5973080000000000000000000000000000000000000000000000000000000016f0c5b5fd920153a0a6dac7c870b1be759c7e9ced21d2d7a7f2ec4f3d9ec6d977f204879ef9c4cfafd45f82313778ffadb63a11eee3fbc354141474dda7821646ffc4fb87e45a531018999a7a3f967e11ecf99ded742d67ce91ed31c92d8a041a97c1d44eb75372d6555a9d20c1dc9aa576e3e440e3f21192e02b4001e9b7d766af089c7153dd79a020f9444df960e5bc0881587aed906b66b4f9b92b060f6ba7d15d23355580b97697a9edf34c0c65db5e601513e367c839c78aa408cad9c6e118b5982dbf0ff062a2c5efa0462cdd4f40c25fdc66f727b11988435351b1662b79afdc2771dd23945d617fd8f7c8b1d75b366443ff05764e60ab8ea165a63c71b5255d1e7da579e51836529b24d2469e81b25b0e9bb1fa12ac8e61b0a7c0c8cc85bea23b691e415837ff6786e1fb1d15547d7ee4dcfa4c57e914d142eb37e6d816d4808cb422ac74b0486f5a6d2e3f084610ce1cd5e60b5450d68ccb644e332f65081f6cb873b18b8ebcc3a5a47b8e3e10c1d592bfac9bf1fc2b26e837dc8d5b3680e719789394d8209423a4f633f6587c394255da4d6e64592f94d8839bf994000000000000000000000000000000000000000000000000000000004af9fdc600b9f2b5494ad008ad00000000000000000000000000000000000000000000000000000000cf6104e92b205f957cd7699c242984af2ce868fe1ebe1a25058e271e1f68e2053891eb6888df286721732afc8c3f58e1472aef8fca06d3340000000000000000000000000000000000000000000000000000000087d4389afd340194a2982947fa8f757bda68c65d75284a67d37d5b9921e75ce40afd5bd517c65c000a66ed79a208319f521d6a737434fe9786437f97ebe3ad3fbe8349ecc8ce2df5d69c00cd372f04bd36f5bb2d7a59c7412cde2c0a0b29d8fbe0a9fc3e5afa630a5e88c42dd617f38d6728c7a95b2db9837dfc6db91b52bee2812865e51aaddd8d7e58d63b8f2824e61cd4e73e2236da52fc486430c0e644a6b5940a01723cdaf0bdf79b210971284ad9e9b371bf7bb75c35ee7217a35649c0e50be730bc0911c7f753d43e930100e89ac61e4fa4bccea1d254bcd0ce52e1c8b971362dc02037c236165389f193d7f0be0f7379110c7d81e729f83642d37715b218fdce818036ffc796417df655c1302032692e0030e1a4dbddc5813de030fa52d5d19632fb0021462ec5ba63cd3400538c10cba5e4533e1b956570b681170695dde7418eeb1a7ac830accbb70f4faa19eb0ce2a49ca8e35b30243447bff801b5dfeac06dc82b3229e94e36029500d83a8249e8082aa0b0251e239027ba2b119aeeb3b91a8537a19dd3166f6949947fe6bd115efd3a41106fb98cfe0d4497cac0635c43db73ab70111b402e59b940743ed8d61853f5493797485e3a5e33eddfa6566d5863836f482b21d650e0d05700b0635b0b8851a0c6e6be79027b6830ce371e760ed37a389c589ea0778e4f0551d4ab3e9c40e2990947354c38ebd58fac940e17db022ac5300022b704212647ef6374b4e1117f278857c8d7575345139f14a21784ad6027e2f7ac9d659a3d5c36505c07a8cfe7cd4984db3ab9459bb636e040e3343ed8d7b26f6b9cd3b5a0aa00d1ff62516631dbb43423360fa3762d9b99567fb84b55c91a76a30428758b08668ffa04ffeebf45d78d5c85b469d64a50dba4d14390d0222de714bf8be10616ccb4c3cf1390797a8d2c7f7817242555e66eb525a33f6934a50e1025cee790ca2843dd819f7bfbe6a5934c54420c5e351bcbc959f7ba789fac2ecc5e7260e3f2c1b3affec2f46103642744bbf536320a9450cbb678d27d7d5f4e3ec8f9d5862878725bc018a92eb3797a8178c38a1d96cd43540b7833c0cde3bf66191889e9292bba64ef55241a1acd3630b1616efafa89cfc28f00172124dfad3b37afcc05857d0df8f5c4daa90e4819f7cf918ca0203279204f754089390e14f92a49f47bf85bd88ebb9c16e5335f15fe04ffd7b7f1d621699098b3c685c31082767c839a5132eeb22670608766854ac1745f0872349dffb86099f351186094efba92b2c64810aa05d903e72d0b28a5e53121d437f1cb007c4d0bcdbf80e6cf1ef3ea746a9e7dabc1a66890bd40e732b527c82f8e25ee066e122a639a75eb62562778894efff4683edcf07cdf042cb4d071df24271dfafebd7f952737c977e70d5e20a1480fd39603a43c3808aed3ba9d38bfd66c3b8a2d0f763f5b733075dd6e563052a5286f14f419bb75969fd0a204f430efe4f820a9ace80aa3fb12dfa6c6f6c6b316f1d65c8e85dc819dcf56baba734c7f166238a7ebe5d6eebeb0a2f0fe9c67ea4bbcac6392fb6f3f9ae158b74e602d5a820279a92bfc7ab27d99152b1b2f8139d33402b48ef021d4f4abca738bf27148879f6877a5ed48ea76c110e3fccb59c8638b72a29cf281d2f0a68d14e4b79255e0b4b0a97c65cd207f33c4313ab58cf5a748214931aa0883f533508593529bf05fe60f2fbd4206b87dea735b10175319760b564e231049aa09870884352a721c01a16854e72e6e9e69e611c8cc856847be2c8e38db9c8ff9302df8b94eab53c796fc14752ce43be66b1616e40be6ff409ba1ef87fa8115b3af6d5a1e8e8ec9c35d68126dcd812267f60925cf8a752f730e9263d6ef763540094858f83c9a6dfdf5e2d475a9f2a478bccb83be31059cbaeee37232ee81a4846d187de30e405d4cc8876b83db63b4a2c8e40642a00f5bf318b21c74025ce90fb6bd5c7ed4bad8dd0b4715ad407463a0737e51b7b8f5fcd912cc1438887522757a6ef37d90c9e183c2211ba5e6acdd26749f355fdd7c20f11dd3ffee8ba87191fee44abc5b443a4c96e1ebfc9ef85ff294d6fd20f6fd82ca3907e5c6c20973ed05df49b8be8aa9024d1ab3fa54d994fca4ebfe9548b69c247f6b0eaea3242f912d53ccec595d9b800b6da653fd564bfb9bab0e39e989039132e6e05a6c9f694df5c74885d565cf61a628da54f534eb2956f82a7207",
"spend_index": [
0,
1,
3575252040,
4294967295
],
"result": [
"cc01dc94e18217bd5c50001a2c6f079fb7e37bdd1b304ffc695afc8ec71be0f3",
"2a1efbfeda89ef3bc34df79eb7439559c720f2465ac9083beb293f662c20cc50",
"8bd0513e5555b8c3692757f692f2d5a98be1db1435251bf8313a4fb5104893fb",
"0504e4048cec620be19b025fb0be79c800d3ac8967f7ed5389927bc1c0c620ca"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 1,
"Witness": false,
"Version": -341052226,
"scriptSigs": false
},
"hex_tx": "bef4abeb01b9bed30500000000000000000000000000000000000000000000000000000000cd79af5300bccb233201ea4eb65a0a33ef7dc86e238642dd5b75af59bde98b69cafe8099d052237bf841e9f921d5f9f1d116e9037f7e9ec2fcbb0969213a501077b99180f91ffcda99a3ae872ce91a86aafcf0ba5d4195743c7f1d2e37d1a8a3c68bbe9aacfcce85f186fa38c9d7365cea2081ee3ba877c794e6e9a228089d04e64fc7931f04109bb1c0c3fa8b8ddd47b6d89f311abbed387ba1ab6cb0128d5d763d03786285b0760a0abc516fbe28a8761a0fcfa6b0675c783a59ef5558c11850a2ceda1ee1009cbec3a5934217ac65a3332128312aee121fdc0e9c56438f",
"spend_index": [
0,
1,
2487922470,
4294967295
],
"result": [
"7fd2725ad65f970b0045073b678771bc28f6c3ffd68463a02b3a9b8f5c135dc0",
"351fd112af9b166cba8ce742c2527f244b9e9482aee818b23994b318d8a5c615",
"89d41fc99be7e44d57175f4bf9f5dcdaf41c78c6604f45df8aeba2a2aa917b65",
"c4f884db7b13f039dea9cdbbba05839ad7c1c6c86a9e4075d0b840cf79309fc3"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 5,
"Witness": false,
"Version": -47377281,
"scriptSigs": true
},
"hex_tx": "7f142dfd04c83cef6100000000000000000000000000000000000000000000000000000000ae4c929871f6604b51d016cf732f8bebaaa4321b7f2c64c14fd27ab201f245abef6e9c5730b5332365eba96c9d962618dd666ed5056d435d194f2977090492b12e6fd8544e355cf26af44b8ddd67169f8fa7e96a301782c1af391aaf893dff247ba1e7fc10d93e60c7066d1edad9d7a286aba60b47123a6d8ba46924ba9e0000000000000000000000000000000000000000000000000000000088a4000d0024c83103137653e400000000000000000000000000000000000000000000000000000000385cd66100a46e22e9dd035d6200000000000000000000000000000000000000000000000000000000fd6587f7fd4b01a58bbf41399dc0de27960de84d2f4df493b6b2bd1007c2293be63806183e7ba57765f361e3e074683490712d1ce48019dab7dd33cf2c150566f3ff34f20c0bfdb1fa52f58eefbe85bbe548c9caaff8d35e2757de8e2b38f0388267b3a1ebcbe276c546b57b38ad22995f242b0e048d48aba6642339c7889f2e421c4810ef9657182bd4a21721d74e7e118ece80c6a3b957b45c08715745253412e41cdb8ef1a936620c4fb601672d5ee5fbfe0b067735c97ee69f90294827286dded098a1558854fd1569a72e8c3cec049f2ae8a09299e38c6fcb5cd1ecb2e813c24c604ca1578215b84afaa7d4551a7b45dbf3d82809f8426f60246fe9353aa08eb8e5b75fb20e79dffcb2333df7a3341ac0c8d71eecf76bb6ea78f684787c3409112414bdaf31f57b83674fd47477e129978855eaebf0b4ee7f3107332eab11776d4d8b95e88ef2f4d5fa4b212fe91a6d58df8b54055ec18d52a3fb686ac85af069e8beb727436d52ef0053f809a6f7eb49d8a2a158d5025d0d18fd2b654cdda4a142114932a3fe778f1d8761114667d64b6b5612d90115f33a814a21e54e09d87b1e501ec6dd114c2992de6b6d076bd7d9eaf8c4fc071a95a92954bcd743b7a67ee40033dc4aad439bb89f445058e06d0168ca9bd5195d32c029379ead3b9823a5c53fdcf8c0f679b298a4772607d88fecca682405ee30750fd3e93430736417bac7a2ea7e767d7629f2c410a6b355bcf575bad8865cf6925c156cf722f1f6f230562f487f3de732fecbac36d065c82a3ea615b1481b5e873cac4883aaf24f8ebcef166870ef462eac18f18567851ec1952b1bbe8eaef01a134fc47e29e81bae2156e72f0c24631dd04b6a2b56dd5f8806df36f3dc175148840ff7e7ea02f6ceb241ea2365257decf29030542a208a4c3307bbc98f5648cfebebad4611b7eb35cc8fa403d610e2ee1c6cd20ddeb7d9bb142d44fdf4fabc095d70e849885d780aa14bbd3c6b3cd6edba384f2f57fd965df917caa4295f0d9c5070b19f242c9826e59d4b5a56390401bf741ce6e11c5fa4dfc9e229877a04950f9d4b480a0745c8ed95e3d42e92f311e3aa16f58a29b81f0bb412d1f26b904030aa17c532713f37853c0a1a99661f46cb90dd47047165f09777ed09d09779b15588519f40bac3798d1128822d12d1a623b374a385737834eb12a65a128dcc18b83993161dd902ec2a00807ff7de877bf4ce017c4f8b8b67e60b371c6c0b7bb7e23d27b674344eada4eba4c4fd109bc8f77d296919a93abe1f1fb9bbf3b175abfa3ad6e1c6eeba6711bba4a05670563dc37301085a553a08addd120277b2b80d5bfc0db9a816e1b6485309e686cf6333e184c061c8e53c4ec83968be78da016721519b40aa587eec25458b402d9365c983df46b918b947d5e7bfb6dd9df0e4a179e36bd3f9c6247b2fb3fc3f6bb0cf5185ea308324902cd1d291c2301f65c63c6d727fd4961dce3c9ee40a2c68afd1bf543b7c9e09ed1a16c10a18f0bde29d5ded3b4f0fdd9dbdfbd9670bc1d44474d34640105421f66fe5d10cc3702aec23f163f13fbf9ab3e8be57b5679f78c74cfc7955bb251fff9d185ffaea26bc4778e669f2a3ce0ae6be2a920b02a7ffe87d3ba46421234f40ea33e90d5729940e425149576387d3494b9a0cc8e8b5d9f605dd109c9b11923f71f6b587796adc342d28ea05b2c53a07efeb1c01029c08c861ee73fcfdfcd0584919bb2566a20d51def2dbeaed78614b34372af863032b36f9d0652a5390fe4a1299bf81c7217921f35de1b61b970d8a859b8842157c90a02732b3f01b89d3d460027650e0e63e1e8498645170b16e971d36d7b1197fd410b96315e6591a7c418fafef7c3d40085547c3a1541e25c4c4a0d041ccd64ad9fb5b4c62077693a81959223d81402eb7e550ae48e6bf2a2bf11eedc7efc341d8abe82ab66b0bdd53d7",
"spend_index": [
0,
1,
3740421989,
4294967295
],
"result": [
"4e54c0d04fcbe2f8563227e3b507bcfc0eeaccfb0bf210f51d7c953687b75ca7",
"dcf22f32f8bef20606c4b2ab7231419160c98f127968fc2e3ba863c16436f3f0",
"1b4456e430861141b7fca2414b2e1b87541f97bf0e6f059a397e48fc172be181",
"6df11c86b4040e32099e38130058d13414f088a84824c233214620e958994d46"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 5,
"Witness": false,
"Version": 302150619,
"scriptSigs": false
},
"hex_tx": "db73021206f6d0829b00000000000000000000000000000000000000000000000000000000029ef77d00a31a210425fdede5000000000000000000000000000000000000000000000000000000006dde4a06001a771768e833772600000000000000000000000000000000000000000000000000000000d5dc6bdf004d544772a96dd261000000000000000000000000000000000000000000000000000000006b14449300f2dcc2d158f3600b00000000000000000000000000000000000000000000000000000000bd121b22006ea7b3277d157e050000000000000000000000000000000000000000000000000000000016e3e1d80096225cf5056aec98c620906e73c896add447eef93bd791d8ea403cfb28e25f4785114d9b180a314bd6712bdc6288a65d59a3c0bcbc78ec4ca2a870ca97b9c89791b3a2a7886bdbdcdd110235c949e32f93670779ffea13aaf76869ba36c388e38670640381e78b4ddfa859d4456f0aba6effeb378e0867868db0eeb5ccabc0f3380d9bdde32df0e27deb31a4eea41319c8e506206916b0324d3cb4b740adba3e1943bfbaddc60770cdb61c4acec167cd789dc921bed5718ee29610b75ed9e28df5311d9c3e18e255d5e08a13562fc603650c92593491346e0a78a166c605c8e877d3751dc11d3486775f356909d9b616172829bfbdc854dc858db69f3a6c0efa46c949b2815fe19ec7324bfacc91644f49cee6448535d08fc86d2218707752982c14d70e6d9d3cd0d10c8626a70cfd50b45a8b084b673f42a8e730b772a2e9b090460853776413e5463f98d9e4d377865679e5a9f9e8c422712b32d8063e06ef0cf7f037365f62c134e941dfc1dd019af9256729ba0dc24a60f34fe3910685ce892e72e9e67a35af173471aaed7b11f6a34cc9117140d106976cbbb825e5b32b478b52ba37862e046fc8215a992c37c8f314c6c6f54db4db2a29372e5bc8df7979487b3a094943f981e8f608f73eca10b8c98be884cbf61b6ec388a89489b8312b3c13ddbeb9dd68f7db35b29c47c30d63205a3ed4d4fcf41b37d6915d193dee7d2950c2c5845f4ce9aca00a440d53a457cc1454afe0e3b7ec978c2208fb55d7f5ce98d8b708b3181111c78ca981fecffbb4c733ad474ca7f1db940299108b145fed8e06b783fe266359bd0a3e299aa0d2fe1f1702c93375827228583ec86739024d72d7fb55b62a1bb07519b1f9ec558e2ac3240fe7644bd200b4fe5c271e63c897a952a0f19c39f161a6d8c391ad032b52413178a0a1db8edcb298f4d0126dbed8d7e3d4ad5a61747d3955565792842be7004ccb5579ca2d9c55df5297193dc6fd0118a4c6fcde5aa7fb22559a1e6de40a75e7c0c4b1d9523b2abb145d87bf7fe85988ae8739e197c0950dfe8718f9d1eccc0f6094993a39fe4db61b0e5f8a1ad1c2e3fc619e98cfe73eee0e048f181cf2542afdb9cccd59608dfdd3e4c775e592660084eaad78b4d9482436f7cf8e8fd030017b887831d4a3261690a088e9fedeca9fc0cb8e9e23924a09727b3c093ec8ddd667112c9eac0a33947887a994091ad6600b43df4515a72119b5ab2cf156affdd068d381761b12117441cef46e1588f18a6ba358282e73b7cf83fc967de9d76373a73c7decf3ad86017e5b4871337adc2a894fb84504de61163601e8984c18d8d238cdf376deddd927831f455b5c8897ef01a8f7f75f05dbf70ad405a1f0cb0c4928cd19d486d0154e5de27d5a0cdfd1ac7149d99a8296c1b000f8f11dbd8109338fceea23b292ce5a066869cc1a6dcd56908d613b80dc0d2900c8e28d7afdd99638f5912cdebc3ebc93e8",
"spend_index": [
0,
1,
3924639277,
4294967295
],
"result": [
"c130eb91cdddcae416e509154bc93a25ad565328d7ab173ebadefadf5e5ae33b",
"7813f516c93db754f5bb5c415ea60f3b23600eafb55f85c82e0808f593c29d1b",
"cb64ad463060f574be299ba9e7433bb25fc20d29ec3dabfaebe87d2047f9146f",
"da80644e069e1b695aaa1c44fbbc2be53b7a5b8104f28965182edf5481fad150"
]
},
{
"desc": {
"Inputs": 8,
"Outputs": 10,
"Witness": false,
"Version": -1687061332,
"scriptSigs": true
},
"hex_tx": "ac7c719b088018f7350000000000000000000000000000000000000000000000000000000060ee53ddadc7f6e76bd1e7a19cc794861844ba6bb84193fe748aff616cdbefcec069fd78f98637b764b81522e34f02f600e0c255a01d8ea4cc243621695fbf6a556801168bcb1229cf436d3c589e4f2ca7f015999bba2d22ac41f946d9137f5c858788b7838bc95c38e435ad4a7912aa82043b1c5335a3e9d5466f26dda631761a98d57d6a43814cd3379e66c7235809f61fc5f888cce6a52db6a97c7640e2c9822c489eeb3f69ebe0f0375cc0865701a25a7c1e7dd2ed947a1c00000000000000000000000000000000000000000000000000000000f9585b70fd24019e7b1d3ceefea1103dc596eb827f524acaa0012e73c35f4849c3bb6bd8243898ef39dc4cb2264017ef1a8c0da8c381e9190d9d1610871f64ba9103a9828c14182c7f9d9b1e75cf4fa285333c00ceef4aa5a0017d3a04256a7c1aececdf5faa46dbd26ad8074277c4b44f257c4621c42d30404650eff423514e767ed57375172015f389fc8c988032420aee0ca83284ae543ca172854e0c2ea60640d52ac8f6b0f3530f0b22237ce5ff2fadac7dce6641eb2c8bba1e64216b413f3a78068d4f2f791148a8916020ba45735c8acd0bec26a79be1d90b34d960dc58cc6223fcc45d72ec84d90d38ced9c3f1e924438d687b44992adcef46b8411f90bf3f784bf74c29409278a3d769d2cf5a95cb03e74d55d26d96481e49b40a574869ba8d70e34af1f197713757bc2cb64d2740000000000000000000000000000000000000000000000000000000001d16dc30c0755267c7ed369038683eb583b91a6502c6221e7e447e7686dee46f5691b355edba357cf34d1451d64db554e09505fd6338488a6179a524fed73d39cd4327af7c760e3c7aed42f6d7b13f28ce0bef43ab6c5239aa67329629bec04ab57e4a2b8e4e8de786b7a689b95296a22254da1c284f08267a20ed790f5f0e956eae97876fb2aacbf89696eab0d63a74591f7a5bcc8277648c81319c2739b70e05f8b4b721ee2ebc025baf60e88fb41842b5d1e75acf7bb43499b0ded5a32aff3043304fa1948475de4f504f5f00000000000000000000000000000000000000000000000000000000ebcd37a1196e15ac4a12c4b7b9fb75bc7e9025137b360ee837e806d8f62eb3ff6b3ab00b939e000000000000000000000000000000000000000000000000000000003a24db7af3386cd1c52714962bbfe0ad27e211784ca2428c5042a0b3bc986884d746b08465ef6d15f40f684edaa976ebc352cb25bfd702a8cf255008df17e2fa100e9fa9a6be9d3b999b87d6ce1cf501e9afa374e4315673686fb6cc45e94ba6074c895d85e80eb90a3ffddbf3dbf56c732769cbcfd535c1b04e17547a04e9cc6a712cf62c767449bced4dd3b293b3a1eef8a59753b095faa4dab37da86af77c811c12dde71037500562ea0ebf2026b4808b845f84e2d2020b693bcd2598637ccf13a824db3626d242bc9d8d540271a72265e9d9876c7ddc58182c023dba500da6ebac6977cdff594dc4965097aa26901774da3cdaa1dcbd7b6b52d99112a99f000000000000000000000000000000000000000000000000000000000babf8dbfdb201bf903056b264b4f95f9004cf116d91f9345f3345eaaf0257f684f211dfe3b179cb04af1f9ed6465babefcd3233f255435e276755e286d6a4b5fe33e1a4bbd44b8b2c93661b2ce5866964f8cd2cb23768f59e0e25406e7c35ceda0b82e9d13194ece032bb957fe82559c6d89b36deecdbac9a52b8fee109bc644b746ae3dc230ad1c623eeb88e1d1833b3700b35c99dc7466b6877cae1e6b0a2979f28b4f9d3e6483a9c9b3a18c227798bea93efd6c9cf95ba0effa4faf9dfc213f8856b55d7eb7c72608c6b244621ea350cfaa01c2414b9678b77e0a9451127b63cb5fc862288bb844b8db8471b97380bf7c1aaa809f3552ba550a586fd66b26be432ca1e4f164e62ae3481502377ed31b0cb5d98052c24f9bc8ae49a873161f76c8784414a9ce487e8e69f8c0c2d4858552867d3ac64b6836b9d3a17f439718f1668f3063930382b598db4b275fe26a5697d0267f3d9d0b1e09a7371be7af6af8edc053d94de486840d3b7e22e79c1897b07dc6f35168e9a92ff07e544a5d7d2850be99e63a0cdb88f9f7daca9873f19701d003781460037628ebe09d771136cbc77a4c822d7b1b19d99d6507941d55a113aa60fe41541ee377445e9b233232d000000000000000000000000000000000000000000000000000000000cfd521400b0835175527d7a49000000000000000000000000000000000000000000000000000000008c55f71cf4d538093c313f44dc03719044bd4e227a18cf18d93cdc7ea20974ccc70f1037d23528dd50cad2894129ef893a62a96c7e83143288055ffca70277f7519deed5f0d925ea761a7be719c8eda1d35d4ca46a01e8a511fab67e180058e8ecf9f97a5b14972521c6e14ccef9b784a264b57dce5d3321ca4c5f417dc90559e3aea31a34c5e01261e9235614d8bf640d560586495ec6a5e3560e08373234717d44b14d1d17a7435400a9d82d26bbac519dd097e68fd1e62b1c82387c029396758950607cd43ccc0d67bf9752b99dfa87689942fc250399285818be8162ff120f7d410c6a01822f131c00e1b08f3a75d4bb0d3375ea78bed5eae296a20a72a56e1c1ab71857c85cd1c212492883e8f34959209c155cc9791711277fd392ba2d790dd766e3cb669cf6886aa2da75dae2c24edbc8bf0701bd208e5f8cda68901dd3d6801515f0af101b3005c935850606d014380a0927122442baaaa7021db4a1c7dd6e791c1b085001fb016228e037768c0f08d25b77b7143795abb8e80be5d3d3d12aa29d02456d291120ee9defe74c0a4738ace82b7e9bc3c37a5f4f7124b8e39775b0b83b6e47e623e387133ca355f52db30ad68a25f5f12d8eb5df9caf523c2aca59ad02cae6cd49e6c7823780c14ae56ef23c6c51c8aaa060f60adc3941e97088604f7af91101796ab38bd6bb481c8a4ca38c1f987355c2636591a8a295551b5c31b12fa682cd38ac13f5c04d67b61ec26100e53e2567ddb4b4ddd26189980a776d325d2b16c36ec5998af267823747eedf445492a6e3649f2c06ba0f270d9623f94538510ac54a0bd110be46788222357d6c0194dd75460b11e3b218a0160f4ba445c5649bea0bd65c6a85cee24937e4982167642ba2caf30aa92475a55bb8715957e1a986153569a5473aed2dd9a4d013374bf2bbe64a9cf003507abe599310d8a39a9423c89f043123462fb254c4a0d42fdca3ec712cfd966f948bcf1a7e49d8f46d66a88fa5e50f70960e456b077f88f2ee011f7c85c83dca4bc31a11d35736f2d07f6f3c4d6ff9acdc68cdc95a7f1ab69c40e8a798c780edf27fe7e1cad06c2c7f6e4bc5ad9b4cbdb47da45419b63a76ed4f107d7cc95956e6ae0633677a7b439877d5245635f4e0632d5eaaea1738262a98a5324cddc18d1b65d6a7b3d000c7c2ae907d2bd74090612024bc0a5a57b72252a196f1e77a32cc0b0cb27279534b5b90dc7b9bd3b70931a46c0aeb316ade6ad82a7cc88a91ddb56591e92e94976a261064b32722bb16f74f0e335fed3bdad50bffb94275fbe5966d5ed5025ee640cd549539b9a46d5e554dc99c994cb98f887533595ed95f40fbb7885254b2d27fe97c6756c34640c1a25725b3db799a270b0045c4545af52ecf5e5be50cb5fa8e611da245726e64a767b6a81a9da3073187e3c8c26d4081643d8e6568d5417fc2046ff8ac317d805c610b3137f08591aeae5452fc2a6cadd9c7cefb95901786fdd69dfb8a2fa9df5dade44c91bbda7d9dc60652ee8d9ccf611f72bfe2bf1a63fb1ec1105f3ac821f9100f9f26c1eba6260479648d261eda942020af70e5ccdd0187a3a71258e3ae599d5f2412f9d79f42eff7686a0ac6ce1ec5db43e83a1a3b37c13903470f88657e50bbfca4b789d2af610bb6f953b0947e1309581b4cdc80ad4b315411ada29248669d344b51b33f01749850172ef4fa38476666af61893b5635beb8e620dfd6bbf1b6c8d311f2e5a5b1691e2b72890aea7c7855338182d6c6e602abd54426f1f981babae8d5d08feb9422399cb2b451d364845f992ac3d69838f399b97d544346d98fe72f7f08328d38e854af402ec81e91c561bd062f5d21282a23110e47bd3af73a5237a750e722411e20ccbdc263c7a0bf39e9104592dfec629ae55852ee0bbfa739afadf79adb1a6e9bcdaeb5a5d8be5816ec6b2af6b1bf69cd5a74a8e203de40f44203a47680d8b8818393a749134ecb3cb9be883f13e7eaa81b1e949c16edd8d0bf53a8cac6ad7516acaa5f27d5e6a43587da16688e25c202673106c3b960b237c1c78ce7b4b98213333b77914dab2c174dc5856b7aa6ee1d42b06dcca012116b0c8e13d652e2ad030d6f1cec0fd6926b96aed81e96ceb43bed04611dc88279807ba111abf164c81273eb8546d27d3cec9844e652c791b76219c1ae5175e34812d2a0ac039289faab7f8388e3c1d0b2cf48c3b0735748427f9b74532406a2b5e2eee87847342b607994d2160a1fc9cd897d439a00f598bfdd10ee96c52eb97f28d11ca7cc2f23cae3663645c5e3d2268fe806cc67f27278dd99b714a5fc9c3f42423ccada1a0c92f55dac82975e5efc4017840074c3c3b2824c44acffc30f61c7e576432f4e318076719837bcc4cbe0ddb2e2cb53781674b04f62fbc4357a1c978b0ed54fc5bbc73981b2b9572bc82bba1c5a6c2527832729919b4e77d160d00fe00d6bec1db1022894af82f77e8dbd1c2cf744e6fdaaba9c4e4475e1cbf633861f800b4e2731cd08c8c9810ab2f205e7e4897b090431a40ffc246b9feb4c3db30277f3a37f4282b1038f8f1cb6e84755b59d9bacb22e649a56c96166a0cbd72698e7e2f2348a11e88d77c9a6c0b99e8e8ca7fb31e5fbcadb641b98dfa7ad9032fb85351549c4219355eb112ad37a40041e3cb52f83f9330edbe03a423c083f510af680425a0c9dcdf93ae6753a33b5446f7f1ff028a36c06a0e2b0310d45c8949810f77d356a67cb0676baa54f7b7973ca5f96926e81e7d6504cddbccff719d6ce3e6050264c25bc3d78bebd1dd9ba5958202cdf6f0953469357a19b1ac4e371dafcc0b6b60ba993ca7fbf8b85a342bbba015307be43c0766bed0fe5b2a24f38ef53ebdfae738a3f9b049a1226c1bc2fdfc45a9a48b7a5596e9d17d315df626c0e7f702f6f391033f2e2081fb4d7f30c5fe8e9d5d41b33661a6bdd9bb13ab0c953391e9552d638b38b9cab98b53ffda2ebcf648a4f8f82dfa81f8243e501320d5c3f5216ecacad8837ba6b23e1db21c8bb9dca41c51a93a29d05a5692bde298e8430996d4ef89239ea526a9395d38309ded67c6f1692757584ebdff6116977e82bdf69698aec3b7de080af9baae11e95eb6a8af80cbb587b8d05401b71c09e2fd94d0ebd26d87de8430bbbe011cfd24c632dee2428e13740785b2f628d5d2edf88b893e36886ac56abfcdbd0dba50bea6f41260c0ed55bc62153a28b33732140c7c9bae7fe5714e0137c1f7819bdbc918b9fa8db7094ab68a26c7fa302c66d9076948c9de16fec03f1560d217bfa08d977bd7c920782a1beeb143313",
"spend_index": [
0,
1,
1946888704,
4294967295
],
"result": [
"a968e612c0874ba3edecb15319b9c5655f1bab0396f581c8c6d036a681c44ec7",
"f8aad49ec5c23f6887ff71fae9c60b1fde351d9acba75e0dbb12929d20d2eec8",
"a2127631fe7b2c06edfe99ea1573ed54d73ecd214117dca3abd554e2745cbb8d",
"ecbe851e616c023747a2cff919fddc58d58d72cfcfd4073e89ed4916990fa69d"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 4,
"Witness": false,
"Version": 466173704,
"scriptSigs": false
},
"hex_tx": "083fc91b093e6908ac000000000000000000000000000000000000000000000000000000009dc406fc00bd1ed399a0e5564500000000000000000000000000000000000000000000000000000000f9025e3a00b51c5ebd1689e28c00000000000000000000000000000000000000000000000000000000687d327d00502897bc2442a3640000000000000000000000000000000000000000000000000000000020b3964a00cbf69cf982a67d4b000000000000000000000000000000000000000000000000000000003f37248100491e232e0b787ae100000000000000000000000000000000000000000000000000000000a697b480009ec707e1f6ddf5d50000000000000000000000000000000000000000000000000000000017a68c6a0015eaf38cb5920fec00000000000000000000000000000000000000000000000000000000274717c900b98d1d47f3ae766000000000000000000000000000000000000000000000000000000000351dc86700c92fdba504053204d7588ee516c8d7f27d7ada3183ab69b437bc1c247fe38b45960f2b79020616dff306e6d97a49ff6e26d50b2e03ea2d7d9e6fe6c1e39c3f481e3d205a48ad844ed0cfbbffcb6df49c399851be6b4c6fb2f78dae553159e76836efc3fcb3c0c0ee1a1c647e6c54adc34e5b85d18c84912ba431746d453480f1354a1e1466e25662a38c204521e8e5d9a56592ee2360be0d81d16b13988cf3cf7f6bef2aeb2f9cc875d66e93fddf9c2786064ed48cc60a572e5843c5da56ba190171bcc794a88dc36e0a8b9e69bbe31ef43b43aafde09b6a601986e0a871c83d02a483f8e2be208876186e745102161268f69e88df59884922690b08ebe8cdfb5984d79a8e0e7deb99599045d139bae8ed217161f0cc4c30cf5a26d5d2a75f5c3fa16b70cc9cce715d7e0c5a3980ca5f32696c4b6d2db4f5b78304c5449e0baa041b7719231ab9fef77c1829e52c6fcd227eda54e66babe849fc057aaf9dc406e9acd8842fdd1c25844970802d0d75e29bd0bc11dd9be6c1801b7771c888019845f32e83316cb172d211fd3a09d70810899f973c23ce067fde902eb00b84a7749e5d95a54294c3b729b574ce63356bc8882a71a728f7667beb7691f7f09f3683bd5033ead48116680c92208ffe9e3cf6e1893c628206a7eb58642def9e072ce1a557b15dd86960752f9c9573a1375cb16875556f8f43565493a334b5802f526b601e6bfbbff74d179060b879db6b90ba3d6a2bbca1aeabc85ded93a792ce3e3ae4ea8b6fc745c263b3a12e4c3caf135ea2a9c77587d72557132fc222343d6c4b1711f442463da69e9fde09050a77dbb6410a5e004ab8c8688a5832921c0bf10a6d4a186cc3dcd09c65d0c9a20fa81d3c364252a1457176ecfdae27dcb1dcc713c89ae4407c4501ee133b0bdb910ebb21a589b604e975e003f211d368e77e776025c8765db287e9d6d43dc622013f04712c29289d88973485d7f3188d86ba86326ff11dc11f2471646c883cdd4d84583f0b11b90603979bc4fae082776b51b0e4078d85e9cd8956bdc47352904da4dc55ce41a51e97b24f130f454b5be20099e8d2c7a10d5e98b568c4740ba129127e991c673507864109715733683ae996585f6bf3d8430ad85eddf50326f687b6d852274f8d7296f40812761f1c89ca8b38008457d0c794043c6bb6b8882f27",
"spend_index": [
0,
1,
514404503,
4294967295
],
"result": [
"2a5a5d8d2af0c04eeaf2d9e142ba09054cda8a241fe9528e36760fa8fc98ef83",
"dea1e91a4bdfc44486a6de284882c31ad06af8eec2f504297d418d97d21a2a71",
"601e9890eb3c45ce8b96634ad59aec943207e81da307268193391049bfa7e1e8",
"ada6d4157e399a0b9eb1572320ee47533c95432e06ab41bd074c029d40fff18e"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 10,
"Witness": false,
"Version": 233800700,
"scriptSigs": true
},
"hex_tx": "fc83ef0d04b7e52aaf000000000000000000000000000000000000000000000000000000004203eef760c2d9d5d95108bf9500964227dd7f892fdbe8f89de24ae5f582cb1b62e5a4c8e22e02e339634d17b7ee8edaad546eff10f9e4c2ec94adcace4be3429c3e23e5671aa48ab5219492079b5513ab33b5fb9c9983e86dc0a158f588e6fb5a001fa02f9d460ae28a1ba3210000000000000000000000000000000000000000000000000000000019a9fee7fd5801730248089cf34c385a872f5a1d7f3d7dfe9d63fb2ecf32996f18a2adb3d5a9788f1c1a870c52c0b15425951b365092dd6e471503cae974572c586e945120e380a7c9760ed66fa5ae3863b156e435cc73c5ff29c515640ea530fd4f5bd11ad91c8b69d66372f6328d67a1fbba2f643d80d289a01d55500a45f5fd60dee6febe6964b2e716693ce33f1e4661ab450fbdfc17d418d774299f7a9f6378983f3fdd525e873b2fa8a1776b7afbcd326f80e0e22b3805d7d2799fca6c95ff1a7c53df48f4d1108f4986b1e9f1306869f0f026bbf3b2c859e3d966641ea4e0a49bf2bfc05e9ad33b15e053c1ac151cb28f5138664d91581e55c9fc4c17b3851928b34e0eaa2b05c4a9cac136e02abd7ab514ccb474c89fb6789f809a2529be7ea9e500b38f50d668993113c57d60623182c3a2081ad6e359a415f865f5a65df2085ba8c8ec6c7a7297915372b3072eaf844d5a29ceceef72fe73e4cc82d3536078b4beda000000000000000000000000000000000000000000000000000000004efd6740fd4a01cdd04b07fc9793e79911a0e4fe2fc5ac2166d7a857124945025cdbb8ec5b0986c2258e1c28fc414c819f702d74d873595dcc2910dcf57fc7b27363776da98e60fb085196bbd9f67e2fc0c70cdef61aee0156d38143d57987d8bb2ced0934c8f6b070215eab36432c4cd05adee3c3c0e5cbb2eb90c50b7c6b277f995e22831484d0fb4a8497d86dabdc6cd7682c55f422e3958de0c0b64ab58c77c27efc5b0c4cbe1554f002586de4d3e35b21dfb02fb39058967579d7e780e19d591c73ab0a48b2e0d6b95f708a4b8857ea4a39fdeef37ac7bdde08642c5dbbc5cea1dc767a576b33b45c844cde2f55a064da242367bebc319117c43bc962e273babf68c98d14cbb4d512b7efdb6128a58c44c7114a9600acb792a129bb568d70ccf4ff3711e16bcd86e8b009011ca257bafa003c6c89ace435785a3243e3860cf626baab93bad428b686573b3b1732563a83701aa598868c0000000000000000000000000000000000000000000000000000000032317a0bfde401d7631ff85de0d890f36d4b7a1da07fa83d05354c9d44695b04e1732027e732c1998957a43049603ec3a3998a1c3764490a6115f53f6f001bf281ba504d8a4c826d17a1686ca2cfe7a488fdd8b85b5bafa48a932c5f11dfe03293ca59c47f742251ba60c5a44b8ee2f15e9b38121e4d90c8def01d1ceaa877e21e1547085212ab226af086eed854528618d0e19e6924d5e8970b5f7bf178e94c4cb63208d0c316946c56bb46b1ebe8f23f61bde981d661ede6c7fd5fa27f948baa7b279353035570c993920091cf6524d110d44dc94bda9caf2483d72ef3f570ce9bf39c65d605462c602061e4abede479083e0eb5aefef32ce7f5e9b83da0a11523a2a20908e482598ae22874b29fb2d4a17296f3c924a42d84893fcf2d626e949377d001aa2f0020e686ab764aa6589b303a87923e3c166db609a440bdc4eb5c762c596128e9cfde3ac55161236a001a9e4b583e8f3bf3d5675de869f721acb9f9a80741b1d28875323658ffbc2c14258c790af3c9c58f6e1d229200fd3bbd8cc0ed54270bd792ef797a08aa69e132bf2d3aa809614b6e1c086a812e84250c58fdc5e9120a1d780338716ba27ec941ea97c5d0b3fcfe030ed4385a2e070806dbfff1c32d8102c8feb9d65fdb23bb81cb1e5285b2ce322971d1e6d86bfbaeb95fb29a22e25475769276f6edd89aca0af57943925ef22541c86c9ebb6ebbb38ac2140948c3ce50c34a54d14843467a7d07b70cdec88ede17fd2fb146d65c9ae8cea0453850672616803e4bf80bd092199b4202f86b14a2a976dade99795b977d409897e0ca406427d37a45500c41208c08c4194587b5dc9f90e542e78c29eb4f6f8c283f7233685dc3a34394c01e8005b7b02c09b852066741347b42bc9a900ad970e4487b63c7710c7569025cb4d025a7327b00a926f02be4e4c30198656c510cd5219908f7bb6e2d84a33134fc66c7de2e5dc722b73e39480cfb3069ababe48461760b80ce298622c8477aa3c3d338fab24a3848594c14271ea483347a1afe30359b3c9ac1253dde5fa7012ebe3d169e04c85cae2dff4636628f4087e4e2f96f1dab62e7b0555a63d6c25e50c2d3c045865bdf76b1e7f730f3222d3ed3e50742d6180e2d73cfdfa8bcb7ed37336a4826e84cabfb61316e454255757dff3e4c35533b7f8abbb555c2728ab5edbc5472e362aef4920c0899271d1795e1490bc621e71c671301c44961e6eedcd5400a19122020e9093022cc01095419de6583c49de37d7fe720ab61d5b3f678e29419df8d2a13739e5e26428520c8a48ef7347a4ee8e49637a82ca3cc8f885c32303aed568d82849a8559e96e158b32bc6c2d74b0c66c73fba609684e3d01c5e1a161e9249bd9239d57e84ce27fb766b9787ec353d84039a7ff4040e8975c57572d6d382ba65ff6cc6c6432f1f924efdf63ae2903f959daced0af629f8c80ee4d61707eb4b3c030de99b6869c01fbb1e07bf7a5321b352f99d922eaac5cacddc0b789d245eef8eb7bf938368df405c558f7ac01fb01a78b72cd7cbf02bc85d60edf5769e1b653b81e69133499b915d0bc442da6ab8c1f8778148d9cf2da1ec862df77f2250aa707750bb606acad444d1173ef1eaf6a82f892c7026e0c0ea1a0d18f449c6cb6255b95a11ecddafe4ab15cd483399baf1150dc79b5f294e6eb8253fcebb293d21de6adccbd4950f8e6f12f3aca441efca113a7c59c1badbc8abecede2360edd1acc2fe2b2b862dc48ea4535e42f9fa64d1b3f27282d0b6815cb7e3cdb12d032bf562b039c499ef735f65dd82b58f8aa65007dcae541db4ddcc50f935b8f24eedfa5b208d13000ef9c6725a7f85c75cfb9a1d646b675f4bb171b7f446a24498ccd0dd2656dacc9f72e330c8e697b15d5c88c6effe101a8b7ec63352b86084f51c94f4b3dc4f58292e9ed61059e8bff5c8d3533627808edfd6a16f07436f131007b81b69024a78dee9b3adfbe56a016cad6e93829e205e7fe949a7cd8ec0a84f0d4f6482302b82f03592279d1900b31ec56908ebe11442eff5c4f6a2986910273898f433e2856843a5598126576166aa0edd4e38a5d074dd2d039e349cb4b17a498ddac2da07248c24bec883ff17e9988ee69556425ef25537d06b7c7360e983ca381eb6d55328a2ea969875d5fad6c2bd2593d4e9ec42a51fc4ef43c818702c82d7af73a492dbf992760d2fffde226ae9a65f14019c6d451ea62adad3e8e1db773a901ecc1fcb8c376c0b899dfe802315228ad19dd6749ea0d1b57bcd7662616ba9b99e822225bbdaf0d8a501afb3151c9dad127d1b6b474e1b4b4c0a967e067905518603124dab7b59db38d8a3876e24ab5bdb987b575e9a986652c1c7c71b684359a84a48332479706fa34582d1e5388763ac1e5a9e9962797083827a545cd82a9ad1a4f01436825ba24c198e88c1c3ecf7861919908f29d0cf0989af3d11d5c42122edffc91234adbb830ec89b4a5db9df532fb94d768ff597b3bbecc5bd78a709617e6ed71a26784894d751d1232a851e84b5dc943916e4733a303386d669f6b3f57934044aa5cafefc3a36f0fbf360653eb2fd5bb600da9c5f06947acfc48b98cc79053d3708436dbf47b5f3dc77be78230387c81e41095762a9cc3c53ea44c3a49516886dfb8a41050e4be03b31385cf4b51af20e8083edeb6092b2969a8a9e974fd14c93d025c77a1caaec8562a1bd1bb44dbf21286da4e8c97a93f575ce407d0a268a31c52e7f6d98934195c827fd4c91d798a2f50ef12b7b6ac88c01f752c889e795921bf829b38d1607ce1a84e978f5f4d39ace0ee956dfe86f6cacd46ddad231d4cdd81d8cc097f001de7008605950f862a888f32bde2bea7adb920ab999fa927b04e8d592efcdc11ec62e3a7a7f99ba26695a1a2e8f794b9fd5e21540d1e3ec03cd8efd4d5337caee3a71d12d28d2bd4e791cb7ac7fa84bb211ca999d991f47b2a2db39f614333f74ec0183d42be2b31131c5ae835f2920968548e2834d88f58e013687c2ec4bf5ddf0a1ca1d8ef2f4073ed281aacde9e16ce649b793bd0f9eaec438abd3e7f7c935c8a44d220ce46cd5ddc6d8af38d400c9431fa5028e80fae7e962361082922cdfb2b276f88fe61783e1b9da26edfc65a3839483186b8725f78f515cb3ddd86db8b79983aadc5e9e8ab689c240431cf1e9453298c66964ba0e32e12754dc109e4c2fc8dccabba837a4b6fd00182a17e615f9eaee345faf7a99d981b4ad04b22e62bd5a5268cc1ab37ad1b56402defd4d13cd65c33c7cfe0c9382cfa22504cd3d789da2f45ac68037af47954d5fdeb33983b7c14ead5dd99d6764da22c7f22e119998b58593f4c15d73acb636b27d56992845c868d1b46402c1983083d6278ff19f8503383ab0cd7071da63a4851020f74efae494f346d7acc626b4e097997661d24ebdddb17176b723f3c311486f86bf9e67ff524837be585a48d009bccfedd923255b44e2c66305d7b0db3113b830105d4231cd357dbbc3dfae5eced32e95cbf95a85e967214285eb1e4175b51d92348fa5767b053611bcfa84fdacbff4d6206e12c2b361749aa5c41944b2946d90c02f3cf463474c365ca4eea67f342e08b84240db736f08807b11ccd4d76670a60337932ef31bd5d28fc711332d46b983",
"spend_index": [
0,
1,
1012000868,
4294967295
],
"result": [
"fdc72b5aabe68203dd0dbaf37a1ff78c3362791bf9527ba8de717f493e233baa",
"1c7402a155fb9201e164dece687fde25a6b03f39133cf72c1b6c3a912f357baa",
"42c0622a740320dff800c460722a13359a020425d4a7f1ffc0f6675026b22334",
"ff35ef313d52de732a2678aff944f787a5d3f018cdb12115c19fb28578da9d2d"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 8,
"Witness": false,
"Version": 1064018199,
"scriptSigs": false
},
"hex_tx": "17a16b3f0ab40e831d0000000000000000000000000000000000000000000000000000000044bdb289008d1755433928a3a400000000000000000000000000000000000000000000000000000000d30c788a00cddbfaf7cdef7b6800000000000000000000000000000000000000000000000000000000460e6b8600291cc340112862b900000000000000000000000000000000000000000000000000000000fa10e4d900b9ce1c6bd05fa09d00000000000000000000000000000000000000000000000000000000dbeabe9200461f00e8967ebf7c00000000000000000000000000000000000000000000000000000000f4295fce0006df8f31488df2b500000000000000000000000000000000000000000000000000000000f0c4c7ae005cfca7cc9a71195a0000000000000000000000000000000000000000000000000000000048f9d0ba0035b65c06a0712f9b00000000000000000000000000000000000000000000000000000000cf7dff6500d925d393cd2036cc000000000000000000000000000000000000000000000000000000001e389110003de7c87f08011311cd86f0277ac857453c60d9dd63b5e7f0ae592aeef838bfed1bef937defd8b275adc462e498ed93153cae785c7c015be5a7f09f209e842132640e471f23547ad76eb5c6fa4e506f119f9929ed3427358d90d88c8e92ed0afd8cb9297c705bfc0fb7191d6160819f3ecd86833eaa4325a8db1cbf33fd36bc8ff922be21c123850c5e521b00203e69064a4634a5b448d012ad88c37fd30312c75c75bb6f8072ad9a6fa2c490d44a09e083c5c33ba352ae92a7f25fd9de3954fb267875b6121cdb5d0f8019387875f6a044bf95994b6c372a5f8824b1c426c84f9e3745c5410180f79cdc820f19470cfde0e6a5d7c4dacdb58ba5c9f8d7ee2fc85db3bf3d580fb0179e0bb7c45b21c29809cf13c21cad38fe27f49593f3b110ceab98da43c4c451258d81cdc998cb157262d3ac3d9f6d6d15a86e6373aab439be2d83961d1fc0cc1e7870f5833b05ae4b1e557399c408adedd0fbf60287efde883f67f64a3c7bd7e24943be1123ba52f55577c140783b1a20f774b5f099cc6b53ee63449e95dfed4f51a281e20f6e7efde38ac79ba32684727d3f7b219044cc17b0517b2622098c6144652e2960880fc84b700c55d4503ad6d4a481a0fcda1fbc1e90123da7ac4a0430f349ff5afd4c2ee2ef713b451f701b80f77b98d61dc697237612f0982770c49d69682e1eb009ea26ea561d47f51321e346d53e06da65aeda464ee98d27a769bc92afe93d49892f3e7abea82b459b7339eab64a7beb08c44854c309a768d896ecb0e797551dbc6d21c70b488017b9826fa06e681d0e04d67f85ceed3fc406b252b5f74896b25ab6fc67224a6e9768155beac50d97b66f13d4cb47a45fea4dc299f5d0282a2080fabcb8cdef66f4a10767ddd274d63cda14c8db3ad697bd2a43590bdae80fd469518a61abbc73450be68855ab442f2a2b15690f682bf7b1c8489f34cafbf7be712b8b05b495eb1d1c0f6b73ac2e954b639e9334fdac360a7987f4ea1dce69b234f22398f3f0caa9dc7c831348aa5641c8ce7133e2648d0a3b52c03599454d01fc58140dc536809a883f63293390faf3a4587f72202866e0f4e8acf47f4bc4c6eb424a526a9adcd36b4541171209a9f69f30274f2ca27cc7494719dab7070ab4df23c3175783a18013b9d69c811edacb2f4eab5e1f118cff0bb2f76658dca537725b3bc8f240a320e32d496811ad9a68e3224fb58d7d3e4135045aeea58d49a6bcc6b95676a09459242da680c4caf017b7d2415708a141d64253f50234207205712c117c67b8221d2aeadaa3a62104de2b31632b82cc1decb5e69e16c5c942b57cbb999c354eefb6f09fbccd59ea85ebf83d48eb06d5ec7ef4e07a80c976f953703d4a57ae1e8dd20ea6dad831d21ea5add18aa169f66a886b200b252ca5991d3d25c56d17b6f1558c3450d6e3e758843a2976156813d4d896a80bd13187e20047108a60b8e349c3b649d51e2dc0b9309f8ddc57c8fb590c74e1ecff4ef21b8b8878c155672b1884a07fcf96fa4a2818156b6d006816221bdd869ad734942935b10dbc6c5445f6b1948f914ffb0a55861a993bee37f615f80654d5514d1540ea30918fb1ede5f37cfb3a38201f5cefb3082e3fc80d99004077da7a9bd7a4ae5f2bafafcde71ce910df384cb6b6013ad9ea302adbef6147e0f380b71274b33e76016276ebd61df07c1c296cc71bcd425d3286beeb0bbc2dfe5c1031a0e5700bd29016a3303a048b012c4d8a1a11fb3bec23518699c7d47858164af9bb581fd3a0360e5ad16dc8cddabd6aa5e7ccd0260ff50cf04646222b08c853ff8fd4582e83918d665cae48a924f947d02562da8a00f2f19b1da5c1c6699b6c92ed7615e81357a12b1b66f290c4b82001916fe4b4a53a1308803357258c4a4c4e3cd8a9125a87f3acd4cda0c67b99851daff19108f1ee8939e981c6bf0f8639d8e1a51645405e78b8d07d4396a4914e8b2f0715520559bd74911a8f16cc77d46b17e82b3d6e29ab4a87bc9c0b71ed69609e745dab8a6b851e5a183c16c301d631f02bb44d2ddb08c182611b2b338bc38c09e4986d9a69fb08010810c82d5ccb737cb4fe8177a00930c4eaed5d0e937129b7908064bcb5abe64333eed5ed5d2891005d58de559d2e8626768a84234b296f2a5a3fd8c8abed1983c1b8c184a98ea23f7a5729beb24d1410090755afff465d78e17f542e0fc19a36344bad169ee18e7cb200ed08f1abed035b1284af52fe1f25350af3fc0427a7b266ac5e58f83d1570016f74db68413e12571fac80adb5f50283066a509bf27fc7ee459184a95c6441bc005bf320deed8946251a8a82683278c14798ff3d9b2521187e104adb1d520ae90b38f8399e5e",
"spend_index": [
0,
1,
3173180552,
4294967295
],
"result": [
"3771f95a8979cebe0d1f1b6eec2f54226d2a432ad54d975bd71befb47810a34c",
"5bf8f06db72fc5eb93e55cf6725d504aac10a24e5cd3dc9370654758e9210756",
"19462d64e577214d14f1550e312db8f57feabc5fdc850d51585e7405b03d3692",
"e6e719ed457021afc2de1271af2a1be2461627d047d0948e2f7f47d694e92999"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 6,
"Witness": false,
"Version": 563167293,
"scriptSigs": true
},
"hex_tx": "3d40912104388256aa0000000000000000000000000000000000000000000000000000000065971d1afd0901d31e2e46c0a53e7534c44895bfb8ccbd34eda968f1efec0770c1fc4b0abdfa0c79d6f7d74c05842a6061826a1926c5525ba7f89da09f8fdda8466582b81f203e39ca696f1ac39008427ed21d407b95714ac65c1abe7cfc6903916c42a0a0e8274baa6084a8e317d4df7ce2443a85e5a13722547021eda174b0b3142dcc50fd489bc16fd186334f893ffb16d1088bbb80248afe97202d455f9bb4fd7409ee677f9a5506c2217392b62a2b419099dfdea1b0abb6c9c179d6698ab6ee3f233958b511c220bbbd70c51c2800f2e7ac473ba9cfa5c91c979e1b619dcfcf4b9fd8b1a4f9742e5cfd90ea357781a68193f1124405faeac1490136644536c6dea31869b12889cdb240434b12d994798581ddc3cd550000000000000000000000000000000000000000000000000000000042c08f8bfd7101d3c5ba9fcf3d95716ba18eecdfb54561471505c26ac9d6c3d72e97f8deed33a5383e7662f8da2f812f802a6931a01368048ed1a518ebb4dbb8c3ae0dde3d00279bbb9edc3199eb94495306d0cf67caedca41958fd89e65c90ba8880cc5351f2e966fd8e6682b9005d99cd193b8fb32f39b0ef689699566da3eff816307574949387abfd7d4da1749fa7afd7145f054c34cfb45c59cc618f947650450111f25fd31bc800233bbda6e7d7cf7577192f0f4d6d7f78c771e6fb1a9e84b3d3e9ab60ce8289515f8a149469ca67d8f2c10cc9968c72b203fbb6cc239d945f5820a21f62ebf419f7c49d3bb79b3d51feed9dc4a3ed93fbe75438a7e282cae27b40fd3a04d4fbe5566349f2e3ba757c4e9bf9e9dbacc2fd6e32bf7f53410714b660965d197c6f091251385a71321f949d2296193eb186aa23587c00ea43cab68a5def1c58cf6bf08e34fe4db6d69cb0a8ca400b2fac82194907d2a09f78796bed876256b74a8c0f253db856de71d10ffaebd7b037dc5b67b2ee0b3434900000000000000000000000000000000000000000000000000000000db0adbddfd91016851b0c4df06980c4e9ebd072d00019865043f6bdf595c8f8dd2f15d78025c7f6d8eb5fdaaff7c3b83e2411f851be671bbd8e3420d367be250c41da4a58ef721db4116381fd725d68bd560c71d146ca59211c2331885c7294ff7c829ff2b00942b2eadf80170854e68be35c5cc921724f68a6ee96c306c68f9b9920c1e68e23901f5e5c170ec871e8132006d762f1a6130ba934ed18f27be027d34761ee5c7686cef5597870d9b652d4711c155d1aaad9bb7cb9d5e0b16eadf6e19af1cd5539efb13a222753da6df0a9860bfe3e42c8dd8f791cee12fd1b3483391afffca1d0d9722975369efccef028480adbfae107df62d18a92e33ce65e68d8d0ac212259755a13409662ed350c6314780348527a3189aeeacf1ef3bf0af72a23e9937fb8945df0514897e131ae1bcbf30113c3d5c657e2c80a3c666e36f730c68ee89c58de8f0ddfff4bce478d4b8bf9d92fa9797f0431d8df0221d6daf47c90e998c0761718a44a4c11f4bd85e6a860c323203391fb78b2002b4efc56fee4380d176df834e935a32bc75c5f74d8e4da1ce671e3fbfce1f3a306469d9b00000000000000000000000000000000000000000000000000000000024ef503159da57602a43f3d2d9001532c98ec774edce6374436d95e3adbcf7c7eb75f17fd05599270f4cc01a0674e1cedd6c19a8bb079bc927c16dbf3c2264b6def9d86f0857d4e23d190ab958fcfd26e518904863dc91085ff0fde8beb21680de4f0602805a85d3620c00c8bfe332e6b2feac297f46400d5780a1a2d46be232f49f4a366db1861bc87400259795faec7db3d6b499b2b3a60d8f637716d21ee5b267e9de47deaaccc913cf7444a111548e4f7ca7bbb9eb58c43395dbc70332fc3affe5fc1031ceff43468411f20bc3981fec2b5f0ba7ac6c269aa004a0952609dccd00b63e7701a4daa60b06452d2bda5a8449eaa5fa9a188643c75a40dd55682912d88c4d61729b578a1a26454f252982490b7199d00a6a0c5b5c48a0852e7c3415b572049683dbb57ba527eb141e5b09b766ecc40fde226055bb0cc8ce43ce3b423332ea000e610239d70d88b76ca43877297f5435bf505940e3d623c242b1e1961489efe107646a8c7e0ce837eb4581dbc7fbd9a56099181ad82b8d8290b9d18154dc34a3806302d9adad751938990aeb2818b20fad15016ace06919a9adcf24e45f37f3e94a8fc209a6c9f07d932bae5d1db804a06b06a004c7db146e9f55b2fdbeae59e6e84f844e15560f376dc956369d15c6c11bd3c720b9eaefc5f5e61950db33fc732b0a1941c9e524715638f2183d49fde432d7f2df082b5ddcd7a4acde97d06d5dbf43b82f2d326c85d81f49b1aa39f3889cec29490433541ab03f0e8e23a04d2affda88df42fe602e40e5064c27af0edc2488e4a7f4623e664dc3730af3776247b975e98868b494f865c482c879dba23861deefe7a0c2a4769072cabf7340aef83a3f1f9ade46bae0f00c0cbaccccfd601e17d9c7bd678582af88020b799c04053181c33093f61fb8927b6e032b0383a61a9d1fbbf585301b0eb8ebbb7ee96606842d866d393eef4b0eb066e47814e277cf1c4e3bd10c608515b15f5501d32badaf9ace6285ee6652fef608bbcccbff61a55b15b2ac6413bc8ef7232cf413326da9ce54e4e4e605d12f025fbc5eb1d6a8694721d18431f3ad5e67fe1aaebd39cd51275b68f4a42bdb6d7c323690c32eda3682e583b7b542c41694cc4a8a0de5272c81c09152de7790ed01e3809ea25807f296db08219773e5ecff9967208f79353dd52b2af31eda542d095c189b843118cbbc5c9e990866aa5aa406c8ac573148557cf384fe950fa9dc3db0314dccd1e9a07ab01088bc32af3010b335f0f2c466710837f9109b13f23f4da88981109b629a66e954025bde287daedc656726f08b5d2c71cca97549555c895d265117203812a7cd687c53056ba25f924a4bd3b0970162b9470f33c5c2912e0f178abd5609bfc898eda5f73d54ec474e4152b205c8cb5db43a63790fad88d76c3f1b28d41ad9b80dde740cde498d4e7fb13d7794c2491f524b186d7265873a016fb6ef7911c1b665b3cdb8f28037ace8e1dd55e50f601231249bc7d663dca77fb711084da39cb57076a3baeea27c67a418c49d1a87853eb20bfb934a71ac66b6e3bc98cf781519bdf8bf1714113edf5cb6108914765202004744a3b0832d37549ee983f4f7e8bf0602f405524a046c80b93f3f4f121310100227d653f48e72cb6ae007fbfec63235432a543bc98f7592210eba0f8f6c80e1757460727660fc7cd9f6339381189bdae7e511f9b3e7b14c46562a2c6553aac2b59d6faa4c4e2e9627c28f42f2f914be9a71f7880e4229be7d259a0047bd33f6276915be97d0d84c1bade71e32a368a0048f405990fcf8362a4576f50d3d387d8d0a3914f91fe80c2534b9dca75eea410643c5dd660a29acb0759b0fa77e7587d65ede0d6aa9993cddfc8b8fc0e30aec481457cb5f412b04f3445b0b275e0ab96a8d590",
"spend_index": [
0,
1,
3730060837,
4294967295
],
"result": [
"24e96b4a4e3f89c2bb481a551862da16c22c5f6c438ad890c0165e3e07d74fe0",
"7a8618b8e1b73c23865ab6852d76b972cd89cd6d917d1282c0a158c7078866f6",
"6aad6da206cfd5fec432e5a6c3f90fe4696497c1c74d9921be54592795aed984",
"969a11f68b297b12bf6a4d26829f9360da3081ba2c1ff5e2c142d1d1c5a180d1"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 7,
"Witness": false,
"Version": 846211581,
"scriptSigs": false
},
"hex_tx": "fd297032059d8f2e4a000000000000000000000000000000000000000000000000000000006ad4927900724e9113e1539ec400000000000000000000000000000000000000000000000000000000affd749a006c86c97cac51bd0400000000000000000000000000000000000000000000000000000000a95230250073aee47e2c2c13d4000000000000000000000000000000000000000000000000000000000cb58c5600b5a792b6d0ae8af7000000000000000000000000000000000000000000000000000000003fa6d19f00f0f1b7f707e7783686e4dfbd51c8fe857be958399ded2f893d90665a96953c95cb37d0d6ca11d5338967f9ea564774258038ca5132d0157c1b4088a4b6bb4b1bf46d644304ec66c9c6a19081bbbf428aa322c0baaf9f98dcf29a922a2f7ee41187112b587b433975c77d87d88fcc0be07dd76e6f14032e78432e7cec4ed15a77ccf3fd575d1fa216c16c278dfb49cd45cbddc73a8a9833528844e834d7a8c9f44be368c481aea78a6c4a32c950960ffdbf4e14e43d3769bb28b5e9809229561e8c0201dc8e5d27574565e628911aa81221755bb7d470b1c6d0bd185f862bc846ea1cbd42f30cb2599c50c38ab47266dcd373b4233f9fadb5afe00b3ea9d22cf2b4431d0bec7a5686aa8b4bf2a01ae8f8e7b91221f69c9d88237926274dab45b0fb2cfc7245d8cec4b8324c38f7e50f9f93eb5bcebf24d54a2ba10e3c88d64a889d7ef4e0fd4a55fecf3d8eb2dbf582c1275d0f9cc2cc3f1ba6bdbb33fe2e2ce8478614477363b2b5f7229fedafd3ff9d13ffe353cf49f12284d77e8a6943cabbf7ec295976312b7ba26b96c23f6aa4f615760a61e471ceb1690e54b30592fd63e84ad21c71e92fa8d2f9d541f40724c8daed51f21a7eea2568c7b3774e8f6cbe9ae1d65ba0cb826ec9c235c1839bc2fec4ffeeaaceeaa0712046d04214a5456421e99a2eb10b18bef429997085f3fd674610dfc9419551191f003e96125299aa486ce35448d2df6e9aecde943f740cd4fbe2b1503d41a2a1233055f64f1ae44c9a0cd07b3871e72eb80e7e5541ddf87f85713891fc37f27077d383d68815c7a628e05ca92129e856f3e1493b9dd49c4ff0b4ff42d81791064b1093ec7a6704bf7da9aacd5822ad1db5d3691c8ee2b46718fdcb111286f5c273e136ef6db90601c8b349d7c33632ae5537af353a80a359ab89cf1678c05b28a702e374b18f7ae18bd971e8776fecc319986a42a95a39366a5add38c31ab5369b6f9c2c2b9947af297a229c21c5ca69a83283c5964656ee143c575e3b88915fbb3d8350a8f6471ddf2d0d4e26f3a4bb251c679a26a764a68e2de0404569e316d663a04283ffffbcefc3487f2ec84ea96fb0ba8a80f96a48ce4d8d42d1f44e3ca4664afb94cffb0e518f691171fd4bea22c006ede1c9ab558b023474ec51352bdec18b1767c031687dbbb0e9ef59ba9edb00b249a06e20ca17c8543b6394e1e20ed1078bf9df0c1f98a032de907a3fee041093a1b7d1824a97269734cb907806c1d3d45ba44c9770af78c118258ca24e5d36c1e6a39f4496fac8f0ee866ea8a3b513b3ac5fae0444044c02374795293d50663cb7bb01855b82636271803331077738d6983344b4a13b95afce8510a709df3721599fbadba71d8fa1562ca72689e64828c305efa2dd4d57523fe6d46a0443fddf11237a222d0eddef737c2c59f27dc6b1092bad424d493c3c57a5314ce22f11f555b96967442556bc30769a9ff4ed430313f99a8e1a6a31c8a4852731d6be398e9c42dd8537e56aadcf961cf6668a5b123234f53bf6afe930b9d1461a312460b43f713dd7fc9b136c531c94e06f878314e7f0c0ca444a4e911cd6b9f4fd949c27226d7d8e3441e5f15996c437fc7fade96ee41c64ec0f8bfef471e4df5f734c66c00c7c78506bcc1c292968297f13ad096d90d9f2b4c3b26a2c414810dffef179a98415aad4a48bcfd130d8f46d23cff68a04e585a67fb0a38a7b71924a2b74e0f132d7365abe6b8b0426cefeca897d7979405b97ccf843530fafc3204459855c5c1cc655aa630f37c8adeab4711ee9fdafd851aad34c4ca3afe979dba3f2a7b0c38028683683d5021ef8066314c33251e1fa4399b33693b822a9810b73cf87d877575e4a09148c23dd63c34bfaf2c47af6133d0da81f88a8e98b85abcc00106fc3ef5b7321c7a91163c73d108fc7f149de4dee0b608890cedffa091c76ccb5497b6ce70615a12fef85ba29754b8d23a50624c00d11c9a128b19dda89c88f669e46f69dce3471c8c018b224858a563771acb6cd9e01ea94d9846f62807758da50fcb345c8dd486e9a3716633824b8139fa8f28e63ca",
"spend_index": [
0,
1,
131671016,
4294967295
],
"result": [
"426d67aa0b10f1989589c3dd19384a15d02bf6c359eacdab6a5d86b4ccafd4ed",
"fe8428c7b9169065fae17bafeed4219d571e91379a51fd8a415db0b875934a26",
"788e97595eae8dbc90753d7b2b36f2bb200f359fce4f30691c8990100e0ff215",
"c23036b78b162b2dbcc5f598a6ec0f5d17f154101a940f6d503635d2e0c0f39a"
]
},
{
"desc": {
"Inputs": 8,
"Outputs": 10,
"Witness": false,
"Version": -1574382780,
"scriptSigs": true
},
"hex_tx": "44d328a2081b94443300000000000000000000000000000000000000000000000000000000a886751464f9f38e242c62b656610a1f82319272a176345cd2a998a58370215229be9127c7738443708ee88324a59b15e0205aec039f5390c8d78242dcede6748609a6eb7ae09a75936050b1e6ed0733b04aeb4bbf84485b966d192f5eb19b774afa63158934da28bee5be376e5524d3e40000000000000000000000000000000000000000000000000000000097b8e2600011ffa1143fed34b000000000000000000000000000000000000000000000000000000000680196edfd3801442fa9ce30ee6eabb973b35ec0c9841fc00d64cf688b14c4b7817de9b3b32a90f59a8b5c7656de2ac7e9e625eaff5099488fa9451bae856e1d582d8abcebd400b34c8f236306930cb5c02150a39a028dcbff4fb0ab95a58b8911da783b7278f3efb0c799a18075d61bcfdf9eb32420451d8251cd4bd9678993994649f58b3254b45adb9733ab37cb2b3a0c1a008aa4c38c583cfccec7fa8fc4b83fc28ab055f119f0de6f46946b9f5d2a6eee8dfb4a4cd4e031bebc30a8bc8b3308740955ffc939ac41dffa12d385736e75503abb6b3c280e6cc625f5bebeb7bf2ac66ca18c84d3dd12adb02a5537e94827a6e38f49ab0e4874601c098c89d40a59704d192716ccc244592fa4563c9d7db718de830e0e4df313d06257cd34e0ee02f4b3f7a6b60e39eaa35e76c8484c36bf323e3b628e2b66188569d9414c2e1633d23c83f3700000000000000000000000000000000000000000000000000000000037fc715a00c349adb6ecb8c9280000000000000000000000000000000000000000000000000000000088c15f4f009a3ed5e5fd37193c00000000000000000000000000000000000000000000000000000000b4a019c1fd3401ea4bcaa791a17606d3faae9e9a73e56f016fa9ada279cfba50e41b15b08d9d76d494a21b59c99a03ed56a240bbc0deb9ddecda8cb1a54d3b12b3602a60f00fdd69057d7d23e89fd451c3eb1985539665d46818c24612fdd8a524a5307b3fc7f4348c4a422a428200ae9d1b2763e054d14954653d17bfd9e94924c91ac732aab35081b1cd03d68803b10f2b26b805ce5141291f2e836651e49f5d60925e4b61cb54cc7fdb857cea50a0a089a1632cb13a2b07fd16c490150e71b59677f8ac627afbeeacc5072685257458a682a4804e8bbc7b3fc8482ba4ba33cb12b7bc2d54e3bbff7bbb8ac6d7155791520a4ff2754df67521b1905a8af5ea0a779dc7f9d1dd65a6a0cfb4df5fee1829f08e3b125ec2527a923339e3e16b693c1b69b32517b6641505d223b2d738ede86fa5a60258e8ec2fb96eadbf11983890373d00000000000000000000000000000000000000000000000000000000f8283babfdee017b298c98616741fb4b87e68170dfd1dc28eb90035346497219c02896a25e1489ca35e164b1626d28960f88f7d2589f086f3f43fea33ddbe0462cdd5a94f35c2f8d083fa67f4bdc23395ef4f7b46ccdd5299781503240707e0c630529e2f794ca19292ff002dd35271adf84251a94fd399cffc0b99d4e63a904d3c8f5783ed87e2aa2a77648da6ffceb55a2b20e2f2df1f49f5b6930a73c5c2360d01c7ddf1b69a2b800abfb9a8550ecfef567146e5c14477189e87e7d4147afc52cf5daefb5f3771adfb57853e560adaa2f9ad65eef299ec873a32985de4181587bbfecd50f72f335738f7ca54eebeac8e148fe5bf238be288ebb548efd15e06722f5a8236113103619c100e45142c6e0677ded1ee0b3cf47a58735e38b8ad9d2cab7ab46444b529eb93ded2b15f9c0e1e0dafe27fc78f8f298d1972d955596992cb9e04f1471b7e9c8bcdd4c3a6a03891ecedf09ca3cc0d3268275205c3581b3eceb46a0a1d75504b7248b9259b55172865451b506decc4e8167ac83cf1cd60ace255aa7c1cd392b07209a8dfc5ae296c33a631a1ebca89d0a1142f5634505d33365d646a9a02c25946f3c08a1cf1edf7a51bb7cdb212f14b96287a8fd3a32450be5aac788aaa5bddce1954acda404d6cf92b080811feedea53baf9c31724466c8ac66b3f9d066cb128bc9974e94135a2220942e6c8bb05734f8e40a00000000000000000000000000000000000000000000000000000000e939c9f200f34e11770a159c56ae33e4d155c8d9121a9088c37c866f585b375f63d91083287016d5747217a0dcbd3080d36d7405f475a933a7e021381f95837103207c98f7b3b80e33971c6d84b489a51d842bc38d930f1865ae1e9282f1edabd7d8e4a4f3626255380114f3efa6c5fcc031be7d0c82cd04cc952a9817eb7fd36bf5ed76ed16533371e97ccd869c79eb547eb2ef4f62802eabbf560fd4a96a99d93a745077b5549fa3f55b1aa9a9495fc38f113f5bb897ee969dd7853b3d063287eb3e3470e2c87a29fed0fb76a4f97ffa1bcd3bbb2e32a82608c607bb5fbe619f6667c8e84727aa6542b8c89b932991f22592fd0fb95fbcb6985998be7b4a2a2961c9a37dfecf69b63444716cad444d17475b1b1de727f0757ce053f24113725ff4f451fb74e8e2c3e2ec02bf0e1bdfbdb62fa864a0f9986da097f06cc1f2ad0d875a0fe71cb1767e395600a1bab80b9f9b7a827993c6a9e8eb6501b441b6f20fb45e8725df5fba3946024cfeda5e7276438135aea3da7ceb78a7be58e7d9b37d2f36d5a9a8cc31807d74f56d6f8911e255ec2623b1bbe615831cc64695d4d16d8413b778be4baee7019b79ee3404b8d1489657c8c7da55e55c71f99040fb0af185bd9679e4ac1c846983b954b5f3bd83655f281a13dfbe9ce548bde41227633c433af464c98864deef1caf123e1ed85808c001acf0441f8473cd7b97798fcc7add646a350a06ae7c7af6c9a60872371273206d2dc4522d545c92a36969b4f19f91ab3bd87bf754f3a9335875c8777a16d83138f2dc1c8f6823af1e080d7d164eb7369fbc7646cce618f41d8da6eb3b5332e8a9310a152a64e4ece54d6d48fda989f84adc261b307f09e2b981c06e9a7f8a11761f7263bf55c729387ca1fb70bb5aa73e59c8e2614a5b408e48cc3bc346ef3f1ba49b1a7dd630738083c44ad54e08675d6e6f3587b8561fa42877f3e8790e16fe88a54ed69ce6d3599f577bf89c371828dff961250bb585fcdb521a43cbe45eabad3cb17046fb7ab209f17dcd519e22f093d915fcad8b85aee4b774a1895bf6a910dd9e1dc56fd8a075ba89f0aa752bca314a12a9b5dd8885b8dce3d4cad86ca14044a926648af953b273b9e1fa9b85f0795eb4cacba1231c9ebfde1fe89064adcbba3dfb294696ac1c964ea008758dbad14768b6d582307354afac871599b075e457c8e80f67ec373c1dd2ee83a44f42eae8e52c7b2cc37fdd4779bf8d4e859e637dd1dc42a9418db9255d19a494d8afbb481aaccd8b424afccb4701ae74384db73f9bd595924abd0a090cd2360563dee0adddc312249540f7843dcc89f6d210c3a1ea9d5d4ee111c04a01bcd96d232078a7535d62a517302a3a6c3b792ebd84cc2defa7649c9118a37eb69273ea11a3f180525aa5f035f9133f616e8f70c49baeaec8ce5aeb613d58ed8a9894e42b3f87b00f386035229a16a0e90b479dfbd69123b3575b9976d96f04279cb272272d37bd67c8336ed74ac5f0abd2cf9dc437311315b1264936454dd1aa60dc5f3a00d91b75124f90962835e8fb88a19f4089fbb593579024d0c6530ce0a3b07c0367fdf9ebabb228d66a27b6e28dd091690045200b230b7ae83b5941140cb56db28f5fd7a97cd4c34720543a093ce486794bd8ac80608e0c18eb7b6a7535e1e6bd601cd4bc258519b8c30b6c2fd70cecdf105e395e79961ed8fd39d2ecae4e10c1fab97fb8c471ffea6e5cf4006a0bae56266261061d692fbe2c3bc19a4ff3dfc51019f6cd4bf167eb79e182c6a8e3fca40e22b8b02ec8ea0ac6ad75e9db6f90da6de1e2f4dd334a46a0d71e7c5cff5bc7618eda63792330c5ce4a5bb7aa2896400936f29ebac089d4644b98d60f68c7684af6f9605deab295db64956af1e005ca3199a5a8041d15636315a8811a18f3095fc95e4a95c61584bcd466ad77ae40f2eb0896435cbc91eb5ddc739f0d15ada9d0b46b066b55de82a9c3188c5ad66933f86178fb512c18c2805b8721a0c6dbf2e79854d076dde7f54430078cae232fac81c24648a23ce29358628a76cf26d58ed796f0f3c7d0cc5a67768521e20b881633103ec45c52c820d91b6211266ef7a0921c4dc51568e9f836d458ddbd025fff6b52445ff707e8af0e02c3771411a63c95d901efa7a4fd10fc07811f517e52ecab1b1680106eb7c3df88e2bb6d22a4f69eef0277cc509130587c807f682645f16400ced744f1bcb8235f5b14f5ec6d355dcb934766c1bf20a380262734deb57cfaa6993526923c0b63593d273a9713b79bda14792b8952908279eedc11a6d3068242635af8655789a74a9ea299af963457e671ef6accf1754af7cd5d0b1ffb271911820b75e3ec2f5675ff743d113a465d314a7cde8c6bc80e731e427090252e91a7f105b4d1958e7971aaa7760730d01d22ecb0a9b33a14e7e508452259e8ac97ced7cf5b604ee116da49b27021fab72dcf595fee200311318193061756315d4f3073c7ff7c03494241367e72d753ee5cee93066da766b883848c58327eed8ee3a43faa1d48484228f648966d6b29beba5a6357a1e7b3f90f690d0ec98c1f486501abb10ae7f6ce9502d587f161b811b5ba44aa33f2f2bc59f7cbbedb53a9ce3bfd911f2dd7e59f0b0ad885044a6e3c15939a853b3f82b72d1f542599960ccb04c04e6a40835d58c82e3860d477c5e33ed3eef6d984a73d38537fd5d890caec9c0e540850e3bbdb53221d387278c19a4270e58f7b8eac4f41bd3b85566a879bcb6598e927f0dba5b8f33db8e24a83971be4ac8b5b1d3006be3c997948ad83ca681eae944fe1fd7e98d23a15f1de64f7d747a812aaf50a6fea45cc1757a4bfecd0e8bd2ad71773a773e098928bb258078c30601a1f0c6cba095a96d77ad50a5e89554498c532948782527bdcd8538c114f98ae43ea365915de277fab9eb401e4c9a157ad0b015e03c32428abb2b18011037edfd64b",
"spend_index": [
0,
1,
206680780,
4294967295
],
"result": [
"58341bcadf24913226c239c3f98212df4441eac171767ecb3bd9c10c3173b869",
"8503f915c572b7a17e89e3016c2b332b4d4b695320dedb09ff14c68cb9963bab",
"fb7524262bcbf4340dd6c30b26e19ff8cec3e48bb4c0b33ed059c4a82d2a730b",
"722b46c18def320f4abefe4537001b871c159c85cfccfec43ddfe59551edd7cb"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 3,
"Witness": false,
"Version": -1982256653,
"scriptSigs": false
},
"hex_tx": "f329d98903633f5c0000000000000000000000000000000000000000000000000000000000eb79ff340060c265897579fec400000000000000000000000000000000000000000000000000000000d036cca500b6a3d11d12d5c9fa000000000000000000000000000000000000000000000000000000002711f92d0087209da1036b4a21a0b2cfe547c8c8ffabb4a756d191e0d24c42a9dbefe8559ae663ae6cbf2580e602b0536e96921deb78278aeb52bb18128f75397415ec434f7524be2ba88ec85137ab7413f06ff04256b08069f4aae1919d9d1894deafb4fc8b302497d6995386eebacb2c3f14fffac585449eca6a9e50b40312debaec965cd9df71ecbc1bbc15a140ef8bca7649ab68f9d79db5fc980730a23a3ea5530a4dfe867e7c767c6aac1056e69436155395295a8e00f1d9a4be8bfa11726f57c57c21db2208bd30a33f773980db53c93f55586dcfa9a42bbf55896cc9b93b15c8cbe3334c332e38af044b0e8ef21829ce3ef4e19e1fea2e1945d4471c1dda993dde26c856ab40839ad349600153a51eca7c8667245807be1df58e61ab6f3ee44d007b2a2fe91d43e49cdd5f9494a106c62810a79bab090846168697070c6d3dc5c1809459d1273906e482197af5312a61624b6cd9d4836183a16ebbd237ac52703131acda724459a5a8e6f6185ee4a22c3e2a299816ef19d6a8b07bba5feedf5c38249d67c7036c8439a6476b9b6504f137ce251d50f32e069cfce6ad0859c4a3cdacc8fc9ec92b7172cadedc66597218c85c1c30dcf1ac87d363895f946b81bf8615762423c4d6e680250cacc6b9d97567215134973765fdd5c7342a5fb40cc8ca5c445f1ededd874cb8aca04f8da28f367f0adb81a30b4531bb9dcd58c90e4c76c0c0cfc5a8abc8bfa1716e1613d8a63cd8446f28d4c7826c901f1fd660d1c097f2e956ce5ad240411dfff96fafb5f125f3557a425d7ccf5899bec1c1470fe93e27f29b273d3fd323529f9b498e93a7f6530fb9fa674360c7fedd5697979b10f65e938375fe1dbdd7650345a9c00a2226b1b3b00772763a701c50ce4c",
"spend_index": [
0,
1,
1790497802,
4294967295
],
"result": [
"f03f41fbe6fa92ec2305822d84f8951c10b434d32910ff87688b5e0954483dd9",
"8d1ee39f3f10d26642ac461076cb16b9fb79b5a13803f887235405762b460193",
"60318fe6ebc4f4d78b5670e4fd932b32b2144c7f0893894fb7c6da3f1fdb6e7b",
"3a7bb937b729b5812da85c294edf30e930b9c9b79ce4c6668d87208626552a18"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 3,
"Witness": false,
"Version": -1503121461,
"scriptSigs": true
},
"hex_tx": "cb2f68a609e5de017500000000000000000000000000000000000000000000000000000000d09e2c75005dee941d01796ad30000000000000000000000000000000000000000000000000000000056b1ef68cc0c10a3bedfc6217be5c1971491ae6d8f63812b90d946e47af784edf79c999d365da76051f8ff09ad86e0ed91177e5b75f97175341529bf4bf3e33432958b1fddf62c6db571f28ea06c35945bfc100540cef9b6ecdd9345f2f615102185ed0686662a6ee2bf34f70b3343a1b484571ef1b7f51f0a40e550a2f33e9d95ed3e2f95d5520b051352bd822f9917195d2f05e2a84e5dc945e94076a8aa5770a008df326357eb34177a78977dc0ca794b84105040a8aada606401f8232e3dda42660aa783e6523218143ef279042232e95bb0445e4fc6f900000000000000000000000000000000000000000000000000000000e6ebe4e8fd4f012f3dd6f2ab4c101582a10dd8f65c9c3e584f17bf7c167fd6c5f3bd3b317c3d978fa2699d67853c33c351b432b9f3172054e7aa8a4f54019c88572c06ef175a2e509491f23c51fc28384f99c6aadad951d45f4bbd2ce1558ead4d687d4bb42faab7755f525ceb1f43059a62725840f8e9539c4f4deea0111bf4c4e6531677c66df5311049ac9888612dfc39b8629e6a44cff527a0be982527906a3479543ca2d6f65a9e028a4cf7bdca28678d63d321520225460134992c56d77809f2e8eb1b8829e26f92b5be1cf0e35085366b6514fee542adb64ec6fc224a58de6acfd22374e5fd7d7e63de0aa53f9646ebd9c373e01a680c32ed65aac686b5c4a32940080cee2a50cc1d92f2fcc4b903d29002b3f20cff6a73783eeb935275ecb29a21bee39e50fcb97a30500fe35ac0c63966b68d08417777d193b5545cd3a57a56c2ee321bbc3e0fdb70d51b2f86347668995cfd0ab0d835bcd13700000000000000000000000000000000000000000000000000000000909ab41a00022fa8390b856ec4000000000000000000000000000000000000000000000000000000001166674a009a5886e8859d478a00000000000000000000000000000000000000000000000000000000799b5fb5d025f4015c024ec5146499032e5b85db12b613a37f9eca6f0daae0339e5b388f90454f9e5526f69b73ed8bbbd3da06eb5413a5a7e562355300982afd5bf1eb141cdce722dfa113ebd32928aeaf331ca40f788e9388a0e72fc65ea6338104aca1eb8eec4c3da4447147543104ca5b64f06a8d6429efe123d4b704079d786294dffa7ea6349103639bb5445d6be9bf00e5b2b04fe48528f6751685fb770cff6a09322675147528cb93b733db529aeafca641a728b00e39528af9dedaa626d9b6503f5c8953c4dd2f9334af98d73429b10225522feaf01b4ac33500000000000000000000000000000000000000000000000000000000ea307843fd6501e76f82049eeff7f492a0e5ab9628cd4b18131adbcb67ae132c3ab6aca8dcfbc8857d65ca2ee39354a8abd325f989bf53aa3472e057c78c60f68032c1fe9b1ff518d3b46177a63f879116bfc138c1d8800143927d931da826d389a16b828e78efa3ded11b5a02d5201233c9813b7ef1101812ab4187b44969b6ed2375164823bcb896af25a6cb2ca6f658cf7d65656845aee7ce3f115370dfa65952454def15460f501d41d72c8dd5d24f05c7a27bfb653e36057c7387f040997e908e98a2da052acc094f1c72473095dd2b0f0388c800458cb869e67fffcff7024dde61f6d44dd799148b99823d5829f907f6195ce1369d918d44d926bc818e882412f852d68be22621c5fd0d1489b9b886950933baef7e087c8d1d9432edc50a4ec45f715b16fcc099644e6ea9f698a0a11768797dffd45cb5c40c7650c1eae727826e8dfeaf6d4f7db6c88262f21a9bc3e2a4169f1d6ca332e51c5254137861bbb7f81f5876c2d5b2309053c013e14085a2350000000000000000000000000000000000000000000000000000000086b313cbfd0501c1823923ed8340dea30b27639a9e04fe0a05956a720ade237611f42d73e77bd3db5249e7882591f38bb387f3be852ed297cfbf74268d51df9a91f1daa838a932cf8fd4e07306041c582b41786add151d02b225bb4a1deeec7fcd7a4df2630907fd5d4494b5a609d4945bf684ac0610ca35366e8d2b113d51a1ff1f1e1f45ca772f23ee577552245c20ee46593fe8a4c856ddceb1b964edabd8dd33367213ac7eca9fd43441261425a3b01d98ba0c21a316922baf7cdf1695cd277e7a544ba701c3a4ba8de3d1d2cad9b0af19e95288474574394e12121f2313861bf614ae244f37ddb3c8eed5b30bb043f239296579c39385106a206e430c950856b8d0ea237d4f5554851dfef7064b186d04bd000000000000000000000000000000000000000000000000000000000409078ac09bc4f8cd9c964f9c5e4486e37161f169d67b45f0083fa625e05fa4c38fe6cb6dca359ee8eeb8c3f59d0575415c9439bebb662ab770b55df602dc9bd3057638887ade68586d70ff0a5c6e4d3d8b69a4000dcb221683f41a675410019eddbb530ab5152bf57b9aaf5b77528d29e5cd052f1a870aeffea850a75f060b66328b7eaee58b381c083ad7579eb2efaa74dc01f230e4e9635a27f38f73786b9e773b0d5cf640c9597a70e28e83ccf9d5d54f34aff383e7ceb72de13508c57c69ddec46df91676b8203b87c4e9c53038d04c8d40bfbfa8b032e4a17379eb32f8bf1e456bae2bcbbe5cd8e26aa59a85b733215d93dcd3dcd4f0013421268d42e44c858dc04fcaba2454e8a08b4cf156f1e36ef7d3485eadef5e5c7ab87aa1f530cdc8a314e5e43bb44fff91c4e2639aa59b8a21507400f3691688a7a43fd7d54df22d556d17fc8b39b3096282bfce97d5ade0d3101985b1654f8c65269ec354c64861ed6f238fe1aed2c21abdf0ee5aeef56b6444c08cbdc60e6996a9d18ae6724ccc824474efd708272a99c19104545477a16c1825cface71708b5df88f02331f4064c8f0c63b7bffa3575667fe06d6e631ab8db726ee012c6d4ae840ad51fd1c46805689bfd7559be84c00e167a1ade51c3c6192ca0363905a8f396e42cefdb9522d93a7752b6c0bc31e0b375d2023cbdc66b39e0c76378ef4039330bba17f6ab6fa36eed1acc396c3f6d1279c30ca8b6a06bf911e59b5cba6e344a013aed80fa048391bf7963584500daa5c6b3dbfa550a46f69f0bb049a37d3369236ea94bcc5175475abdce243fd1dd6202691fe588b701d286f9511202bfdabf265601cf099e4efb8ef631face8c4e2cfac08c92e1c545fc83b7a1c23d3c0197bd0c0dfe76a7744863e9aee8eb1a315ad0cc9a7f63e02247b9e0f82ed9fa62b684d022f651ad8a8b64feeb2e17ce697bd66bf943e2cf286f015f5671ea22269ee9deadba12c2ca3873ae4f91c281c5b24b6782aa6f54c83730c855b4c0340da726cbaa4ab5a4b141809d83fb821214dc60b089823b6dbca1b944fefaad4ad7333c8a5e65254e40d2fc51283a76ecde81217d067d87b359a66a363e075b6fbbcdbfbc39c7d5eb0a5cbc01d6e940d72dfa81a73da02a1931b1c47b37066f9156b5da387c641",
"spend_index": [
0,
1,
178805667,
4294967295
],
"result": [
"c0f082ebcad4231a1fad70bd0d02c5d293ce82d7c7e7db185d5b2554b2f4455c",
"65f3fa82949b8689ea3ab6107c5fae7127547bddd3c8f70738905581994820e7",
"85d973f15ced3f6133056c16e5b424872150e735c7b19a0045442f336ebd9f5f",
"8fae3556a0ede99ae4e1bfb4680dad9cec44f64de26afb93e3ad0f871c226cf4"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 6,
"Witness": false,
"Version": 1575624129,
"scriptSigs": false
},
"hex_tx": "c11dea5d05cb981dc4000000000000000000000000000000000000000000000000000000000c9b9b0200b290a7ac6f849bb300000000000000000000000000000000000000000000000000000000e91bdc03007f72a0d3acc43e6200000000000000000000000000000000000000000000000000000000b6b1ad2d00295bd546d097890600000000000000000000000000000000000000000000000000000000bf722469006fa6c23036cf1e540000000000000000000000000000000000000000000000000000000089e9b7380072fcf87606b2e599f5ccd68544c897d63d66776afcdd23524fe6cdb266d5c1022e393b15e3ee17a96b56af1d9aa19d9ff7ce38f2bc382c3b4b21fa6555b4af8fdf82e3a559a6c6ed58b0c042c4d281f539a0cd9c5404ebe7f8c68de5dd1aaa31d449a6b22e7c353d4f84a738a944c3dd42ec792c28e7e50b4b25b03c4e86c7e3ad3779977943bd59d7a06a9e0090bf65c3c224dd9ff87d7b7ad41c3f56b6d391fdb3988e5832def393ee04113ea86e347a304987b08ab59ae01f63e01f3b747efdfb2bcbcd03edb079dccfe5c2ed683a671780f86b3a3646a566e0d31302c8a788110d740f48430a499f8fb8c445d6d1f8c3b3e07e94a5583cc4f539bfcd9a8e1b160792164cc7b9d60642e8e50c4c46d9590ecb8dec0edb4724e092b8ca9204099ab8bc9f7fdbaa9fa4b5b08b1c87816812fe09d5d4334f64776faab8ec65b8c03295fc44960faf95d6eb60805ff6a3f2fccc6afce6d49382909c1841de89abdc19dc35b8114b0845aec5f4b1cd7ab335f0c31ef279e473e859f701172f43b7c77fce8b1126af6a4adf0862127d3e4ae3a26939ab33865468723fc52e7f06221bc6d2c3ae9a9268b266cb6c79605cc8aa2797beba4931b1d95ea442894acd628a631cf9278971b41040da8b69951830d870ccbfb4e14c6bad6f478b860c576a63a920f837fb311ce454a471fb51765809d682b3952cd2afa0f317f2e4b78e3bc4449a89c10350da53a331c082b6b42d4675c99208ae204e7997723d3b289ccb1bc297ef4d59405e0edd2ae0e34747c07569b477f38b9c6863b778f2d84c20dcd7bfb4440788a6214d34ee7c8083e4f1f74471ce772b43cfc236c750e4fa83f46cd676f6a66bbf9b248cb105ad129968547b37092688c8c8dcc09ed8c4a32446c8a4bef9f3e37817a5c02128f3032cc8b4229c047c84e2167852aae160fdf153418a6d26acbf78994e902d18d83000a0be6f0a8034495c73b32c01e35f7b9d992ee3feb4bd48f0c14f6ca7e5cc606d9f6fd1fea227ff025cb5011ef6cbc90fd3eb56d6c5820355e2a1e8ef3dfb74dd78ebedb2edd1f40913d6f07acc44a6f398f2fae987d709c8ca88c68d614f6454ab8ca4cefdc57471f2bcebc38cb511253baac79261b04ce77b423b2c9f0bc51d784f75c16b78501772e4ba06dca487a1b990f7102d1a4f9e3669ff4d55b4831a4f65c8e7b03d0acee88b7118c26924109098272ff1cea11fb4ee9496d53189fdf8297df6fe9be7ea9c0691c5b1b2fdcbfae3d962087c340180750b69ded3b7588326f51b80d1dfba75c7be4f00d0d0addfc2a18216b120b3944590d2a5a767cafc86798dd75f59e29bf23a942d6d903ca78d3e8da941af499d4761cbd4c005a3679c8eb5324d88af0a1bc29be3721452ca50a2081824a288cf0e91f71a820ca781bbf90bedb0cfefdfb951ea0e975116d5f640c781e7060a521fd3655f8bfd185966e89f75b4163802287305aba751220d017fc89843f5e6ec6069404a67fa383be88db9707cd3006e4c3dd25f5a533b762b21fa06dd152ead0a659aa3e085954ede15dd0aac553e8c3dcc09450add4f1ce86e0d0dedb3a848bef9d016147b51d8ab928c2fe100f5d5893c6babd9cfa5b66ee80d92ccdc358330711a6237c4db067ee8347a1c7543dcf0d82d51ea17f75c8db0ac2354282c7eea98052a584a2090b2a3e81d1216090e0285a8498e7c7422c7d95541a34b9650667ef74fd06fbacdac9b73880813bf645e33aaa3711021beb326e8abd9b96b47a86770ce6994ab",
"spend_index": [
0,
1,
1689259243,
4294967295
],
"result": [
"bacf5ce1b20c30f37c9fd6bfe1ea6a0bc2d11ffbef851bb2a938774ad81e24e7",
"76a6b018ce73966a14dd33b530cf7bec0654bc03c1069425327c2bd8ef8dd01b",
"2b9480c19a30bfd2d71bdb6432ee44a7a44c1e19fd5e50422e98453a27c4b361",
"292235358d40ba53a6087432aead647aa651f3f415f876da958fd814d09c561f"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 7,
"Witness": false,
"Version": -2047477303,
"scriptSigs": true
},
"hex_tx": "c9f9f5850a71a2521800000000000000000000000000000000000000000000000000000000a797937efd210139ca4af1285756ba497203c3872a7a74b940f5691de5b47b685708a92a2f2faa74bdaf7ba88ac45e8f125a3a1392a52b7ca7f2379af61d8ba371c8a97c28812e62e0c4180d2938353f20b276e5753a466f15f680dedb499623a659052569a57d3f946dda1f587919f424682c2fcd35b6bc8fd9d3ba1472c19ed75e922135b1a4752b89512c7633796caffe25f7c5abb1e4c45986822921e2ed8d4e653d1232b45b87332bdf367248654e48604bd9b487e6786ad47d9b77dd3edc2e3366fd43981a54b1cead2da51601ba9f3a0fa0ff3d890913d43d16e5262beb7cc3be424755f453cab87e78281689ce51c1025e64493d3f958bc0ddce21d75fd82fb3215bac54d40fc8db06a19994665973e5f627bfce37f6e7b608585a7856900f58a67d89344666517b253eb1a800000000000000000000000000000000000000000000000000000000c568837d359b2f75e75b3d39b5d95ab308837b50b6a4724c83d8884e52d24ddf11ee2bf8e2f09a6aa86e6849a218598f427f899017db9ced5e37da0d3121cd256a7400000000000000000000000000000000000000000000000000000000eb5cc6273221db095a626ba6a6f671293cda3558d1c3aea3562fa80f535882e63dd40ee619b3cf5ab55338c5d64b3b041bf99e6b7912124b9ff01b549e13a1000000000000000000000000000000000000000000000000000000009ef30358fddc01f3e13fcea1413e057861d719e571ea78aba967df3fe4f52d13d8fc72f0345ada8ea98a968894cf0d59586c298dd9878d6bdb01877289328be0a280871f629984afbe1cd05e016fa0f38123bd5c1ca1c5fde54beb5c872e5b481662b7b86093ef6bbd3e59529b02496ad66583e73ce2d5af8ffb787dadc5483180687ac1014a22a35c490aa0be5a1326619057de4a6b5395540eca7ce0cc2df05878744ab989b21e9d6bad9fb7d5f658d777c4c83d11eaa9eeeb74eabb2e335f3ee751c9c294dc3c920b9b619b0242897acab50c722fe78a2dc2aabbdbd36b10c18525996f558f7d2cd36f0be38692dfce12e5b507be796ccae0bd29b293c4ad831e7bd2138f06576b395bb0182d67a900b60e588152beaa2b66bd9e763d25b2e586806fd09318e68fe9d61111884516b860d8143014d36f43ade13a21948f6cd02dd4724ee4d9f348410c4187d6236164361ddf614d7c9c75fed4b022ebb131b1c749bf3337fc519b2a6021af2f575183e587211d8aa70d1e5bcde674aef5ec5a8cfeff8b0ec44974a704d4b199f943344dd610c97c6998b7eb4b7fd6f946298946fe4d8c2684beaddb47a7219b1370a2a0dc97d3f159885337dae2ed4cb067ee9040c51ad1a557c3134b5d88bc88dffd39fc15f550cc5822cdf287942d05a60306494a7c10be05c8f9b000000000000000000000000000000000000000000000000000000000694f038759e676927bd0cddc680bc3844e849de663b85aab13a5738e4e8edaf7efd4db889d87bc03a060118f8a6e720a5f5c9825d110a181eb8a2be1216f21198cd954d2fce2581b3ff50725960a9013a8347f270c8dbc899a7b20f101f67ff7573d32e63341000000000000000000000000000000000000000000000000000000003f46ee457c3eee443ff1a0a98c0e17deedad1445a18de5b2a734781a0cc5de3a1577b4c11cbd94fcba823aa167ffd6282a805e8fe896e883ac8e0f9795fa0f1ce8cb39042e724417cdae4c3397cafbd9792738820b286a24e9d1e3b4bad3db1ad46f232bf8e79da2cd1f5f0364c6c18c9526d856e725c3285aca3f0968f7d71143032a22ad87a2b12e00000000000000000000000000000000000000000000000000000000edd59f3dfd0301683b3db9e8877da4b82cae60088f4cd57375d6c182831acb9d86ac0bce97887bbc3eaaf0644bc87ca1e81274701718d2000697818b8124aa686b06a2ddc3ae69688cdc5c024a4fbe59616c22202cac77ddda4b52909b166d651ad5122c4826e2b555ca52d75892de41d4eb8e8cb2c17bcb32e6dcb327bb36effbbbc8f23757097813095f6b3b1513c36dca3d3f8c10b6e87884c18c18c83ff27588672afdbcbc7956e63d38e265bebad4a2244017fcd2cf948c9d0f8092fc61c29245186a53a87b1956fc7e0e2492b1381c057a56df789e9c0b7ebd1e54097a6a1005cd59a2c5be167a8327019390aab0a56f8fd4aa82b381e5788e60ed8975dec6fc047efcb2bbc597cd00c4d342aeb95600000000000000000000000000000000000000000000000000000000edc15b9c0047a68fb336095ceb000000000000000000000000000000000000000000000000000000001b0abbacfdff006803a5b4846ed22ae9af55d16d338f39d56b32ff7e6a42e8a030e50a2680cf3414b7b8a2010a8ba6bb70265aa6039f06ceac4a9613bb5b38dcbc56eac41d420548e9558a16213d5cf7c9fcb4606070a1a1f9258ef17c895c0bc00c5f630b702fe0e425b6990748ff78bdb27d6512a4c9f326dfdfbe71e55f15c7be300d606aab1f5c4176931a8ee3bcc13f8815311529c7c2ea41e3280f7352a296493d2824269660fd24aa943608bb9c9a9e80a82bf4853f882ebd5028c79007b91f430e106899a0656a9ebc4455d81a40158cccd76b92adcb5051920e5b0f1f305140aa3a284c3da654ce887959ce95f1bf095dafed6e4e5e78fa1f32e8655e68e980bbbeab28fcc45be2a6f0000000000000000000000000000000000000000000000000000000008f7fd2fcfd3501cd53b57518f1d683ba3e7395986dea55c44a344f653788a3a820a9c695dd3d92df0d7ec6f010559dc6423d4d6a1e282f7a3b74fac6cf91d6b7e61e0c7b3df2ec7ea3dedf627772c0644f2ce93abc90be91bd66426f11f1a1bdbbbbc5adfd0d8be28792bafa71603a71dae861fa62dbd7f7e4fc98261343414e332ff5708e3c97c04ff418e2b2ec185d1b8d1d589937c12ca0f2bf62393c9e7ffcc910d96ef652a77af479f9646957f137af33e2e8cc58e5d81c80605283ae26bbe479d6dad6c651f10920fb383486616b90f2c658c4a39e1cd13afeeac9a5a11ce7491d7cbab2808663eabede07754429ee753fd65973ba88763881fe948863d12189ba885a3d4bb0a3895fcdfcf83f2e20a3f47d3121278aa64fff71f49e61cf0db1dbfa0fd27644cb79582ef0c4c81a088abc64ee0f332e1dd3ea8e605ffa07958d3b14523f0b48c82baf8901eba24111293e08901beca34b0642739d825930c604dfbc401f30ad29b6e97b716ed98677151242c9a109050636c83eed74df2a58ba5bd6bddd07bafad4e39a0d6e3310fd1de8c6a0264a1c536083f69f1cf4932ec2d34fe1a0e85f2bb796ad86ab07142cb28b3b91f3c178b993608f7370416baa1d9ab723a9007d083f07db387d6c2e53edcafc8940b945adefeea701b9509f08b512a4135fc00ce68807bee85521217eadabb6d45e37746b3151aac0a18a052030c18e9173b48ec6f516c2ed7d7804706b052b4301a2dd3dc8bed99ebca3f28694850c382f0a5d226128b055a8080826ec21b61a70c74e792e617457917f31bcfb17aba58a489354fa9627dc2a876f65f8f5e5ed4710913f68aba0cc20f6e6c4df1c51571a00f5c5b552f96c8f48278d2e7d68ad0c5e34295b899223a1a050d2e9068fa1532f6856ada35ff0d46dc30bbd1a360fb6ad6d08d9b1c409be3cebc63cb049f8582ae4b1ae823e1db92bd1d63d2348a8f52ca9b0f17d4773f013c6f481c5ec94b4798e1b2cd4ee8aeb145c9abfa4dfcf8c94c720721d4ad0482b55338df705638f45cc8159c82df07f7ff24630a26eebd8514fa62ea0361915628853d47f3b9def22466c99d78f8ce43d1937d616547e50f6aa1a7fd89da71b0585c2918d9e1f9f76050a983712f449f74cdec61641da51f6a511738de8b1e535a9c86a782903dc1bb6c7c2352e1377404458a5cc8f55fadf06c3c1a13508e4e4946a5a03314124621ce0f679b816512345d92fe6cb00e5e54692f813c454b4d3457a80de5462440908f40dbd9405177aa97603acac2f6d5d455676291fbf033b2807644dd91de143d36c438574d26bdc85a52bbfc8d4dd941073f44cc821d802e47b393c4efbfb1aab7045697df1a9850ab9806ccffa9250d6f84ae78f3e5fc325013b83f27b387cb2ab37e2569467cf0ded9c6e570c303d8275f0950d7f2645f299ef2f4157f7f7d5bfb330c094d83b15fb2cd6ab743ed3322917dbacf75cd00e1de5aae7d40abbd6ba08c22e2eaefa687cf6ae33f67bf3bdf07793e8e10128ba6f01b64758a376e9a08e71082e46bfe19564d9eb4cb602311223a756a87d1499d316f59260dc315c60532af3fc7f73eb3513ae426e6fdbc117e49bcd6295ea4519a02ce61072b4670874975bc86ca4c27018ade97e38a902a7fad9e41135078951595ee5d7121fa6b89eeb068a1a361659a0941921c4a0e5f23db42503f88e82dd955c6f9789d877e37fee05f44fb9771904bc6de7566c7d05b3f254fef59fec0a1b2a2e35f01ea60f8b3b1dfb0037dd51b33a3f97cde04bc4aa9408a40563e078005f00bbf94b1d962679374957a5baed6f5878ca5aaedd2e316c1fd4a8fff61d9983a938cbba3973d958d3d104485d53124483fda8a348ed4e8dea2565e8d214d3175befe054bc59c51a18b2a6eaca3d4e6720a4b14390eff349df23c8767748137df6cda8972b3d7e6c599bd39879f38de3a774ed8cb8f623f50eed76534d6a94ef9c82f369a953cb61a11e1aad8f206b8435005db4e81d94bf2b641f47a18a0f44aad259d958790ac964b1702aaebc4b40caadb03a665374803628eba669ab4306173a6baec79b77bc1da5b816574c87769ebf7d092f46f1489f8121814412ac036ed84005a6554a494cd920ebb5d8b804c0f65a7a43f33b471622394b4f35c9dca24d876aa8e5cdb09c50fd9c89e8ca616b2563bf03d31cd11e9699cf7f8081587abaea378b02d48a7eb36bc8de395c6307da59198dbc8ac1f29c539f8307df511739b84cc56bc31d350d52bce9955d6196a3416b50d38468e3bcedad775a09bc32926359b81b3b7b60aa814aabc4800bc3c3e75b71e0e4c47884a8bb3aa678aa87234278e2fbc5da9af56d14541f16ffca371e041ff605c06bf82230ebc54d62ba00f92bfdbacadb827016ba484a74483e0de639c742a2d5e24e00de9e6eb63776ce742bad238567137242c4e5c6fa8f3313b5b18a1dd8380073bcf39c700034001c5723f50a715d06477a93ff8286eb0f4cd84f4ca0b4e9",
"spend_index": [
0,
1,
1195087093,
4294967295
],
"result": [
"6aa6c8f163ed519070f1b5d30899f909846523a9f5d52f82e307f6e325c9892f",
"8afde97214a02462a752ac79057c77d71b29c7092d41566c22ee2006289882c6",
"6ce7c0be2b0433f000fcb0c4ba54e1dad8e62939a65b6b99299fc2afec725bb6",
"6c86ce104cef982553616b66e045d4966c7c8c29039823c9d42420baa3f07c56"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 6,
"Witness": false,
"Version": -261671089,
"scriptSigs": false
},
"hex_tx": "4f3767f00142dcf017000000000000000000000000000000000000000000000000000000002cf836ee005ceea6cb067075c902188b7267c8d41847372c474a50b5fa4210c567208035b741fad25c6648c75350636ae11e4e5f8d1bc3f506dd8e9f736b5005422805961b87890e32aac131083f174433a492531c52ee7d23c03dad6eeed7e350334a1d673b5bc8571713712466d613bcc63afa94e31c5d7024da21180feda39b66f5948b7363bcf687bd73cf3142325a267423edda2e46bd38e5450913f632345d1f87afb0e2f7bde2821ca24f7b35d315e54c89c631ed909cd7531e271b820475f9f59858c53721404c59c22de68df078cfe67cb555b965f4fe79066ed4253ac84dc8c2faed9b7be85308eee3345f411b7fcc082c973ead339c527b9f41580dd57ecd2b651e4f2021cab0df68deee19f4f8b1d3f0dc0ee245827f9e15776a626e784ba4e25e5cac87a4f38237f86582f988659c8da97fdd6635340833b47b60d7f355f0a3c594adc66088617a421180617f4ff302be83d8a869ce3b5dac88770bb5fe367ad271d5da178c8427cdb57f2bf52d09e53eb52b739ac3f8ee1f7fae1f7ea2f40b61f7a25dc663247287eb37e9d07ec12acb11218417fff27e1a23b0192e6488b7e0acf650fbee9440109b59886d16c84f86b287d715375c60e69853f621999e780254fecb325460c18c1c533ffdd325b6dc7ab559615974a4e869e887c215a25811e44d14c3e1cde85302b45e4dcf90d6292a8098c30d70ec66ec9de3cb989ef335f85589918c77ee9476bcdc2f77f75455c647a4fa458b2c5b0107c800d575dcd7776500d98dcc87734fd10c7bb8ea57bb1ff34b124144c075e56272ae8b922cd0a97592d820257fca45f0d4b020cc56b75bb755301717b62995838bc8789f610037dd4ce3f4f91c9050127373f6f25b8380a14f8b4a835401feb2588ca131c85e4a0ac5e4d2d52198438b4ef5fdd9494d11e919f6a9ccc499de66092e2d5b815b1af828b36afdff71274bb1e765c118585874d12a1f93f19a7cc490ec809ea923214f526b6bbca0bbd44363cf74cae4853ccc3631c51deb06c6b84ce6b1c7f8891d5d86457c28835bb6a6fcfdc3fcdf5e1aa01ad043bc8586e03aa89de83b85d55fb367efd4fb0f32512fb352d2daccec669211147b9bab8b84c93c3fe18b878ab6218b2e93571a75b9e405537f6224058482e6334269dde4ddd732b4226d3292038fa94cb7c529e270e18bd1352819c8da36327eaa4004505ee199b3a4a6bbcfb243d33e2070f284304c58ead9dd512b1a5f616134105bfdc27689814da6628ff7decda254d51f56d48a18aace93b425ab9a2e850b8b3554e2f4f3ba93ced376ed2784dbce2ac333b189bcf91fb6ca0048063114a1a62aeff98b67ec3901d1e986cfe63e4979da9f13c642ed55a0446ac66df97231f3d025db73d707ba8eb6f140b9fd562da17a8d4050be92438682fe6aae8682488a579ed8302ea51053bd525ed16fb71045daff0aa5778286357c8a2eda9923d11787025945dc3c2ae1e55bc85f4128c5502cbe1159affd70b6320b2f6081c64f55304f3582a42eff01da1231dbf3b4411eb0f12e03b52f8170bf0c721920912ca9337754c7014a4066ca13c032269bf59a4aab7fe7ac4265abf5e34d983da5594abaf4eb582913e3f712ea08c3f861c6cec3e182fe3a86903e62a8d0dddca5a8348507ceb9c819a20f7b721bb11b36fef9e22e6344ea75854cc8c7964ff8040a853e13138fc1d8227f6e722805f53345b7b540efb48b0f49cf60107f3885036111c3351f42cf92220c7193e45dc57749196778a0dd60d267",
"spend_index": [
0,
1,
2550797592,
4294967295
],
"result": [
"ded67ed13e00b640de7195e0da96c0405467542644a4794001bfebd0c6a2b9b2",
"2ba50675e027fa8ceccb9244f4fbd5fd0d2366cc69b38a3f3a5ace71af7c6ecc",
"f13c3dec9ac4a80790fb6366a297cacb6493e44382342d780e5b0db737216fd3",
"e0e7ad3d3908da50829786291541fc8015d69fdf65e4b2727e084aa5327c32d7"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 10,
"Witness": false,
"Version": -314128345,
"scriptSigs": true
},
"hex_tx": "27c846ed0a80c6e24c00000000000000000000000000000000000000000000000000000000ff8b159f0074cb1b9d5e00845d000000000000000000000000000000000000000000000000000000000e6d24edfdc201a28b5437f918eabdee7f036abf5d17d23e586a13004aa00252ee7eda09b265715050efd3a7ef31e1f77a8dd599aa4c8478a07833dc9ff8f95b9c60da6eb33b24fb516703eac7754f660014ccae667be1c5f72718e58074f874216f389b797a611691471f3594eabec54194be149927007950705646c1f3d45d73363f5c8cb62ade56260034adde6de77851bcac997abebaa10c5ba7007d234e11d3d1e190cb721744a744e4374f7a1c5e2460d077bec111dbb0a9d3bfb6544d4b469fa80a4fe5915a4d0e2301f7834cb149637627294b80ecb3e9d5ed92179964231c9aa680911da5f0d1804bf34534fa394fad36c7d974f2d99f4d0382eb640546e2094d6f2b7a6277f92b22f545ee0c1c8415a8a0a9bafe84e2b9dc72a1818c5b802bbb3e83bf9333c40a55321e6407e9a24199e40a3b6b390f6a58d54488560a926136ae70a57817c5c99263201404edf6ddc0abf690fdfe4e28741c482834aa265cf89821d2ee4c2a2e303b4e5c6d60859165263d3a3a10973e85da17102cc949b8f58b723641c5081a6db6daacd766dbd2464f14c0c80292f30d77d31179d87ac7a276d8994af4ea3b460f9a4da942497d638e22eeadd1d8a99d016b6e723143f2bf0933373229a7c36a876418b200000000000000000000000000000000000000000000000000000000d11eaff8b03747c37916c447e0bd12088ec8991503c5edd6787b75aaddf5fa306a25d779522788419be153755991799d8cf6edb31a99de4c285733a28521b2125bd29c0bf2d59372af22fd4e2ed4c22782d55c77fdb1e06b05d94f4eb2d1928b27cec8e0c897f2929a064abcdf36727c9141febefbf5a1c64fcc80fc13384622f602ccd0ee18b0c63981ebc4ab01ac36b60f7fd20ff4bf192c2b6bbfb832e7b1644cc23b724f3972d0d8bb5beb2dba946559f7978eb6d33e5d9a0798ab00000000000000000000000000000000000000000000000000000000c7ade67d4a901eefbf3adafaca07900b372acaf84573def30025cd8ad79d67698c9394c0bdb8a7e81fa893aafa2cd596cb1e41ca96c376601e618c29defc023dc73ad746d3dd2586b39a2307e5c4a6a385b3e05b25a0a0000000000000000000000000000000000000000000000000000000009de5f8a1fd6101794a308c3a3b17197dc5bd3bc31c1a13faf76290c11e22da8e5243e7f9df2de976c0d3c8cb3901adb94df51f822f21c4d105f186f9e818c23e2c2a61002f518715e8c61a4fff2da5c967bd145121950a8192fd642ac909c810f6e50d69f224a2456bfef2394a8c041b92b51d752165d5e3beb68c97f2774e87ddc6775fae42c6858026f3c21232d45fe079acba4df781dbdc9c5971500846c76a73094a3f0272b0ecd56d9eadc50e4657e8d04803bb1fb8eb161b56888ec4a59e2b937e832d2cf4f89acc88a4a283b798298d01014c2a6755779a8fe9e3cef6409679599bc668017fea94a7d34fba2ba1d8ae20118bb1b4c75f1477844685dfeaa0f669752648be407001399045ff125bc812e67ce6659760f7ffa10330cf63933df273c2a732995cc88c369aedf0adfe9298c2004697bfc63290a3eda5eb32da15d28505534e1a652694f6d69eb7fbb925767759795bdc475b558dbf8c10bfa35ec9438b675758649f928c5d1cfe42000000000000000000000000000000000000000000000000000000009585b4aad92dd9dd929b8c4541a894d112ec4c345c01ce68b81ce1580eb15299b20929a6d0941b889dda59444eca47c462072e0822c8aedb88e0c37413051f74417c85c677602c715dacf1ef27a6b6bf96f2e757aa35594dc4768a7ea74c820d686612e656ca5ccb186cb0239b569e807161fe27c7094923f0055981bc4e96f027b33fa3a5dd431facd38f61127178f613ff89cd558e74aaa34b7ef87d7e4b58a8c15f6ecdba9071af642392e70f8fd4a01b23e909b321965f2dabd76b9d745d4cf7357c012f882f7fc14384c31e149b876675061a580f39072615918a45e11cd948eac14d8400000000000000000000000000000000000000000000000000000000489fc2b600e6712876383fe97d0000000000000000000000000000000000000000000000000000000096264e77d6689608c11c1b96feed680b3b8495660dd2f453007831b97d9d9e81761a355aa73e51d3f2f21874d15684065e4ebe611096f849e1929c67178036eb399a60f53d2ab4a4613782d16e98112e8dbae0ac212a82197405cf1f0f0f8878a8badca09a6c2486123c8cef6dd79d97eb02fa9d6e8411a1a9b47eb012617f3882d289f753a42c35783f32045e0663e09a309486590bd44c53844423b016bce45aa54319db1673cc7e7d6b74fa943af69c6bdc1c0d5bf42f63b3974ea79e8cd363d5a478045842bf211b0627b998b04251ebe163ee93e5484280822687b00de3d99585000000000000000000000000000000000000000000000000000000002a8dd8ecfde0019bd51b99024f038464fc907f34a6c795eb4306462677d6fd90208dc2d8171303cb23a999425899bd694b5ac52e8327d274888b75ec09dc85b3c89e8dc5fae1b15817f2fd6511f97aaa0889721003c629c0b051abc0cd6fb0b9881f95cdad9496f466ae5145b2ef0b53ccc31b7458fa376b4ed1a5c56480bfa12bed0eedf90085c901c29413779848b57cdb1e11ab3bb8101bb942aafb72dcafd31b4e9ff2e5d6ae15fc93a3bb1e1b9b44cfe7d9e9a32224a98510c4efcc1ec26db86d9c80abaaf7c806d1375e77daa379cafe1bdcc35683bb1b361552cbbad843a0833e024d1ed0f66df9a6627e0353c8c6fea90c03a42e1d018ef833bd56623b4cc1c91833c6669de6fe7f0644af7284c158ea81c09a7e302d6b46eb91aec4499a8d8cd1b89baf7d40c408d173be78351705de63cfb5d34619d380f8b425c04be8358591a3d88c19f648a62d097d7b3119ea72d45dcfdb91f29e52ebb8dcc49afc30b571ff89aa82137e3bf54a7e66d5aa6b2b638991fef76057b1dac2c113d6e2a8cb472f145fb22fab646e74d6d4835f0c031965ce46ff37eadaaebc8d4cf0dc8c43476a0a3b098ba4652ff8e2a4e33d5103f884036aa7577ead93a06e24469345162975412508264b8ae7d7432462f769e300c2a63f3174e803a48d1735e2e9b8397ca6ef96d41350c4ac9122000000000000000000000000000000000000000000000000000000001c1e0a33dad3591fdf0a81549975be8dbede186c82ea288b85a3b73542057a2a8410f377acc3d5a8042a3abe9e48b889999fa94e632d20660039ee5be42fbcb1c7c2a064f1b245cc8f633c1e0d57f485d68e278e42b162b7bb28e096b85e7bda65957e599bac7bbfd4c9f7e48fd351755dd75e26f97b7c377d2ba4f54b6ca34d265f5b2e47a95673780847257ec6aa89fc011556d186aa4bcbe244b258ba65231d1677c13255bb009e4ed81d14d301d376e35f7f1ab917fd7881b276fb589eed0f1ca2d27b693c209dd3146b30abd12784f1057146528e3d06cf7fc18a66afe5fa780f0a46b0c476e11c0e11c85e0edda9a4558e8636df12ea5f709c430306d9e6f68451a5e996c6d3f3be7db5508c86ef151d8d2d0521c47a7ffe10e3465d313bd9b2aff8f9812248de032e270d0780ebfc5e38c3a08a79e94f6b8fbe455337cd84ca5f2370969a396cbc0fa242b2ac336051cfdaf04970158076832e55661d55935931d826b977b19b8688b367d79b795ee9be443abd800e36b2e38fdf717654038e9ddf3d7b251d9b2bb7f34996dd88f352ba3fc3f4b097fa507e550a767e942f9bdc82caf841618ae5a129bf1224beb2e5ea536b07bafbce673d10c80add70eafd3b58823c22a9667dba9e3f53f96a41aecc79b85c18093923dfc3b606264330cea38dadf45fb42f8ca5f6b53ccc297a66a2131aab3c0e332d75992cfada18ac24bbdc27ca738b55cdbd2255ecb7c112bdc2ca2af7fac32aae75ed02d0215d0fb92dc55bb67c1db0d470256f2ba0cfa216781bb4a025e5a7aafee3cd3f120ec9106e50bac17eb8c1d5746b94e425c5bdaedf0b337f1c042244db78da9f42940c68cedbac6049e00dd8658deb80383f9603ae735a6f13c98d42ddaceb6490b5ccd732fb068ff83ad4c46dee5fc88e865f33dc1ddd00213924837e4e77a29a9aaa962e9eed5be821900fe77321f0397fa0cd89ddc390414b59d73059014a29d6ba0f51d19331fe7906b65d9e60430588b9813cb7a1d1b0cc7d4af69be3fb459168ca33b835f25377bc7de64f1e334465bcd92f48476915c35e188a20021328dd6ae5edeba6ceb11f7605ba708aea7cee409ac7ae52fd79985eb6c0937f8de27c95db4d53dd88cb49ef4d4ba44aa06ea60ee849f2aca8a300ce85603512b7741f31af9e9cb1c0100bb0baf36e82c72429ae9f56fe6c28d25bc1e80797d966c8e2b6f7393a3b09e6c76ba16432bb4a9f8c5e3dbd6395afa0755e050b4ce2b8c6497f366f4278bc0f45cd7c88be082d7d4e271232f54c09a1e155b2445bc579e090748be3d011d181c49a845beade68a6f6f8af6c0a5596380a9fb46a81c03402c17143999436b9e57f22e2e22d7c568c917f6655b03dfbcc7b5d4f6ca236079e2287338b971292e06c6f5dc4a3e2d4426d49b87d09a9f432f40b90b431810d88c6d18e4a13ac69b78731c06c0d3ac81e572228332c200f1b48b1501880c0fc452ae815bfe794e332de32d1b6b7acd263c8840d834946ea5e174a0650a2dcbcace62cad3f70dea795d6a65610a242b19733795d4baf645dab1ccc035c5535fb0584aafac55aa591f71561211771f8dc98da6074a44c524721a5bfa8f5a46784aaf9e07859efe37beb8abd97becf88a0e6eca66b42f100a41cace723eda7b91e8e7c869d83cbfdbe8d36ea677b736671f85c4c55521ebdfdd8aaf6dcc519f803b9cfa7b154f8ffa39fb81471178f88da7fad03407835b4b767b87655b5e44f261f8eb334c4dc96e85700d30d30cba2a4a254d86174ac8bb11e9b9f2eefd27638883ac8bcf0e4949096bf00fc43cf99b44f9fc12469c5045738d3643e72a029d25b323f1e3ce8d1645033f5512fbadf30eddaab425e7a19a2d9e23f527c4a85b1821e72a56c0ded32826150a04da789b01e6f934e15a5d32ff5e128edb0108d2a6f7fc4181ce9f7053e26d7ab2437ed5764788ee58289ee36f27e85f0ae48413a52f15899573c3500e39f66d8142efdb08d5313a69370b2807e0130d26a82ed3d092acd15d7ea314b209efd385cc49b64340ec654403c763a039a05bd1629673e36d5d4698bda16d0d08b265955524f14321d62c880de15f2431ff99042da3d686767e7bfc7897e36b2ef3b2008f47575005ef0c15e4eec0b788cb874154f8904f6d0922ac6c811b49d5eff4bce3c2c466323de1778b6c369c821242de0f06c773c66fb633a952c423aff0d275e5eb1bcb416345098d9597f6bc089a82a84fe4e1454a187b6ea4d4d08f705f5a5c47de3a0f54b3bcf7b8de10cdc6fc467ead97147995099fc40ee0bad50997ad02b29e75da7814cc67b296b2ce61e3d5e6fb962d6819e997f8c59420cebf26f4088b33b88e1e3283829c0b291a51b4031ecf974ded95e55c88219d1cce2f0a6d06990dca93743651986a07741aa668d2744e71d1035099a93a6e57a230dd21f8c3feac40e20f6285229aa295ddb27788a23d8fd005060147829bb5ef833dafbc56c209341cff830ba840c63bf375ca20b51378ae80c5abf8d7802506640302feb0c0b455f0dac44cf9de3726fd65f4e9d35b92567e5e44c45376a089b426ab9760754b004238f210b06c693bbe73947092457b0b770af0a951b2098a4e2b86cfd6b8120e34dcd10b6bea9acd92e0a92cc56f63e7cc062eabe9f07f823ef9ee6c587d9379e19450c46c8d35791b8f9095a5f75202c78dede7088c77484726bfc91eb3268ed9a9598b069e232cc0ec4dc02bfcdf697c7d6bb9c9e51da9b93a05cdf0187b7228debe65c1ff3067616c4e7276a460e8f4932329867102ee8aee94c5216757ff47a79d5bc1c2c764593fe80bc04771b0326988c067579752a43e647d201405b2ef4974833ccd876b47a4a06505404dd4be1cb1b96d1df0e4a1f68017fedf74803eee63fe3a9fe32219df72cefd86367cdaa378f893149d106a0e60ec3bf2d9abd50e8f3330c80b577d9acc3c70335fbaf3c31225820c85eda9d0e968c5e06687f77cfe8810013102b63f82f9a8a166e9bd06f85a8b99efc4106cc83d2404c8e709fcc2e6857d6666e635620ffd2f3c8c0967f0f402877c12a269b124ee1b6b4a3173bf5c5f47977b29fee7690997108bd913e9cfaf0e056b232167aa1bfb7b61629d1bddc4ee80a0d11716dc6fe897ee47610da07b27fb38bbc71ba392731d1c658f6ed9d73c891d476382d3a67d58c9ddc81c7d290041846f4fe7d81981d4ed47217ab2d843d5b8771468ed90cc4bd8efa2ba44beebe43e0651bfae5d1f2ff43e1e7",
"spend_index": [
0,
1,
790666337,
4294967295
],
"result": [
"147d7ead14620070d32f02fcdc3fe3bd2e312cfa54382e50a92f7eb14b3ad43b",
"5680032bc0edccf216420a54fc533a0d53afa6359d2e5b7d5fb6f421c5f58067",
"16e4e60831dd39d29859ecc35456beaec2c0a6f72ab0a4baaadf6c4790e41699",
"6e43d440e6c62d883f20871bef73df87a78cb683ab96c2f478a639fa5d137274"
]
},
{
"desc": {
"Inputs": 4,
"Outputs": 5,
"Witness": false,
"Version": -2004472070,
"scriptSigs": false
},
"hex_tx": "fa2e868804fa32dd1c00000000000000000000000000000000000000000000000000000000df35eeeb00cfdaf51a02780b1b0000000000000000000000000000000000000000000000000000000036ce5907001765c8dc82fe1264000000000000000000000000000000000000000000000000000000003f6763b3008dbe2fed8c76a4fa000000000000000000000000000000000000000000000000000000002fd35f190080a4b52705daa84b4f702ba527c8a2d7912a18b25f27ce07a923ccd658e3a93d3251bc3ada48464a7dcab9d4f116a95b7afb86c6cbaf720104d337c44a4e46046e2c1852050aea8af53b85b495aec3ef5fef0395e51624bf7f17df2e090dac7b1649e2f4d85cf82bf488fdb1d61836027cd128070545313e1f44cc6071a66f0075b2f89b7c20c216a3bc885cef83d594db270884d4adfdd3eaac8e35954ba19e7171d6cf23fdfa2b3bf5e04adc6b64225e6c2d3fadd1c2ca275b7dfa389e851201d8166e1998a741b7311e41989c61fb215b3c9a9e7144ef55e81a1dd057c88373d17da92f6c869d537fc808420f291ec329f5d91c26d02d9fc28bd54be2d42fb88c12735e1bb0e7f83d916198868259b5eeb4128a843ff48c6c17b430a636a081209523cf10549b7abca424368c4eee8dba7d57c6e69a6c482c3cf3dbf020c2d7b0a50a852a99e1d516007fd6dec5072461eb19812194fb4d870e03e15acc679203093fe771005afc7c8ddeb22c4a4ccce4944307e1836176843af4eb2be90fd26cb90be6b4ddffb307751fda4f7b9161ddb31c2faf5704e9ea5b78954ba695e06c7ad2f4a8ab0e0a05dd1d6da322c857cc0b149fee01b54b4a3d4640931874e5a92d8f5cdf6124b7a3c58336f7973f250c66e7d37f5e73c4954a91f669f54dfb544e3a019a92ab2adbcc30071411ace79f4a039c58fc56ef33e7cf87f65ea9f6e2bd21b0c2f88c43f521ddcc7dfb0739bc70d85c1761aa3e2474a129d0bf16bdb9678254db8d39cfb669bafcf9076899da38a64c3386b319f37431c3a195ca292ee99e5b1082c0fc6eac72075af73c264257ba8733a900244f0fcb3797307b5ef30e644f73466aeae75fa0a2cbde0c12c8ee2386f966fbae9d6c09366e803dc843e02c3b1cc0e09e27f4c7fedd506b18ddd5b67da189dd3134f8a896b2d8272a3e0d38b7195d7b45512157d9b868ea79b8c2f8675a8fc1151947972361caf4629bc8c7700ba977794b1632930ae16b47eb05b6f4bac7d731a36081dc5bf2fb15dde1593a08176bd158787beb7985cd1c49f16084e4c257070f71afbd0a9ae3945644589396585df6deeca13dfd547cc9757a449ccf0785676666ba67db68b608ef89a0935a57f7657ca145911ba7b102c8c54498e03e66e2e1de762a53d5871e707e0404c8d72e87643d6c9db5a2a53bc82c56cf4474ee01fbb08276b103c13d8b1375b46e56659d18d15d135cb339f014e7b713bab7713ec591e10245e175638f4436363739b79c4919c4d68347e74b80a0199311bd7150a246410181817d2194472d302899dcae22aeebb04f8d4d1325feae485c435d5534de05a367cd4ca2292f909982a166e8dc6a2b7f1c93fc02b0b350215d3c9b28cf1758ab0c033f50cdcbd75e44a14cbcfed6488dd8cedf6c3ca1d4f47754f2147d884f7ba102ef5faabcb39fae61c14ad46837db28321eb9d65dd365a879efadef82fb50fc",
"spend_index": [
0,
1,
4101939609,
4294967295
],
"result": [
"b9d8733a838d2cf61fefedbb592286444de3440832fc73d1a1206d7485a9e3d2",
"c48192f629740141e47599ebbb22a0931225689113e0a185f55f33c9d5be87c8",
"68eab01f3ac6ea292425ae8c072fd2a0945bb497aa0f95aeb42e7fc58edcdbd4",
"c8c9e45933f973233075bcd7142e3e74fe8429ce8b41c0b74dc6e6425833eabc"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 10,
"Witness": false,
"Version": 1446712085,
"scriptSigs": true
},
"hex_tx": "15133b5607c2cba0710000000000000000000000000000000000000000000000000000000040609b0700424bc07f98c5d920000000000000000000000000000000000000000000000000000000001cb98a6cfd5501bbb59547dd3d0c1e66b56c839684696ae9d554693f1bc92101826a61a876ab59fc7004b7710186829a8acc20bc161add3ed5edd3ed495ebf0037c66aabf2e6fa0e7b37684735baa980583cf96620e749393a728302b093ffe5611005e4ccada468800b495f8c4bcd638c984824c421ea4d9819b601fa2aa5740aadcf5dc670ff7ead04e1f6814cfb0608cbb8bfa1deb4b2640bb4178498659910b2114184bf9fffca8d82f7b80ed103106376077a28a75c4876713b88bf754679ff1ba05b9582a0b01988943789c7c925c8f418690aa8a7ad3c604ef67a528cc0d7198248b64c0e526c696609eed82875163929fec762220acd0b0956d29e1fc1e28bed792ef5192a099e5ee5265c18f6300c3ed1ccebc47719cacd91cd5760cd23eb5e280a033aa743d5fc01321674dac63a64c5fad5d67c54a4909e02e265600d5b38736275d344b3577af0b1a95a4b2cc58a6ad01821d828f859243f49e3571e0f8600000000000000000000000000000000000000000000000000000000cb7e89001e67dd4e9f07e8e75b61b1ab092976d27b9160d39acb4def7327e6933516af60026fe2e86844b500000000000000000000000000000000000000000000000000000000703a47660011f2a8096bde483d00000000000000000000000000000000000000000000000000000000a1f21b5600e65010bb01c62adb00000000000000000000000000000000000000000000000000000000ad72827680c77e05d377624e4ac98dcd221ea62c147897f9a9ffdc3898c4c572592fb31b46a110428fa3a7f8cf7a6f2abd247275330847d6a3aa164ecfd6e9bd24a8c2dcc8719b6159ac4efdb7f7b551e036bbcdae61c86017c0c716fad801f760cfa1ef8afe3980cd3d8e1b3fdadbe01eb3e13bd628e21f521073feebba0247b45ee586edd13b3083d22d7836000000000000000000000000000000000000000000000000000000003800dca4fdb501bfdd2976bef3a9c3f25be5f591f0557941e9dba9d44de758e3393e564f0396cf2cce34db3f9e74f8455b835925e5472210458f7ea6fd7cf6e7b49a18ab0ed3fef33dd58047f9199d0f17ca8ef0e1711bc2b82cd76e88314f22c71c87d07bf276fefccbacb0a4b5d2ae64b0912efa400740edda8dc5df5e45d422579928423f230a5b84ed0704470a5804707a331918b773a03559bcaa8af9d38544f8b1e515083c6fbbb4f050447841c2be6bae82f8af7997dd36703d418595a47299088d5f7081d24547cc93ac445e4406ba3350b4c7d921a19bf6eb830386f23b7419c19968ae6a8b801d56a8b616843f41d7a14aa8b48a3a7549cb25f91cbe16bf4e8cc1c3928afce289fbf3891c10e3de8f5157c6523af71d5ea32fb14a00d1b3ed6546ceb515c0652171f97efc9f07e493d7cf2b90ff4ff32fe906d4695cb27da5c505d0f30ce50d2b7006a4f7490c44b959663cd23a3b1eadc2d2bc34eca8031474f3790137bbd9585ab386502153ba3c8dc27e7314226d201de0966ec277f67bb6707257284885526ec3b1007f0cdfb7cdfa26d418b396af6667174621bfb3fb62b44a63ced32d591e477996581bef111af87f79a56d23bdc24aa8f70a15318c27d9e6bd0ec87c000217f88d3bda5449272fd5804bcab488cbd3b06ce64b77893f9154f0533e0388e9bf89406cab037a6698c8a97170919b49c99ab04746a196466e4927afa49413dc0e75c0bcff935676a27b1d0b21b5b72336a075c4e518a053d66e210f957420756a6fc5a3ccd603c00481c4e3017305731e1c1b3f21dcecc89e2b7f3ad48198263d0b3c41acd65a879b0e08c2defa57365f778fa539be998fdcb3e71b00318795c3173695014dbf44b31322ba18f581388f57a01f444896e2ccba15d10197fb4b92ebf88a30600c4de35cd5d95fc84268479cd00bbcaea2069e8d628a497a2db2f3fd13b4f3065e138601bc9d3293fc2ab76e69ad43820a8567551c10f1b8bd95deb63f6faaafd03d14188c8876e1a11b12d112f0952ee0646f06ef53b4f5dc7883b65828e08d9fc205502e14603e8b443a1a50b7c76fbc780eb3259513edb6dd031e9eddcdcc67f5b87ba42700c4961ae4862e6ca7fb666fe80c436d3317dc5a761a4913364676739014b0cf6853871cfb26cdcf04c880e57df20e5a63a15b5e0e293eb88953a392262fcc478413f57dabfbe45e33f3c8c09b9758578020c83cc580fff6a11cb3fbab00ed7a0a9d5730060b382759354b1548d366659b5d499a6f995515c42093fdc858b5006c58a80285004c648071de196466ed4c18c428926626c980c30c5f998ef72e53a05dce9a24874c5cdb7866587ef5c65f0b0635213e9a4130dc7acddd6febfd0c760112ead253b9c817292569a6db8dcdc7e907b11691dac626093f998c4442b8d7f55f8e3274b49dffe35a3895800568ecd1f6a3acff582d3dbfad7e315af69b204ce906f7e5d2c76a7a939c7aba20681678de9ca63163971ff46b21eafaa0844e5c62c84d58e9322edc4418967a0b2f4bb68d19383054ef11620778594623f8b0abfea055e3c9384ba15b6a810c2e92b8586fb77bf469412435ab40dd66cfbe958106afef14757caba6e0940d353fe3582a7483422a30bcaa35a9edfdbff8280f6adc10ba940b77daf81b3a6202a7c8893ff04dc0b7e621f4822bd96f08e378840a6a1008b0f64b0b9c2daf75f8a783deba984d3892bf65e99c02ab2f10eec030f74469ca2bc66703a177891aa9d78785f0b159a6d24b97766b806772f188d141f56a50a5d95ff8dde15ae6c2e43e430ca6323ec8384adab59c7c13ab79b3a75e1cefc6d62e98746cc0b35d8889bce1ab448508319e85c55fd0b86a8bcee1c27e5912dee8ae70380adc787b20a7ed4d851c62767ffee4fddc68020be50f2a745e7b2bdf8fc787ff0afbb2984a6828fdde02da107691467a3fc5264e17d1e44cfd9e7f0e4612a2049156f87bb0fde500b3bc2c331e05e0f9b72bae5cfeb27aac51a34ec72bff597700803446e862bc71dbdb2ef4cbbf092bb98c8a0c85036aa2626e84cd2aa596c60c36b98263fc2d9ffc75e93a94bda39f8f46b3bba37c3572e675be8c6ac8f29282e5002dfd857b42715c40eca3f6a01078c4e376cbdf2803bea3067f9232678e696fa03c6e00b552058ae5ffc0b1137f8470a39d0bad15fc63e1962e45b178e8ee73b6e9eab2b442634fbeed3056850a9e2e3cf13d46d5edca466c5ca784311d5b8f6001a7ccb0864edea23c8c5c3c886ed58b64f3d11c07465656b1ae6d5f9d66241799fd27030b0779b1bdc1e4ddfc9c546208de35cffa57a5325c758f9f80ea4d7c06008580a3958410f38606953061938942dcccf8eb748b6d16123c5361a3dd3996b19b8a605d437b70596fc8a2162f94510b5508df825f07f3061033f5813134d9e722952e0cc546cb189349b6bfce54df36711b66e480782e30f46d2a0a6d4f10b623c51aed726514efa70d303c53c8be54bfc1dd8acb76e0529aaefd2dc1775a5cc07f16af88680c40037d362e74207d0114b0556a57e6c5d2ccb4e7d99426078b4d260df66b2c8b02ce0349cf9be23acf2687b50e78f7e6422477b87f9ed1f63b55a7857c508b2adf6aac32e2818322ac12503edbaccac3834f7fb65314cfd183fd7262e459ad68668ad40d0005f0f99d46316b8f2448f1e38011c8bbb2ed3ebe96706bea3629143ce484ebc6756873ef4b1e436a61497e1756522d7530cc143ad7aaf2b5b6cda40bcd97117daf5f7077c6dccf63e330733a05f782e59c5e95b251755454963322eb0ed2446db1232144113abdaec6c0e7df67d4d4cf540564b898fb865fdcd0e3972afff8ac7c0ad6dbef9ce053e5e01fc80dd044351f5c0cf926a53036758f2a03d9561c95874ec698685d97568b137fc706bdd9cb7d63c225aa88a28d120cbcd52411dd144041f2413a3ae274e5111233fe3237fcf0ca8b711291319fe64067492bf87ac8395687a2590fe8a4baf463af8613ce15553a64863e11d3289f80e7ca37a01c95cc9221d26a93210a379c9aab597374417cf63051d5a945ad6f3b269523ab30250244508f2f1459bfc72250882b79c3e649d2a7faf898b915c82548a89de799f8ede390a2448f054007eae584964a7697a52cd9034778db678ae018e47d08effde2a1721c340ebef76f191ffc2211dea913b73fc8fabd74823c6c0d33a7fb0d6f7444efd03a6b5e37dc0ab8de7fab309a642c72ec1972054de15fcddd201c80b9af14b3a555af753dbd117e86fe7f5600c86571d70877321d68a8bd20b76d0c71c91897c142b54460c6982d18547f2a95f0a979368380a5a4111455cd830e36a8ce399cf578b0a54a1581f89fc1fd683503c316b83b0878356c42b7a4f01c3a85963fda197500d1f21f1646c8915800985b1cca2b8ed9e0331cc4db8ca8953810bb76d83e622fd33f03efd5a338f6f1a56d77480caec4ff1038619f78bd86c8e0d5a1272c132376c7d781c8de4d01d0948890425559131755f4d397d37b8fdaa0254b57a804c4ee77b10cc5898ab0c93f808576535deb43a73750af2d63",
"spend_index": [
0,
1,
3610166742,
4294967295
],
"result": [
"a581267570b10d637e1d7b4a663f015e9a74bbfdeab72581ff16e76d8b8c27ff",
"a43d65c972980ad3ab70db2189a1ecc389c33052c22e96002b61be966c644832",
"8d4b10716dd0b940ae288cb38754cf4ad52c821a5be584182cb1fb3a24b747b3",
"bbd663277ecd2f4b7e3aab477f2f440b2b4469184d216dc99a94e71f549b4896"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 9,
"Witness": false,
"Version": 1429618895,
"scriptSigs": false
},
"hex_tx": "cf4036550a1e69583e0000000000000000000000000000000000000000000000000000000053b3ac7c00784308065011639b00000000000000000000000000000000000000000000000000000000231e523800461c627a3e23edf6000000000000000000000000000000000000000000000000000000004c20eb8600fcf2862389a6d9b8000000000000000000000000000000000000000000000000000000007e59aca10059e33d001536c90f00000000000000000000000000000000000000000000000000000000e843c21100cf7d3ad6a01d60d900000000000000000000000000000000000000000000000000000000558d6ac900e06be76a4fa0a26e00000000000000000000000000000000000000000000000000000000530c17a20093edfcdca778c1dd00000000000000000000000000000000000000000000000000000000329aa83b00167d5bf0effecc20000000000000000000000000000000000000000000000000000000003f779f7600c27f2f4be65470c5000000000000000000000000000000000000000000000000000000001d5b9e7e0032eda9a109ef86a95031d0431ac8c79237de2fac720028f16a99c45ecedc6cbafede718180e04c7307479ac3f2f8daad7f99fa08476b49be2c2cf0f455f59ec467f3dbee8cd7443e5bcca8fcad104b67193dbaf24506a3b63207264fcd3ecf49609ffe946b349e529aa8935fbbb34ee04153b044c0b6038d41750dab1a558dd73c833419bf138a08684202495b94182f7b2abdf139bacb177288d20fd574be6eee5dbb2feb90a788e4c7a09b6f50f0aa37ba5439b2b15d0b39d41bf80884bbd943bb60f2bad7a6410a80bd9712e3e20c2fcab17daaf3332cff0e48066f56c87b47280b1119719d8bc26ad2cca7bbbb6609916225e9523e4d6515d826c528cda7d41d46719006b86c448c0be850874ab292a534ad431aef35ffbbaa1f6568b284c003307ada573241f08af8deb6ee1836f5b26fc2934852fb8f1c50c94dcea454299c57d91bc303b22386975f951a5c3181f5c631b11d446d5bedca67e4f5d135cb3fb95d88785eec8edaa5258d4ac6cab78e8e0c2245f4a4dfc393044cf0677832f752042ce6412092700a8367bb83b3ee55a96ef59b9e3eb80131db57ee43d04d6dca1928a958d82a72ab42e0cc74c880161aafe35571887d42bb41b807651bc9115b8a7266b22ce3655962571f05a794528b47f479023e513c9ff51dfc19302a8815774c38a294aa883477bc8ac5672564ee530cfdbfd464ee849750e977baa3d23bfcdae91ee718a51ab671dc195d9180d506b8562167c9478c6b2ffdb0b3984c3ff19f785a10903d7489fce9de8f3b5ae99d2fa7362510154aa066c30d6356386fcf44d985c9a13274036084d743e3143f95f50b5331798f669f9c86e7ed96840d4c881bcc2dcd9b4aa689f61c196f9873ee3c814b00da14edf52b422173c8f7676c1c89763eff57daa598271a24392a2c87ac24abf4ecfd00190952f275499159640c3faf1dc6ffdbdbf3e19d50f132a8cc51fd16a669d8f44b88eb3df1d181513059cd12be4f1c78ff1d4c39ab6fd8be05e9897b33489f1ac730ca61277f2c88e0da172bb35987edca8d4bb8310741afce8dde16fa2092738162561724fbf8e848c31752a86620cc50dba829ccd5698c351fa760dec06b787ae62c45a984252851a97627bdae70c378be540ca590c4947811668128ee312b480a95250807e8bbf26492e7d6517eb0c866cf24d879c83ffa01e96b7bef2be2a1255ad93811b9223ef2699dba5e28870258d43a7d3f2054b96364d50e200c9d2abaa6195593ad62d983e0f0a2d1d9a134bf185cb7808e6680a69091860268803d598ad1b14d1ea096ec63b347fc4f0d026afd93b674e943f44b286bcb5645ebc6ade6c1d0e1665efd0106fc781d2e0d4ca62c3214c04ad0fbf7d5cb84dc4c67d47365911de440ae9ac26ac463eb3f1d940bb9f3e4bc88af8fffb50af763a3887f5b06d4465aa480cd58bf6bd2d246a1fdcd371ecafad2aa8a24b15a0a713d52dbaaefbd984f64c85d6fbf6d936a646bf954f8af97d82893dbc4792ff2d916bf9a68ded2e1d749631ec9355ca968c6c22fc8c2003e9591a84b73be95d8ccb7c17d57898da59b3b5c6e4551ebc17527c352a4066c1ca758285db0a187aa5f6b9cd2a41f53ec1f2cd0774761d869d8bc475dbaa93eb173dd5d2a45d8126cdd4096309576faad4a7b8082500547c1ff8a0e001c0e32cba79d8ddf227c7822aad8d6562a8aecc396578e6fb2308df5096f27622f2628a3fcc8ab76b79ec509138f467581802eadc736690c050a44ba18b0dded1dc036b9883431c824b75d56f9f969de7f28e2bc40cce434303dd8853de7200c633254a7ac883f2ead10fdf386f951b4fd7de6e95374a049706bec917df236028714452552d0b68f2ac3e9551b2b8b40e2f4da0322f8d10a002cd9c686bfe8ba1e2b1b9d702f089f238432a10d7873294a4a299159a3238fb1146910947758d581d37efcb209d1ce30ba921048ab2c988d975f8e62aa513b67512d7e0ab1dfbdd64cb2ef3eb2f3a2a6880ab231db4ff3422b08e64dfcce75a8b66bdf82b5116e4567a8842e91aad3a23a27319b50aae13d6bf67d3c38252ec8e3035c90b6d5bcd5a8e771dd5163c2e8c409a02c1c1191d024b0df3c84d6824d8eb9888dd9dce0783c75483de2ec4a54c30116e1252e960e7cef4468bda28986d27611fc7484f2be55ca461ac1a742898f68f83d4b1d98abb4e45598f9df9065cffd0f3e1b41435591fae56bcfc9a9f88193ea6e74a403ea62ac87459a17e20bc9279a782121162dac972c44bb3637b4c44780c8f43ee51e23c50eff69f4d663af5fdc8e9d2d83542c2136f76c337a031289a40c40d61218d48144756cf728b3666a3c6ce35a74583a4ae814caf9ed0dc8360b02c141a887351baf1a498f2c1e342730484d8f316a7a1f5fa0242538c67e52e8f7be2b27b56527be0c043e9ad1f704c822c28d259a11a0899d950ecc24342f72189f226ac725d568fa016303287e44e499dff0bfe46ff372df241761d90a0d35d54523d31d4a1b5ab842299f87027d9bb612812623bb877801c96e72598d47e449a98806da0a8cebda4aa4ee671b19dd1501eca920b49f1a00f9d91759d5d499d66fac46c1d89b93086e267a54338d9421987f51d690cc273fceb1c621a1ff89c73bd27f88eb6dc6c8f1",
"spend_index": [
0,
1,
3616295423,
4294967295
],
"result": [
"edaea6235b2a50a95096eccf977cd9c6fdee4067c395e52623117f856ba78316",
"1c4306f65455dea78cc6792f876c3c3dda28a8c4e58cd44cfdbf83ddf15eaeb1",
"4f001066595dee1ffb13aed2e36921dde1f9fb7f509c4182d9678ad6a08b4334",
"cae1e737e67d7f80941b39a0e178bad2d0748c8823596d765b7f3450b019210e"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 4,
"Witness": false,
"Version": 228922200,
"scriptSigs": true
},
"hex_tx": "5813a50d095dd52a8c000000000000000000000000000000000000000000000000000000003f68f1b9fd1301fdd5c373efd2d10c9c119c2c6ba1cb5d7338fe6cb30134c56e74ab2840685015dcda105d2f6741a967b13b4f8b18ae5aa566d9f2b96162ce31d1db10e7eecfd2eafd84af25bffb7185925ee8a844a79759ea400783c32abbbddda7a2db2863c1487237ee612147b4ca963bcf386da21d25504770292640a4d630234c79f002bf74d4d37c84c98ea96e4f02f1a3073617636380a34839e83c28982048d29fd0ec11328e1127baff539546f49372e36602695179361fe5d8fa358fed0336aad6a9f9912762fd13b276bf9bb39e5db98a95ecaaec84c18ac52b1331041742ca0d2390c094583311ac565d6383b80dd356b6e3474c76fb41b00b4be83b8accb7417c97256c13ab7c6316a87895e5b8e23dc7e1d5fb81937f85c0308fea00000000000000000000000000000000000000000000000000000000a349c5c529e3b39bb861b27cb85e78c80efbbda5bd41bc7b73245593b76c3ca8cb3ce09825b04010a48efdba5e682f350a76dc61c74b0000000000000000000000000000000000000000000000000000000077521299d1c9a0c7df8c9ae9b0bcf4f64ca1dbf93f769c755b87d72d182fd71da39dbc7c729b23d97f847aa67b046080c9d127b78b99500e5f5aec94abfe8f8cb31734481d30b24287563b8a4758779c8a5fdfc238c5e13530496861355c3d0e0eee0b6981c7ba365a5996d5c79584afe557b2d8c9acbf2e3a1fea1b18ae3f700b5e224ec7775a327116082f6133aadb47645d91dc994ef56393c7d7cacb54e8836d47a314bc8ad81778b1d16662df20c06f709451a4beade694f4ab59b80401890e4c8f8c07795ecf43c6b8e6024bed8824625cefeb15de1965ca64d685000000000000000000000000000000000000000000000000000000004da36e9800b58147fa27f3cdc50000000000000000000000000000000000000000000000000000000043785f350f5e92b8e86564a85247243c37e596200b86c7a059be1aef0000000000000000000000000000000000000000000000000000000003994ec08bc7f6a101e341758c55e5f3a508b6914268a8d97f73e53019048c5a243deed6de204f5675345609dd38b14831eb4f28212ff3171e47d09a54e31ada8c1575c2858f85b18e4c23e0282f1c9130e0bd3fc2dcd42f8642e7333a2589afdeebe42fd11c734dbc07744045b667672843eee4725871dd2e46ec90e3f238178f295edc4e8e0ffb4b342077b88601ccd133ff558bdf313500000000000000000000000000000000000000000000000000000000575e61e2fd340176fc7b02906571efc17bb6adc866e15706dab6b26b57ffa1b78843b585f9d66313ea5c2e46a74eb5edd59fe7795530ee0d98e1635af12a53ba24b5ae140246b746c14bce965a0878a77ec6e77d23d8b57d3ab5ae94733923fd5d75cb5d071f40e5aba7103a120c4f0cbd6acf326a51cbd45195165320d12ad82e240603613c8a1662a116134bfb89d60b2c30f58f044684636e96ad71c48eb95a0252a33853a0ca17d9e20c795ba7968ae6d89f56a9613f5a127edc77a453c4d078c146df95678a2df8d0d00e0e174754828390d8147b84a990147956a16becc9ae4c113a40f7ce62d33ffb31691b87eb5b47a4f48c367affc66a6c88a23a85813f6df5267ef6c4e4d507fd8f3555d9d03e30df1f36f0e970d58d9597652b7730e6d4ded090832d8033e2009bec58d40e179717414074635a58795afc83f451d6b01800000000000000000000000000000000000000000000000000000000ee8aad2efd140188125d5720261c8bde23eca7bbc6c90fbf666b33d2fef90bbf94aa17063904db0dd71981dcb9116cdbdca1b916155fe14ce3c9959e2af9e8a4348f4921b7a220f13c4ca6e7937e0e2991e560277f9930357d86f4ec7087315014fb90aab1fe45ca17ba23f52e52cb1cc5ccce2f5947d1b89eb5682c968fe4ada1f171839e91612a4730915dae8f907bb4f5ac16e030cb67b01c2d67175768800457967731164de2dba58553e5ce7cd6d700bdab8ad5a72f41bf89e42a82618308257e916191034012c70bf2350b731b4686d6a9a8bbf6224013a2b2e17fda8a55c560c18493555f83922a55e4aa9e847e2fe4de1824825f89094f2f2355b4ce819a8075b46a808aa11edee884ab155df2b5f21cccf8b991896de584f7db50156df95300000000000000000000000000000000000000000000000000000000e9d74bb2228f4e510fba6128202c9cb7bdf967ca6a28926ca367f1fc37f3c9984bb3311f8fb50c22bc4fac0412b090b5d4667d73c81e341b829b73715386b56933dc5938bfd028a699df860e772048285343b590d8a5589e0cf8e1b0a3d70ef7dcd59cefaaec33719cf82ba2ac1874dec67a609f572ed71c6c5cedfc2bb692270fa55a928279aa19d4596283f928c06b2ffafc9139d11d130bc8edc304590718e1c7b847f7f0d91eda897d1843c5dc119b75f7376497dd644e0716aefe4e8c8a0fd760c3e51c79a904d7c15ad458cd7c8b9871fb041072d589f1d6ffdce7d204c0f8003774d65b5b87c62916c911ccc93d5dfa5efa66ec894eda669245785c2f9f26de3139c8efd70dd8fc23afd84195e2a8d9939ff747be802e388639786862881ff9f649c058eaa43d59562a71e991e726134a8cb080de0fc8fd9f07d2b64ede78483f462f15538791f907ed941951cf5c503e64924812be59a67ab83b3b2b71167d005702dd1697fe4b3d8659e704e2c7187b851c2b3ac92288dc905c6154f50bf831c20d09bab034a533ee8e622053da5492d2e9567b5958a3b0e22c2505b187bdcbb7822b51dbf2228a9a093fabd7569fc741e554b6107acca2c9b11f9423f561c76866efc95b5575c3af40c67cb1e0d6a66052c87ed3b1651e757efb03bfcd7949fda19443fbe79268748a5936387bfe77db547dde320ea67bac879a2d67e329a8a2763754efd276f70195969d854f26f198f6ff192195ffef5dfc2d9126a68698ef702a5d5e300e7885823760209178671b16ebe4443b3628cf6610f4c4debfe6a10ce2cf1a62dd8e636a3c7da29f7cd8da80083e835d0cbb796846e8745426583425bb2083bb7ad6078397a13e776dff6e4f3cc8949da9b06a83f5228f2cd2b90798058a2636243d7c353d7d60c7cb3fa6bd5e1909e811e25b83715ff21bef61656300c871d91cb50a3d82be69648785cd094ca70ce8766b37f304afd5fe848df15e60f4f3e116fc2dad8b106dd04d8c84c73fc6c51399b6f8baa876e5d0586ab574afe9c573f9b0082641847fa21aa5f0a5cf8389874db7a0752b2d15418c1060a6fb5a72bfa3800bbbbc96473c99b6b3b63d27892da7a5412e15521ac3e26f84b127d82889e152fe5ef50b2ca13d5a0ce805a0f18361aa823c25b7e7aa4b678d59cad74b68007db7ea25e8224ea07b7db0f72d96607805d0239dea20b7e8ef059275f56c2aa92f6b118f159123f76a",
"spend_index": [
0,
1,
708469068,
4294967295
],
"result": [
"7449c7c0e0957bf2329c95151c03eec76ff335d8df4eea3ce509026112f28cf7",
"170aceb5fed624928b1ec575e5456b1988a871de4640540bc21dbcc1d89b4879",
"5eb990a684b48e5fc6cc68aaa7689a53c193b23aa4a57aea52e5087797aef82f",
"ce5d9a1692d85326a4413a9b10d0019fb33b1bd664eb7cd9edde3907728cd105"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 7,
"Witness": false,
"Version": 1849375622,
"scriptSigs": false
},
"hex_tx": "863b3b6e0a1f4e0d7f00000000000000000000000000000000000000000000000000000000cea0a5440066796a3e5d5443f30000000000000000000000000000000000000000000000000000000022779f8400a4ff4c64dfc26ae50000000000000000000000000000000000000000000000000000000017de040100c67c6b7c5c76b2f9000000000000000000000000000000000000000000000000000000003140c06a0087e9bd04201b2092000000000000000000000000000000000000000000000000000000002f4cbded005f9c296bc4afa64f00000000000000000000000000000000000000000000000000000000d32fb30700827eb4860f20b231000000000000000000000000000000000000000000000000000000001996ea7100ac03a6dd337ed31600000000000000000000000000000000000000000000000000000000ec7705cf003fb2d6284bdc38b90000000000000000000000000000000000000000000000000000000017cd1c8500136e3e1a295f06040000000000000000000000000000000000000000000000000000000015f4d5890053381e2b070564ab6e710bdb43c83bf70f7051c2ef7598429146fa2fcb43cec86845c473d5862bfb49ecefdc0cbdf659231669f9aaa562ddacc88743a941e076577a5da974311b3b9687808f9d3812c280e1ede2c6277d3eb3559c6cab90410ef03f2b7abd1ba7cf3da046b8195a0b318fb86f965aa087edbcb2b27b9b187a33b3eebe4647921d1aeb466eba0fdae322d9b23861f6c1d68086377a2a60c92ef33b44063499a1039d02a617f6876435140cccb9c6042d112c6b49b718076b8feae65e665e28ace8ac8941917eb1612a71042d5cb6400f748590fd43424309c8bf3bd45d52f9106406435cfb3e0a2710964cbbfee48b49b25baf0301477bd4244bd6ccce535609ecc6dd12890a63251beb8e092fdd05149322558a2a906b990c5d674c1be436002bb846cbd1a6ab3f8b2f9ee3dccbe0256b676f7cc434cde676ef4aa97850e1ea3fa08f36addc89888fd59500d4c2efe01bf1487723356888486544021057e129432cf3a8b81145baffb2b6b7c59fee655ef0f43269912dedd8595320cf6b0daeb70001dc872343747b50927d61afc5e16407f5fe5e52623b9a22407e0c79fe35ba1ef7cacb457b7e66c838ae3ee3e45a9ccd189b49dc348c9d2ac453fc2ecd4d414848a59ee555ae0461d46aed2078803b7224d380f6254d7e591725db9a5b314562055ef35a7b3c4d791c2d4ee8b60426e4b8b6c413e336f8579e3aa157da4740ff73f935bfad7d9f970f5d88a6f06eee5b6b60bfec3391ebb41ac1f3736123784442a22bd5a15e1d3a61450c3e44e943175c56969346a71cddea0790c8b4e8b51f5e5fc72c6f24dd62ce316e15d51310e1aaed287c4644cd5aff7b8dc20bdcdca63adeddf63ce06b2a213e7f8f867fa5187f50573dadd39b32c8dbd7089b332775873a17d365179c5e5f7aa7f5d4944df978fff7146ef325817dc949933f907ccdc5fd0710fa9337412aa78b9a51e56607b59da97721e128a60c692e021d9659d732eb4f560ddeeafde52301c96f829a9278cf124f0b3492878e49b7c3836bf2fa41e237055c2d1fdbcdd4e4b5e617968e3ae7c48367cd4e6ad75c37b62f6a7a54631aa96ac03bc6264b2157019852dd42785e8c555390e70838e01f87ab86119bde43b60519feb7504c8c1c4b5e643721f80cc712a6efb4df43d64194bb7e6ea8567dcdece0e660c179c8f36ce2e56703f63e16e052c1b7ecb830baf481951510abd5a1494dd6a70118316af13f9b43d8b665546b9fc39c27236396e6cad4677d05b3c7c950da6f3b5c3406e6dc98157c78e1d28f9dc3a8ef12276c173893f0000273acf40e3d89ee11cc018468741154351d436c1da162e9f83577c894fdec48b12c670d12f92ea5f7809ff35bbab7b2370c0ca7524b0f9d01e556d9d0d6f8ca5aa8f044bb82f0362903daf0b56fbc1828d93d18c99f1454f6cd67e8b2e6938a78e0889f67c28bbc8cfa32201e1a3698baedbe3580b75bb0fb0ec87bc284ae0193da658f8a62fc1b695a682279a01e4f3591b0841db404dae69a374cdcb1292cd3f6cf5c30c5ff9ffa13b601d679b856ef86e370171955228c50b5d15e402c078a1b1a04c178caafd7ad885e6779e0c29787860ed55ee6639e8320567329a135b3089ee783b1cfb5252e2bab26a7c3bf40cbe6f7dc856f291d466c14ad7c8dccbea54047dced27aab3cf9369271deb65a3e7fa05a988908de7b93cb9320c2b31a18ed5332722f91be01d3d72db14ceaf8f4f4e8f5fb3501b5522b84f25f025b505fec29617fb575aebe803c8a12e593a9be7165776f717d1e7e5de89a8e79185d1bd691c578e0dfbae04c7d4c7f47267ae773b2de321b9baaebaa23ce5f1f1b76e6de607541cf7dcc00b694aab4ee5ff65d32390b08ed7eefbb9648f4e3c805daada431d6c2ae6bff4ad6920901808648d8a6796e08c0a3db9c2ab0ca99d8ceaa07dd59e2044484d4b4ff9d687e327f8e5f297963325d2917fc58033efb6d1f66339fde905f347a46c908b0a19eb1318b76b2ece20467ec1d32bedceeb7dfaec395bd5b39b34fb7e3d46a69252dbc446754e65c9cd8cbdc1",
"spend_index": [
0,
1,
3358500723,
4294967295
],
"result": [
"a67afbba0065b5896504b0f2e660aed9c45030de3392b04ea3b6eacf74f25c6a",
"0c885fbc0ebda0ac9654aa951a9fe010e8b78d95da3d4b98972f0222d5f2b4d6",
"00776d3c8512073f11d54616b089e5732369bbd5b4935d9a29f3cc80089871a9",
"4e601cc58d1c96b29d4b0306ae89bc29a01a40fa69128aa480bb517952f3af1f"
]
},
{
"desc": {
"Inputs": 7,
"Outputs": 2,
"Witness": false,
"Version": 1798237959,
"scriptSigs": true
},
"hex_tx": "07ef2e6b075ed1430500000000000000000000000000000000000000000000000000000000ff78f49d00cf1131160c6c8a7f0000000000000000000000000000000000000000000000000000000034a318d6d91848af4d612ecf9cfaa2471fdcb5627bfadbdab545df89daef1f672d2814e46b6d15b5ae5b5e56dbe294424e1d8f2c28894ef417e41ae27f9573d4303689f54a333d04b04131ca9f3825fb365399229a0605e361e694c11cb701c2c71ccf5bec7cea486e09f2b710096f90bf5cfa4ef67fa991397cde17e356649f24be45c377294329e9a0f1539fcf230f5bdb8d9a128f9899d418af7889e475e64bb145b472d60e6a6b7fac0b4dbedf3a977df7948ffec09b41397f4cbb8046f27a4dc6ed090aec2c4ebbfe5876ed54cf3d016440fa9597c7f635a94d7cc7945d4bb8359c6d87000000000000000000000000000000000000000000000000000000001fc9da2dfdae014c120bf9bc218f7be58b7067cd4614596f7d58d1ab928fba5b0a21a3e81d8db1f8c89f8db25a72de162b85c34e7dc66923a2926cf8a538d44e6d2172366e619788448f071f201fae4184f990940ed2c51fe7a31b9dad6524ffa22d176b77a4f7e123e575baabaa35ffd4202ea4ef3644c7dc653c970a7f66c1d33a6a18d1b1a01e70b1649276f06cb5b46b2420605926ae5d7601cdbac978301a2d7909ddd43170786b3264fe45f92b89f9870364364aa2963ac5aca174cb652ed2c10b96817359c05ed283cd841b0865d53fe6d8230738f68de6c4f03fb24275d6007fbdfd591305066d1f310ddbc229cab9f7b2c51b850529f56e50a8762feb20787833399cb3c81eb2c917e016ef6476c59cc82f5be77213acd94a9d6465f5d51af9175ca29fe63b323b3febcdd43c2cf6a2129596a9dc8834326a40ac2476cfa29a7c76a0c5ed3c340ed9b531e54ba5bce4fe020216f45cc96675eb1c2790968441b8929c9430b3c56e42871824f4933d221f26ba67c3088bca40be87b86f95508a0f3861621576213069384d58535d8ce783ccbe22e2a9424a74a1f1cac6b4de29aefc8d7785818be5fc302704e8a63c08f0704a213fe8656aa900000000000000000000000000000000000000000000000000000000a7033100fd9e01401bdaeccd7ff2c040bfdb44d1656d0d54b665b2403e59e4912a8c04d60126407bd04224bb6b2fa327496d639c6d788e75e79a51967a27580eb355602f8c73f4a366aa23a5032c5c5f9777669917707eca2406ee9fea402fd0d5b64bf4218ddcdcfd010a6bb00f13c6ce09a05fdec05602636649f3dc4b6bc2b62eb506b3bfdb1e34060892409961e6dcb6263f085fb45af54113f04972eb8b1150d7ada2b6ce814f3e8d5eb5cfb112ef59813bca080496749a3a9ed0d14110acd032381162e13b7fa5fef0d903a90e23f5eb4cac9256f334bfc3fa2508657ad1b247e8f61aabed24f067e90cb64d369e3bd7c637f854945d58a547aeeae1b08bc3765ea8efa65239c7d5f1b2fca37c25a952de38c97224c8c9dd6073fd5c513f3cc69d5b3502855564ffd4340f8d35c763621b0a6f926b9f0f97eeae5f02343192832de354dfaa9e2d78fa6d87bce125df54d15c2b14c52df5b531b33e9fc793451527b4f4a35df5951f0fbc6abbb994871765f8c494fe6d843394bcd54c0f66f172716b7b54505c84d717f129319fd201d51854c191027df094ab07eb6fb6675423a2701f0d6e75c91ff51400000000000000000000000000000000000000000000000000000000bb3ce8dbfd46018d139bc3a62dfceda3d4b32db06baf6edeb1c6121f9a292486a92c060ee0aa0b8858ca8e87c083f3a425bfde773da3e3b639fe454b5f51cbc0fe03dede14118337872031513415ec11804593f83760a290a90e423bca0b99a127f8e6b632700ec71626b1db14ff277d897c7a9a5778edb073e3a3adc45fa91e09ee4ea17e01bcc4cd081679ed54cecdea2dfa1058ed5c948d1c38c4f92e7cacceeb728692bb93a65d3ec0e4f0608f23ba3190d0873667f31364f24409d0b6ff4f61cd20c4126acdb0e5acfcd7fcc1359a30993da1d7c8fac52448b43736b764c12c1684f62ce020dbc325d70bce63fcfb8a3348f29ef1358e04aa4a5076bfaeadfd8646f786ab872617e8259cdbc61f1ac5ffbde8700e10541884ab7ea980d0ba83f53e2c6d97cec6486a8c2d2d8d19056fbeb987220d8e97f25ea08d5ecf0f1cc4d844a48eec48f6058958585e2f04abcb39155700000000000000000000000000000000000000000000000000000000a628b2b8fd3c018097865fcd8fe6470455940a4d67fead20a5a785401ac7c866a95ef9a3772957fbc9365db696d03ad84e51b63cd418f3a08159dc76c7e2859b815429d50cabba3329bf3eb1ae70d3f610328aa7855c9d04a10e79ac916e5789d816c39af09bab264be69819f83b487870ddc2b7378ce083c6a6f925ddb27d4b19b5c693b8da8262e1e392dba31e586f5af636873a3c776e9d454f4d623bc5d6e7567343fbd8be6ddbea50bd1e6d10bc40228d779174789cd26272dbd4b27233d75b32bd1c7bcca3c56f014b9329d3e1edd7001a793f4fd8d0d1b4e78b413fdfe5cf56e992c2d2f02ac71d261c9c31940041d4585d2b0188fbd77250a13c26f3ec0325f245a7744733958eec2cecfb9d9afed1e2a58e4bec4840030e9f3e0c92aeef1f4938c955b46ad14704c2b6a2741cf0606c5d4d0a887db0d355efd681184c37c9f35fdf95ce70f3d4000000000000000000000000000000000000000000000000000000002b11a978fdae01d84f6fa0f47c77d269733927b97b495afe13bd0736173bc108d5a536457cd4393d740d02c208981e9e34805e1ae9799f7fcc970b994e3f2168ae4076c9ee0cadd49cd01e67e3eaf614708413e8e6747a7259553488f005792d3fbbe2cc9e7a4921a4e88739c0cf0c48b322c14daa8a62f7fe1d767ed98ef950dcbfc8e6d3b2912bacd52256e8ee0eb8feb9654e150cdcc63b37501738fa74b8afde3212f0454e274e0c70bfe05db3e5b66fb0a37898339cf842f4069c2b15310e03c7247f0114098a2abd6b3a7b95f74c0d66e5183ef9dcea6cbc76ab811e85a3927e9f1fba24a3edf1733c299ac3e3751d8bef340be63d2bc99a37de7ae4c93473825a8a0e9ccd34add14342fa49b2a4339d82adad9389cdf32914df4df313ef940392eca3dbb26851cc7f633d4c91c18255892d461f96bf3ad9dc20b87782d124b8e9010183a1d662ea87c6390558e30f327e75cb7c02f09cb8ad1b29603fa67fd176b0dbdd37d89898c15d94151d6001ca7467ef8651438fb8d5b69ce346a4a3a9ccc006c55d69fbd80a0956911a5d353858d5d20e161bd2467fc524a70a0121ffe69d6879c3433163b4b268bc144179eaf2c4483a2ac702ff27ef589383cb35c860617e20afba9d9fde90927fce0a9febcad50562c77535a516f0fc46312e7e44b78c04510449c8775834336be170ac6035634ce9bc3fa426caa1a1e21585d5377244d6c0f5b4bce9554359c231ea2d2a44c6371f0030ab2ddde40264ed65b630bb26ea0fa44e22f83347b12f34ddc757476a15809bca3264973795c1ca85c9efbb4ab971b46f283ccd3b31bbbba467d9293ff542a9c047036f63f7999ade74e15afd120060d814ba66d5dd324b5e9840d9c5aa82f2d92c50aaedde60ecfb197d89f803b43f951642ef440a4ce557c119c8b0b3b31396ec5eb2eab3b68bfcb8d87d514e2fa9d99f55bf73b6de4a2c0ae686ac120ecd351950f301d788e9d05a9be5316fb0347de8f8627aeb14222479d9c0935682cb19433ae087e6fa55586b71fec9de2fb3d7fbee0fca4ba677df4f5a058d881e4883956f7e2c8c9a7ff843153d495ce0508d9e86871a75ac58760c9f6ab2ac11d638798eccb3156d869060c00808e8d589a1ecbcf54c6ce2aa41d927a337b4bdb357bcce9262113256a4209f65cd612f679edcd92024eaae80075d703a22027f77627ce71d58210ce6",
"spend_index": [
0,
1,
2916844456,
4294967295
],
"result": [
"283cb2047c37309e829655648b28267b033c1087d81aead63e6ff2d26caf9e8c",
"7010b42b49bdf5cca62e1f8f49362e68f9b88f18f762620cdd8456154b163944",
"02459f32cf304406ee4b0de8526b878e6f8d2106be67ef4e34f8093b3d9f958e",
"e813f4d71c4648851297b59fbd8703ce205c8c1bfea7665e221d94b32525c2f5"
]
},
{
"desc": {
"Inputs": 8,
"Outputs": 8,
"Witness": false,
"Version": 728859774,
"scriptSigs": false
},
"hex_tx": "7e84712b085a8b7c720000000000000000000000000000000000000000000000000000000007339cab0076f4ea875264aae700000000000000000000000000000000000000000000000000000000e03461fe006a66435164c792eb000000000000000000000000000000000000000000000000000000004d3a4d3400183a7cce719da3c700000000000000000000000000000000000000000000000000000000162a98f500813c238d4b9b642f000000000000000000000000000000000000000000000000000000000ada854600e9fb24603d09b8ac000000000000000000000000000000000000000000000000000000009e6175f00071d3837caed637bd000000000000000000000000000000000000000000000000000000007a0ffa3c00eb027ff74d8419250000000000000000000000000000000000000000000000000000000043fa453f005837068f0891a5843d7f2e8411c8bef21df66eac8337d06a1f249cc01b956e0603d06de734ae6a2f1e170de9ad5737895c85f747bb07768d1b0f99669a7dc73b91a4d168bae17dfeac3d2f009cbe51a15460f3b26d88138bafa6ee1644c6df181291e5ac1f3a6b11bde316a01bd69588022485667ca6cd2fc73f6d7aff9d08e63b0a77fa3c2e74670d6d2cf83670e0b7edaa56ea961c1e8d3b9088f480725029e5a85e0db3dc972895698621b988a3af0c76ef806ec8335ee019d158a73ea608899a0b435ac8f288288c3a7151383f76285c5b30981516f91cfdb08ebf4fc8a638d0073680ad2a824cae7e99034b4507d17837196949c1b145183ca9f56ec5450a4df6d077e4e1f3f057660d4ac9db405fefafe0fb966ee668ee6489d97a9643d2b973110adae292a3332767c762fa56001dbe1668a48e77136bfc287ace637c12a701bbe119dc30ec7aace3f84f9ecbdf7fb6881f5fdb21c1a24fd364dbc4428e8ddb353fbc80889baee1c631e79a03ccb4897ed3f8043333eb8afc8adc5cccf00e5cd6d46963cd5b0483b3d1f09415f656714f502945f5c4e83a67259f6083947cae09df3f4c7a74a4871e41dd4fc8b8700b74e4d6ad991c2d1ea6cd6eb7d4df570c73ee21e0c75023d041f4c2599aefb7b82eb364a5fe9de8de77c208a34541ce5a90d37245d57dc1886715a0b038e2e0da44233dbb7b193a8967b53d959da49e1b745e556492cad3563637539e2a19507dc88b73fcbd1d3096ad4076af5b1e93ea376a705e061ac6b5f76f9735d3372e21eb9f9365aa4f620f60b3559f34254ba22e6e363ceb086a59dfe328df23b6a407447e265130ae51f864c0798018c8a2f8a3b8aecd0e51480e69f4dd3179ecfb5152071652f14206b1aeac2b9105c857352501592012cdedfda53a1780257ac8a55d5f2d488e5eea6773c451c1c1799d33a2dd05f4d72fc69419145efe46f27e328952b936babdf3f80b1aa64dc34696664aa5d5bc5cb8894571d3376d937a874357564b4af3040defa9522cbb52053e460b8e1bad794705049e3c15e8f260d4d3577ba8d9e26fcf6624516a549c932b2231a4fa4d99d9274af0ce1ec85fceef43b11113cc20a02147a7c06116f133159bf277163ee2d987575a2e342103b4128520229574a41c75ccf4b0e492aa6355074727921c18be00cb4d8c1e3f503ac86f0d9dced8a28b17613ccaecd59ec3e7425cce0eafa1aa76d6adcda848043e03a9d02a00a17ebaaefbc4d1c9c3b5c34c51a25c4c3e640cb1204c8b30b95d2544913a04bc599f4addda2b652886778bdbbf267b5e5d222828b7fda07a577ee08f21df7c38a89f7c5591f6d49793bb0acdc8ee4006106912351b2c5d76e5fca68f5931cff15be0b2a507f5c936445a6c05b0dd78d5f16e35bafaab2c94ecf6a31e53d62bbdac9dc32c7c6bbc4a6f82b931f874a9741c3465dbe65c126acce73ea19e3e22e968b10650166bef64c7598a35c81029234477d439cdc1cc604a8b9be7a672ef766be533e596b7e596ea75ac33178ab366a8542dddcac4692756da61b552fc12886e915985b8a8ec8e09b1c6bf1af372791e9c920507cbe78476299142d5d85e153e7de3b1c681e57e755d8cdeae628303acde8550c4ec867b7c0c49dd4cab2d917c609914569d598260ab23c489e3eafae99e398b857e55c69e9d782e4668367b0200fe8020a62d3208031f9d70dfd0b2d9f317fc9fc0b1e1f645109e024beb4190b24ca8352e496e990dd665525d5e00b40085467ccb24f2ff00af6c6ec8f57ba2b20dad8c85c24e767b2cd82083607a3f3cd4ebbc8a9b92d0d2c0006c14c9c5ecf26b023330067c581295cb232b157263ae71599d4de8b90ca13a5ab850ccc63499f3f7b6b018965f9daacf5b96c4d735cebbb654b83496891c6969c54e69c9e72eaad85b83df205ecf2ea504ba71c042f1b8497fec95ab33ffb6e7a0fbd68ffaf2274e143f5bb3cfcffc0235259dcc869ba3f6432d7dd6108586063e0646b30e1304c68034a24c69e790e529925fc7aae4a5f575ccb65584d121e7eaf14a70039066d6415adcd31cf3774f8431c851a8e22b0b1ff4b196ead0f96063c78dbf54b5e44b9041c33bbab4d01ae6c2e3667d825abe24f1d4085d43f9a5561e2b605f8109979b760907ab9b894c0ccb6e2e26536d3a835a438c9902b7848347f7789b9ffa73a21ce7709bbea337c0776efbd9302d7d789a8005c4aa1906d17bf93a4ec1dd61caf6c8314504eed98a7e7793fdff2299f1ad78d5a29d26c64a5d815a59a798d6ae86249bfebcd63efd1ab92fc305023bc1babe53119d47ad340fec3d89d7aea2cb1ae92b1fec69b2ee06a6c8aa8d5d5e87e84f2dfc8686",
"spend_index": [
0,
1,
1256674190,
4294967295
],
"result": [
"1cbc2c12a17c62451d2cf36548bd5428bc856da30d5fe599b16743a3b289dfd8",
"0a1fb9e324a3bb5cb702204e1a69660c8b8c1e13240f4d1c28a52c5adcfe3ba9",
"8be86606c28d4cde311a518f44cd47582eae349332b906ed0235a14be33807c2",
"7c1b06f3d2068192342c5b643fa15b9d7b7810934c665afe08c442fa66ac8b96"
]
},
{
"desc": {
"Inputs": 5,
"Outputs": 9,
"Witness": false,
"Version": -374849814,
"scriptSigs": true
},
"hex_tx": "ea3ea8e905240338c6000000000000000000000000000000000000000000000000000000002eabd87700f486a7e201ac6ca600000000000000000000000000000000000000000000000000000000913fb2e9fdb701bf3f99c49e04f63d21a8518a93a4ed96d016189b40cb85d3a5764d2a13a66a38caba68238877a2c7d804bca7979cd40b6fd7849bea3755721b10482855ce2f68436e85cf9a64e3846e69d685ee1e8601ab13e1ff8d72c42bcbaf4023c935c08969b2734e88529540433125e1ff66b31ced3b196cc54b0128170f51dcea554bf15d13de112c6853ce11c379180534afbd747128f6ec49f696f1b2cb6f2384b159f79019a3a9c30a92078110daef12c648fdc75a9efcd04f663e1f42ba2d5c61bbfcfc73b8d111264424346ca055d77ff1e0f6cec83889f5792e78ac7c02566d0d9702185d93394de0cbf7de83f007f65487e8e7f1229e88f75e493790ca05e0304cda49c000ae971d9b34f418a37d7442e84e47348d4c7a6ca83cdbbf429719c4d50c621ad64bda30107a588cc6d82050e9282783bc79cca10fe04505aadbb90f7d071ae3b515e02d94e4e6c19e51df33b2b5f2b940d6df47f0c68d6d595308fad2fad8354a51ceeb8a28606f59d4bb936c94f82ab0add1ae510adb4e4373a17b4f18c2bb77594809137a66107bdae0ca690cb969c4e1f520ce0154c57dee20139b1d12f5ce987be8f5566e17e24354008f55f96da4c43d7b1823f704364bc600000000000000000000000000000000000000000000000000000000243a49d777627f4fc5e826acdd8e81a6c5f1d7d5ca35cc83369f4f1f1f522484315964c12be52fd9b55adb1ba9b8d20546b29c4edb02a1e6cf24dd93e440aa3dc35964e8ed467f2776b3bd26b51125e3c917e84a89c61a0a722352a9acdc6242e712af1ba5a88a3a695c265abe130a9636595e94ae50e30ec8f5f148dff30a3971e6eeb200000000000000000000000000000000000000000000000000000000856c91830037bb2ddf0def03db00000000000000000000000000000000000000000000000000000000c1e25bb4657f10a47dcd64ac85b0037fd99a84d60773e3b9b144061b33f32d5d916c3aa83ca0d22d932d6b06c9eacbc2617370c3e20cf65dfe63451a3ed9f8a72ca6486ab9bb99825d8e1afe7c02098d36fc80e79bd5a9f4bb4561ca5a46478d51da59d81c5539f2b000bbeabf1b09e59f12d005f9071fc88526fc0e9363b11bddbafeaf51e5d948c453d0d14a3feea58f30ca135a3ba3eadfb991d4241c5863ff4ab8cf062a23be20ec8e718a45b3ede10f67c9e31d568782c5a55cb5a38abdf0ca6aa95549563e4774221576fc9949aeb296656b09cc1a00b25b8433702079f51666f796ea9df041377476d18057f16d293114703b604e9ad5fb88bf4443744dea5117601ad991f568d564a183d668c87d4997b5713587ba8473921f86e941e8f1cf3c53a7997c1d0f3a9944cb5dedfa8a563dea7cdae4b886c4daf24b8268ff6771399b747355c8856fce298f7a3078c80f26627780b203b1bb06504de5332d8fc66d9f85b671393eb52d7daedeebdee62c3f7537151d8a0844aaea1013ce7c96c3f39e2e98399efcd11b5408f84bdfc3bab3130fb5a97bbf8f4e720978a7e50e6dc587f6585f01d9e71c8581ae4fdc77d4e49e9f07f612fac5bda8c7d92dbf139e5c6746b3fbd69a5764eab6588e2bd00019e458c57cb9d788afc60d020c46d03574ea012d56587a7b4ea8f94b2059c25e169a14b0c9efb28bf12ba967bc4b36254d0667274264a62b61362f69826327c8cb745842c875c8b9b6f01084a3326f38f10dc155953b1e57ec2206bd468aa408fa0e3a0fa71ef99afef0cf4ef869594cc71eb912a459fe07086f9d138afcc6834444f2509c0803a5cfe88205e9ba266bd75a83b672542b7741cfa7373df23b765c5e16e2a10d6b197c6a0452c4af74191ccf46bafdd0c66e8162719aa9b1a4c56b8cf11678d10fbb0ba3971fbb9cb136c744dd819239957c0c1948634ca0da513de49584b5afb789d8418a1cd5dc92dfe397dedeb11bb92eb4226da232d4ff4cd185d5e429e0b0d351dd28171f959282298ff39726673ec8eb5604005253281915006ea974d8edfea8f128f8ab252ccea01ac3e1cf88740c5a878f764ced73ffa344744ec40f0fdf542821dc79842b1dc5774cc0ac7d901f6577522ab724d9118f636c590f4b4c72341982d46e1dc5ed3ace8e04c186e519a382134fdc98d1cc1b8496c233abe88976e3d748373626b9ead18ec9cdbcce680bce924253fc04eb32374e4f759dda34f4c39ceace35bd417dd3f5c4d07831853d53ad130030e67655ca30de7f46c5ab27e7370b8601cf804bed2b273e0565f086dbb65faac171a24bd34c7ac0ab8449c832c028d50a1639f5d815125ab6c7149c8498fbee4ab67dd7b3caa147700a58096f0520f595aa9f1b407d46f5091ac71a4dbe333eeeeabdedb9d607593332b01bec9e7482811568874145ff42c740956d6ae7e09c96d1de46e0b5542016a909fb46ea77e5c5bf17c1786a7ce9562e6c504106a3daa54d64b1e5513dd2db3087338ecdda2f886ad7cdbfdb795684548a69b4ba4ec83032e446bda170c44a66d8c27f875f4d18261622f82766191fcc6840d9143d8d4fd0ea2b183b2278b8d26638ac0e0b6707fa18db741b7dd779caa001c8177971a9fbde34a2d82dcfd9798f041e037d0b33fbe8642527878a33d97693ffefebbf8b383254bbe19eb91a11b8c05de60adf3a7708bf29d6e82a1310ea6fb9708cb20869cd5c05ef4865d45c919814f4276a0f17da82ae7ce6a63cbf4c37e417c9a77f273bf9b512c4272ade516d36c89b7632fa043981ee2d019dd9b9a2d28cf935235e6cc3a021af1d9cdd40a697d1bf281cf6781c3c1cb5459de2c2a7e8862f802d4080f5ef3820e3bcb75771a3a5746b761ea033a7709dc50d846060ed2b4b88bd345a5cce967fd2c8a7faec14c8ea4e68509fb61843a687745938308fc0ec9cf6e2ed24448a0cf1ed2d5f0266dceb5c48120be5184c04601dab0cbe8b73d790df8384a4f0863b09d2ccdb2cdcbec287739f5406ddabe7de9dee27a0f6ea8c57a5697c9becd9b511040e3dbcb1a8f614a7b750e15f58d25942f0b8a7ad2897f93d5670ba1ee3346ae226dba8df07efaaab4bf77fd995a4c8072c1f89fd37ca1e36a9c503ef73668a1a466b935149dcf79afa4512427f71a8be26c3b054bf11a28c0db7cad86f042447ed8d23038f3e2053aed5e7d90d34efc68b37ca1f6fc8a4f9645ceccb554b3a4c632caf6bb9d1a9b38ebb2054ed731017b4d9af7d8c979c1f2b0380108d2335408ed3e4bf0989888953d71f3b6130ca8a5a5772718abc157ea3e04ba25a8a2161238cb7c21191169c0aa141c9e1ae1fb00e26176460a98d1cc7ebad95a9bd653950a48881a4d297a320827e4400f8c30eaffb7fae3b2b57c021b8c5d5cf560ab3863dfc712ce41aa849b9a24da9d5bda298f4821312ab4e2addf2364cf5d171bfa478224b80a484727e36a5778348c5dc802a127e988ef1c03828f200d991b9fb7c9590f36420c8626d84d36c486f305d84dc1c337ffdd00352b253e1263bb2e4b868446ef6bed02eaae3542daa4af65b48950b57eeb2b17b92031f67a6f69b24d473a28f68dd1077d73b7a23de3c8570f051ec037c5950c03abc86ee5b958e198218ff086485f8444c928f8e5386d02caf99c7cae1ab51f586814eacb85a9024486d489ae76a1b8eee999169963da3945ad8f894477aefef35c8c788448028ab8796e0c0dda90389ecab4f29f56783228bc1e135cc218b31fef04aa8a95b28fb0681a4dd2ef99e7b872b2c9c2d078c88baba73",
"spend_index": [
0,
1,
3216091953,
4294967295
],
"result": [
"51d6788249aeefcbcefa586c698aecb744761d187790a75f86d0b22c09ff17a8",
"a7ac21bac86b38f58f751e9823153b7187131e62012c5ccf09518ccfc3963d78",
"69d12a2eb89f805fa70741c42ac301d5092124760cde28b0cebeeda59525a8cb",
"a588484f0c7e6406bd8873a30f7f23a80e86bd46eec094053e1cec93414496e3"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 4,
"Witness": false,
"Version": -1556642398,
"scriptSigs": false
},
"hex_tx": "a28537a30675c9c29800000000000000000000000000000000000000000000000000000000bfd666c7004444d5dbd688d48f00000000000000000000000000000000000000000000000000000000903fd8e3004d2e132f18d5332e000000000000000000000000000000000000000000000000000000002849a5d2009261d646bfea33db00000000000000000000000000000000000000000000000000000000b0fde66c006f46905fc78dc059000000000000000000000000000000000000000000000000000000002b79037500b3154e35f19922b40000000000000000000000000000000000000000000000000000000082d485b5002e521d82045140d648ee39373ac8826ed82def4c4d580bc5b5d8b27360aa81b08b0b5b3a0b12fa33ff0d4e64e4b70da80c62878bd456bcb877a629cd1db0de8c23d543c6e9981aaaec764e86557c6a2bf9e2de20fbbc6e8f6cd5dd87e8d014969cfa7e3a66f83263fc74cf203335d164e35e16eb868835bb08d430071ce08e8d00986a8bd9c73ffa3b47d9424621df29370c12a63500706f1f8603c18aa4f3baff28bb395f64e1a2d094747fb5134d581b2ee2708136b3964464c9c8347c59b3a6feec739e395978bcda6fcffdf4b6acd48bdf2cc6c838a27ecf20dcbd3fc8a81a6f4c10f8d6a31b3eb0b8998ef66d76193d083ef1c166127b0470457fa0f483f1e8a4eecae4c7ffa2ca403bc3754ccfaf7c6b784feef3af94777fa9ded97d85fdff27c5ef4180f305a5d2cbf3d18832ac182a65b0d008619ef460cef8a322196d8fefea42add04b9177f9d7ed2042d6b196525bdd5eacbfcd8d527ce2a7c75f7670b605af6027c3366199153482ce3885e59bcac2285b907988914e7401ea486c42bb5b1836c61a36ccedf662e4bb3c8145ec702be5101bfa48fd7f2705d40a5b15f61f1e69a5fcffd51df8199824c8418ea0103eca39e3daf6818c4f20118f0c267238843c345676e6d066254243666b5418a651af82814b2f4981246c056f7f8b2d78b6b56759bf04524718ffc679bb7b8e24276ebaf0cf1062f5db3665bd100b5257f59081ef49e136f0d8b87fc9e6f076110f8e4fd9e99818bc806f1576a033574b4a40310342c889cf32d34385c802059a890463cbc02a015d622a2d4056814c2ff2c8889388366c0de79eb6295f19fec73485584b9d6571209df890f0de9a8bb71c895e0013f4fc8b290422b17ba62b24332ff6ab81f2b00379c9df37c80152c490efbfc668069d1db20a79f9d64bdbba39625a64b4faaff402f5abf0f5aec586e982a9e3101bd961007495ce197750faf3bb2867269f9fb96388053af3716268e387fb65f0aca88b22130e49ecdb01591b03ac91dd712878a97b15e250e32fddead53a2fd03e689f72521adf58ebd8a15ebfb6808dcf4c27b9a5a4f9a1e0a028f6033c5f3e47e11e123c8f1717abd0f18bce748b2d6ffd17bee05b092723ea5992a1bd03fa1953ec441c7809739bb744d74768ca8fa65db6c05ca4e3dec59d38b7a9dc285214dc941d",
"spend_index": [
0,
1,
1428324591,
4294967295
],
"result": [
"6128d94d21e16b1667b475e5d1cf8fbace201967b93316cbc29018ba9ad7e1f8",
"991f8bc21b2fd0ecce39835699e395e2da54601d914bd614b944f4a9c0048948",
"edb18e9a94967cd1ff1e7020b301eaedf57a935a5d85e2f4a367d806223060b4",
"720069c30122090c70546a46f3f33306fd7e335b4ad6ddca909017c2971b1dc6"
]
},
{
"desc": {
"Inputs": 10,
"Outputs": 8,
"Witness": false,
"Version": -211459921,
"scriptSigs": true
},
"hex_tx": "af6065f30abc77d8470000000000000000000000000000000000000000000000000000000011e2d273fd66019b1f3f930e765b6da05fe932d2d17a868ce72055ba505d4dd4fccc39a70578d4247dd78d35a9d97b58f396ecdcdd0d7531e8f6699c808778f3ef5c4e1563c0ac1c1566a891faa79a5e806a3094b3f9b8a1ff4e3387c99224e858f46a612c9426e3cf5c8f16b77c8f90ec321419d007959119be97fcc13bfa1ffb59215096f9e2d15c565582302939923764105c0656a06208abc93d7964d5c569300f25ae8ec9252ac39ab27d34d3fb5b6a6e8a2e9ff95665de700f044dd753e265bc9a5763642af033cdf3755729fbbca777f20cbae9cc0e3716370e0c71752344202de90cfd1706b6ef852e3529e7324c978e511d856af731f0dd311011780051f99318108b3c6f1f649fa615c7003632b2f408c0ac56adefb815f0604d96fa9ccacca3430d2de8a747ea002b790acfa0f65327c89587fdbf195141df88d2ee11d303dfd8211a093c358d6edbd8da5614faa095e6ac029f43f51d931be8d97076394e06bc458a0a8250f00640767840d19ec7b4000000000000000000000000000000000000000000000000000000008cf7db67c57e0f1263a92afe95dbba6bbceec4ce7b9c45a7099d125ab36954f11c096d6ec647e97da54eb8f58250ca9efc6b6d051e4895b22272e46881de55fdf21f17ba4e1f6af7f82cf1ffc25461f9d79089bae859d9bc6452d9e2827395b006d1e067e31146ea27f1ae0abf63f03adf2cbd8cdc16e29b80a3126f55b3162c0941b7a7da15124a614721664be4179237c141d4a437afc0ea7c7829a9f180c45a7e43fd1eea7ccfc7df39a7f23962721b8bd9816553c8d2ff41e3af548fd52081515f1da07faf916c80d012e25e96b741be000000000000000000000000000000000000000000000000000000009749e369f3d3f49a059391f2b6064156a8fb478cb02d9b7455214a7ed3b2266564178c116910c0d63b1b6a2e24d25a3f649dc244210b763e2115e2190323e83858df0e87355a5e532a863eb56193d9177e82b04161aefc46a8c6eeefe14ddf8bbec7f5f80dfae3a4f8ff0e91997dae5807c9a1a8e94846bd8e88f268d66f9a7a9b9ea1656156a35aaad8648907a7908b75b7e07027fb761cd35b655b79e09eee0d9ce64ae803a59a7dd51c0e43ddb5e371f3ad30d62616d793b5b1729278f63b5be95cb683b4a96bd88a72ef80df86dafc96603339534f03071091cf8f6344391620dddf45e76a368e9060ee64f127c35c8d8735fe42afdf5862ebce0d9f559c0000000000000000000000000000000000000000000000000000000067c1080f4842480cd397165a7df7778b3423227e2e0f34dad207e5404415136d42828e3daa4bbe78b337d522c29964eec0adae1a0197235edf369c960dfe1da771b1be8879c363d870459be9ef9e29b806b6418be2000000000000000000000000000000000000000000000000000000007e83b03cfd7b01c958574b8b1b7d0eda831bed14027e7b9f8080bb1b82d10133d3afeb736586de324e883462a4e0aa7e7950e97d99800420c2104787970c008c1cd3b8f2ea20605bd22142410d483411f80b1b25c5a83fdc21400f7007bd28643778c517de70362aece62ca15455ef573ecbcecc9318f2d80fe03cb95a489c939337ec2f9006956defdf71aee1bb5beab82615511a6bac509918259bf5c771319718998895ca20481852bd2a2d47701bf2e332fe11669b1ad5667543a4d2bbd6ce4cbbfb15985d3fc410fcc40fa09d8a48a1f18c23b78c22690f12f83d64bb9d3c63b3f566fefa2baba9fe9829339ef461b08f0983ba22ebb1cfea2d3c374e1edae8bfe2c4572f9851010b4b377d1605572611e7d4f01a95def35c9281d62ff267725bc5a5ecba4e814ea1dfa2a9c91ca1bd28222e4edb479885bbae7f7545750da21377d38b18567e438c6b19cf7511913c4713ce0b3e3a0f260e5abad4ad52fa21f05e6257716f73dbec3bab403abe270f2a6fc0d3cc11aacc99abebbed5d16a5a959b9d7b9bf103f8000000000000000000000000000000000000000000000000000000005f047ed0a8b3515e051848eff79b5ac436b6fdc9ce49d79b355ea2605b5c2aa75d69a05cb8f9813e16073917e2337b4ddc81ba597d3e44c47857e1a5d86949c4618ac74a34b92c67e2958ddfcca76990ad5b06b6cc63d9c755842b60a964a702e2fee1fa942625034e14f720f4a5f32b4a5849c71ed0442d7ed76455bf2696706cf2af3b952eb09129316f0e3fdb6d8b2475c3c28d04c5fab15670d97e559a5a68755f73567df8ed51b0b134d2f8d4e8b225ccd42100000000000000000000000000000000000000000000000000000000db5e3ba8fd6f0184e40c4c15b56c4b03440298ebc916c1afddbcd7afd5eccd9dbec4d35d5702096964d1015737af3e1131237925642acb3900dd4e90e45e1554e11231d8714ded299219ef50e9f50e65d99df34cbd648dad1f067116e24eb8f657a49e9cdc3bffc1610355023f24faa112a367cf8d123abd803b79d2f011e406cf38f6b20ccb3107698ad326179bc6564355b0463ebdbb55a935611349c468a32fda87c8f457e2c3df0371cbed5303dfd659c0fc9a4d19ba1c54178a5f63d20ec9c5e01a0e4da9014aca148da4a5e1d399d3ac253424c4f453c573e947a265a4adf92a1d9b96d4f4c22b46544bb0052a5d20d83da6566f3a6bd5ede87bf00565596e3d02e413e830433879fd6988cbc5082851445857da186a451b44f80107d53dc82cc2eead17c478165ebe17d6d12f0318cdf5cebc0596db7d1c342e609cd6e47fca2871a3381d38fac6d27c32af85fc7f6a863a9d98366370ca56180bcbd3f4d8350816a061f4c3f0515d423e7fcfbd0c8c8310d88b2cbacc674aad1d000000000000000000000000000000000000000000000000000000000d1a6eb2000ee4f5a2cc5438f3000000000000000000000000000000000000000000000000000000009fdadccce95aa4d7458f28a041fd4e4a5dbc3cbdc97bc762346628a38daea7f4fd8fc060f7196d510ff0bfadb80f45c10cf33a9175c7382cb05f35f139a38de9a60c2b91ed96c84ba19c1c572ec472419f4ceaff8c6f64dcf0d2f60bc2fd985b9cdef4429284735913ad616fa3fc0ae94dc74e091155d6dcd4052b9c71c9f18fa71bb89050e1d7739cb581b3bbae181fdd5797e42744fcf7ab04893536f57e85cf860cc32c3468293c42fcf2f85c4e0b0b113b5b8e7ca10e6c55082c4ff1ebc37d62c9150f5fe4e173f83aaa5b837180a014e7e05b417a0e19a275114509d7609c612c52edd3629c56f967b1435d3f6f5dd22db269430000000000000000000000000000000000000000000000000000000067f0c87a000548fd6d08a01a56f0c6c32b66c84b3a5b3eb086bbba2a93c64297bb74fec48fe3e51af608cee555c224d9f4f131819f1503ee536720c851ccceed7fe2ccfbac32d6c07fac139366a8f325b434ae9eec25a023d987219e46c7eb13975cb8b0298543a41115b4b448adedad0c868b185664f0410ba6b2bdf27495b4f48fe970386c8a56cadf43897c6f9cb191f9aa26216af54caf15692ec1e6a621ba844b31c8094c8dd9ae6d2aea6bdd7759d0ed0f8d716240e68b18383483f6bac95407fc95912c2c631202689f490ec2ffbd4c8eb9847c34b10f5e218ea9ac7c121d49c807d704f1aaee47235cabfe3ce21dc6d62956c6b944337f5d05b28083a5688fe1a03d2316556488a7d7c22ef7af9a9a5e97947aa45a7cd09fdfc86630e374b51e19f795fa1d0d980d16dd41cc7cf853a024cd1594130a81e4e95edaba49e490cd2c05432f0b7fac41c1dc99296214295a02a0db4dd2b6ce13b32f864b56151304c680e67ac84867034ffbde739a280635bf018eddaf88581c09daf5744ac8ea0a6dfe300aa0c62a0daf596e2854a95af252656a0619777c2e7cb0fa407a2b4e097ca00cef7d454b49aafebc478285b407c8260126f7fc919323ae4b0e014fc14082f5b515fd8d35d40328a0edb6b385e6a6fb3cf900182d351a1ca531528b521ffb34d4384303a8ef5e03632796e8ba5479345b57b3bfe9f7ef03f3c64ea7521c819f91668ad039512e3651b51cd120dd666073f128db33a3a47e66a03f39eaebe93b0069705a4a2af10c907d7aeace015cf20b19988eef8df7f8b780ee61216b84e52234b9e1573f37d0607fa8e9c85e4b03a95b873c611bbcde2b607bbbffbbffa54308297a8033898b7b741dbec07b63bd71875e90cf933fe8a8d62dbccd8461c8d2e13ec493e6f3751c1110400d051c6e0d7fc4afc253512e9b5fab91b957032ec85372fa71eca10dc5c4e2ed7a0ed9b65310dc88648d559a8fed66136b69318e0bc9d5c9ae0b456b2891b76d5fddb89f27c414e3fcccd72fcdbf61dc341b7f29cd39126e001648e350d68b3a6034dc10c43c37f1ba16b77f3b5578b90b79322ee96a72de721e44c02a7cb6ff86f7888469c87d6a04a90b77b422a212b0efe0a17daa58dff7f4e76fef4688a9bf03deb37b8928214a38d7d410c65bece070bebc96ff93671d9777c355e3640187d0c40ec8c90140dcbe2e46778796a6394f8272faed81d304c54bbc9de9a9f7aad973eb067583057cdc18999bb2111de8c9f008d282c26e7e3fff2264f04c066e4138098e70230fdcf47b7c1fed3bd9e593bea4880960cb3d3e89ae00f5b4f2d90e4ae58830da9b6333f3274b314bce2f3143636359e72dec9d81a4c68c07d86f39f2881614137bb65c22341cff4f4fd91fee3c1523af2c716950c8f17657a12188b2587bb9b16fcd232ae6ff25781df9b5a88db9027ecdb7d05cccbce8fddf86a0fbb5acb0d37ca147d5e75648c9f66da2deeb4bc891ff6daedcf5f3cfeb59f07c0903c81c04dc2ef98e4a0131587590db695e8944ba52a189b440bc77f49caa62e4ef258ecf97dee745ef31f3cb905091db896f98c758adafebc5472753cfb9f3de41b07584fe704ae6851ed2890be4b6091175a247397b8f8229144d15da9db16f0c429c7d74cb31e9ebccb6e5ed783d93a70f5f8e5fe027ae1f4361b5f89ec3b5604756935bafa937479dfebcfd66cdd6fb91aed84a76a7781dc1316f2e39879ed975679336172a0372587a289004948de16776e5228236bc6bf737786ded7570dd6b5fc8e030038e0c40eaf9eb94be857c72cb5e2258bbf22ec9f8ac84562ced49783c0a47addd78179e018ee52ea04a4e91c396b9730fe9a9e595dc7ee04ce3e5eed6c85ad367ccf0e0752c7e1b27b810f9d3ab1d4850196ab41258eee0f2e06d39095ca315a0be538f537c2c2a3c61823667ccf22f742f47c9e3273dc0d7fbaa9ec9985a603c523ded78a4bb08538bd30a0c298b838708d6f2f8ce657daa1ed68f75d1f5582f26958cb59a56c0a8b2037f3e568c200020f26ff447e947cb5aa48548a6f64afa7832c860e4bd5b7020b51d6905c8920289d97d67ed1514232c785971ec84b744430bb29a067f75c8f51ebb50f2b704ddc20aa78d1129b50181aafe9e7792c970f4d89f64c91ab37bfd01db691dcd8e86d7cb60df5f628a48a00410a312e11d204d85a3ec4426926ec7a2cf130af3695188fe2ba5a420b85ec441c66db2e0778a2cef4130e3b8aa15edf7952e2d173ddb20291d1e256d1a11d127413ade1f2b46d0c358ff96f53fe87ab86ba777da22603938cae0b3d126e87c0fa3d3e524a3d496825b339cd49fe299edf7fa58c332361ee8f404822789663e60",
"spend_index": [
0,
1,
2180284422,
4294967295
],
"result": [
"83633cbc593700cc311dfb713af1ba7c4ff5d87bdd695e59d184b61a9d7b99b2",
"76c01715ecee5d532795b67fbfabf83b1c853b74f59e0eb440b0320a1479943f",
"152fb1fd8300a8c37f464be40f512db3227cbc20cf51dcf0a2ef919dba0661ee",
"0abaf55540bf9b7dcd307594168e46f95ce3a2602327bf0c88b6322f13d40f2d"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 8,
"Witness": false,
"Version": 1828189183,
"scriptSigs": false
},
"hex_tx": "fff3f76c01395fd8f8000000000000000000000000000000000000000000000000000000001519c49000e4868e7708a5c1dd79df866c6dc814a969c33e937c2dc893dd125471ed68ef3fc99be691e0cceb9896dea9ec51881a15287fa69a6119911f05224d9cabf0aabf953100833e933f5e3d468d0878b6b181214fb58c6e4f7c16e129debe75ee67610444e322841fc8e55c408cabc75089da4e14db69bfeae855623664640347b1945e94fd89e6944bdd7f9ca3238bce1e035d710c6dade4b40ee54000354892f80c4b70cbcbf46dbc74c4c736e15ad3a32662750afaa5b75000da31affc41b3365f72fe6d8c3269bf6cad4f31571c8002de37a217c04a7a243f8358a3253b62c8a4d3382e103651b5320df9f3dd92119fde16ad13f9d1477efe02dcf8ab1aba443a0d18120a8b16b613678deda2dcb2c1fccec0c2b996002bc5b1abc8fd8128747bfb2b8102c16201fd13e5b3407ebadf66ee38ba3f0bffacd2bec490ccededfa969c7f7d633943de9b78722aa8cc06e89b5c29d8d91960584661594c32da7e7b44dc9f6bbd540117c38c10478f3999b61055ae1a02c2e16ddaf7fde74e105c489cd9e4a9b7d851f8e2570e8c460aa917e2f8169f3b752bf0985953d7f0f0aac38967b2a3b912c6a86cfc46e224b97a7bc8de043f87630bc6d21529716a8ad2d3df44535b1c14daed7988866043d598cb569f62646a4c40865d22f52f1046ae609786292f16bc239aae63d691519f50c66375887f609829659f0892f5734c32ef3017ab698755908dd4f43460c934b211fabbd4e1f52f6b13844c14a6a121ac29d8f08a44b0d97dc668103b1a2aa882336723b10f8f9a581a9a29827cbb62865f2227fa900263fd39795a84627146594bf8418644468a9116ff8a7fb54cbfb560cd0a1e9c9fcd52d62b1953fb68e93d9a0bdbac303e3b7a6466cba4afc95a915b62c8e1c7fda4f5f695ae89cd50b2e8aac8f0e2243ec468f64d5132fd717bdf72a4850c10894d4d2c1dd600d4a1dc8fed25556abf767532811bf1c14d6d07a5e6d670fab661ab57c4d63ba389afe43b30c82afad7822afbae6d733ad7c3bf7296c8058f177462c7c1aea72645fdad3ae66977a7dfa994e3d35a7452f69b299444e8bdbdc875804ca99b7bbf28a737968a96377e36ada76af430bbb6dff870d4aedbfb816fdc43ee2ff1fa8c7db35848a547654702238b79e7e465c4deb95fac095e20b464cbfeb8ceba429bdce88668e3a61dc827348fa419592bb5c90f9012221fd5b851f6265b95ae18b378bd9e74079b6a72fc53bcefd1e78202ed5ed47e80e9d292714b63004a30dbd3be47b3eaf0a5f1d697318b656916f7442b19e7230fb0f641a3e6392da8f9de871a1b040735d2216185b99d473a651935527e251c1af6dacdc0128900920c3f58dc99aef811a3b9ae186e3c8f81dba6ac699228ba33f5054cf51e39e33d7021fac120bf50a7ebdf607a438c411ce10a658f62d0a4c1a3a6e6a13d596a543a472e3b255312183dab6ffca11948f43074ecad40400ec69aec64c82a406c74e35fce2ad407552a2127be23ca25c90b547e175a0e0f8f5260082e4581b22c1cd9ebbe985fdb3214e300c84bcab86b77858a456d7d1a794689768f0f9c6043ce0589ba2fb3f28850a16e50f52da7f40cc09dc2881e7bc3400c9bbb0fa59debb3bc8f85eabf43f4be8eb19707af9301b2106ede7ddc1441c0c5189ce0fb1d05a313fdb6fd11e17f288ba2be293e73fe459f631dae97d81f61eb9defeb7edd2e744736b0898accfcc7953ddeb3ac2b6edb7efd059e9c2ac5059ff62da45cb550213e3ad7fe65948e46e314420ec8cdd4f9cc1eb66a4f16c282367d31c47cc8e5fa853d46d236dbec364042f273c4a4754a480e6792475f7eecc6acb94d77c11b37fa96af178d8c09edfb044488492f376072eaa8bf137df8d206a204067d0624f538408fb5b8de11978d09c732ab9991cb67306976934b197337eb241d286997fd8379138270472008299d336056bcaf3e93c0591973db850d1711962771838a4f0d692776bdadd9a7b21537d930fea9bcca7c40407f6230668130b612fc823e29dc4264ba98db789dfb76a416b9261aae0f881e5e31979583a03e76657bc8c510ca6b166abf9c73d12cece1fb098c22e9e2db0b8bc39202121dae0fef7bbb43295bc5d2d4288d3f2ae029a09277743434f10ce0215a7a078b3609769cb125c402b78407b8def9c52c5c9f1c3d0037ec0c320c8435db314b5019a4233ef628441f39d36096b9709a969d2283b51d593d8fb53fb4906e4357b6531e10f087a107b2b89fcdf7ee6a3ceff5bacdd96b87770a449d77e70ff01711a6028155ca51b04ed5b9c78e0d9d5edac9fa742a23182b75a7c82f38ce36e7f61ec8adb3c9fdd071fe6a44dc3b50478f3658",
"spend_index": [
0,
1,
2241195222,
4294967295
],
"result": [
"fbd57d70f59cc8564c04cbe05b90fca6510655e46d14cd7e380c1fd337c258d2",
"7a4eb4ca724c0a4c0213100d9b7c6f930422e4218d35a940165e4cfb3f130658",
"4a9dd17fd4f6f68a122394ae66c695637d7fdb0f49f59edb917806923a25b18e",
"97f3848d984da92ad3baeed4f2ab8757e4a1d645dcd3f437a1a80cffa2d32efe"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 4,
"Witness": false,
"Version": 2138978941,
"scriptSigs": true
},
"hex_tx": "7d3a7e7f0275a01a4e000000000000000000000000000000000000000000000000000000003416da7800a2727c85eeaa277a000000000000000000000000000000000000000000000000000000008a062e10fda4016027218088115c0a566dfd58ef389ae369e7c46ca01fe4478621ad39094e8e827f759536a9688e2810f1f50b23b0ca743fc677c714be50a31362aa94ebf7573ce52a2a486ce518b257bf400444b1cfc1c1d8621ed3de8981607a6048d45ddc8a5fa5633513b71223b99564bc8e22b52a42bdb4152028b2519d82076b168d305cd4f7a10ca47424a397df0a1ad60e55083650578e94f7c76311fc7f4d1527ab119acf44220cbda555aa2859d69ed0fb7c329992ecd4073e0d36c8920310ac693d1cf43f5c5c19234527e6f3da2f0d6e0c953c090ad2e5210cd90bedecec478d7eae037f5454844ad144e3124c4f148bbd62183b67899e11f981464faa2777f7d0a15addc90d8b9f6bef444f0eaa64a6f0593e4646dc79a3c8edf2a1720eb1d0891d0247a3cceddffb4b4523c7c2b6f8dbe5fd9eb258ca0904ec0a35e13f5ac642efb1b3820ea77b2666bc25ffb3167c56b8b7cb96e5ac415aaabc6d581c54185778662bb2386187e41503ca7e410008b09388bf24c47acb10978ad2b3ed941d1a89bf44f5913617c9b3c50edee7fd5d42beecd02790b058554ecc1c1377be1614d0c0bd7d0a3ee217042e6eed7b479cf45dc8caeb0c8d73c63b343fe76f81a9929752d86dd73335f4304466e436508eede269640785aeb08bd513427767918520da622dc83b3fc74ea99f3d61cd073af15c5a6710760800f11b6361f2a25d1b4ab0125736b9a07051bd961663888dd5cfe3a65a79df650c41b8215c2c4c3387c14501a82116ab6e9f7124380c132dfcac494ccfc8cf987f1d7d8751dee86b7af18ba2493c45a12c11ec2737eca80e96123c9a678b73660b706da76a8dd3b3951888425090dddd1849decadac72dd03dc3b4155256d6379f8146a5d1bb1ab9f20d4216c8aa99314a0833dfce4b04ca8fd74855fddfffa01d3b61ea1c01eb63e4ac9bdea80807cc0473d58fbd5ffbff4bf6705766abc6c2b592a4291f84bee8b6659ca92d6652eb8dc625d67198031277a02ad2375d259a1b89c552b9ea8d1dcfe813154a7fffcd7678e4de2b6d4b5302ce3baf756a8692850bb000c987578cec72f7ab8ddb4c9ebaf9ae3dc7c97e84f38e901cf2da028bcca10239bfe568b2c625c3fa4f1b9e3d40bee5a1aabadf9bfc0ff8583eac4a95a81555b1569633744d6c0b09dbd87b9e914293e32a5a6abb57fd24b659c8b9ed62259d489f9115c45fd77e9882ec861c206506b61b7767b2d96baec3b5b68e74d5db478d06d94a5dba60f927f0c4732061f40cb1f8fb15101907687ec0ebf92c1e939f9a57983d036940c1849cbc6db36b3c979cc55cfcae1a7cfc061fba2d86b8606de74298fdbf4fab9d5e521d393ef953803df37ef3f556704055a56dbac8196c83e146a88b9916dcc089656c8fff94f79f30428d008a7a51f6507aced962fe3d3b19fa15b6c8f742e53cd1b4245b6895fad892837077ab9182fba16250fe9602ff83bf1a72f84ea38751b217c8d7f0f45ff0d4561deb9d8468f8a0f08d3547e61e90b7ea92e8f7eeb6456990bc594d013e5096cfe29252f0efef8db29f32f763a30e93cc07f7916cf142d1b1b4c30885f5df6edb2918729b307cc0081bd06f8882fc69fbbde3927fe6e1712fe7f9dc3d3ce845c2232075cea309c7d50d758086bab845ea1d6cd6b985ed7ce426de20275c72e49e64d760da34f38a9858a3896fff020ef7144b3aa2e4e924505a86cda8c9b69a9e43cae6c33e8b21d2a275679f3de01eee64435e060317ea05821daa31d335fa8729305110b2",
"spend_index": [
0,
1,
1305917170,
4294967295
],
"result": [
"fc195d4db6372da39b2c2b11a1b9c848b9940ea4d1c656832ffcc6b8dc1f4103",
"3776d9678ef3b5ded3bbd787a089e370f7cc2cea3b5e1d4c2ce522d954142a61",
"7bc475e72431de33427d3bfd6dfdeb6a23113cc7357003f6f0140bec3ba76142",
"5e7572ecca53b57b4ba9bc5891d9d3ebf6d80b7b37c60c3f834953bd5e2d326e"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 6,
"Witness": false,
"Version": -294915705,
"scriptSigs": false
},
"hex_tx": "87f16bee063b22436400000000000000000000000000000000000000000000000000000000d4a5120400b186c1459b435bb000000000000000000000000000000000000000000000000000000000f766765c00d2f1a611e2a8f5b60000000000000000000000000000000000000000000000000000000039f3b98600d9b00db56c4553c700000000000000000000000000000000000000000000000000000000cebf0e8c00e022321210fada07000000000000000000000000000000000000000000000000000000005d6594bb0040e8dfbdbcdb2f86000000000000000000000000000000000000000000000000000000000af613a3003f6db8ee060be5a9a7e0ee5d57c87486d17ae1ef277ae1ecfb56007e6613f7a589dec0784d04bd12b55b0e807ee2ba79724856c847d1aa26fabddde471a1e31abc2fbf0590353d9e7561e2da2eeaa68514f6e3a289c5aee9806c61680184a1589f75bd2cb596077ab1aa6b03110ae8fa8b8a5fe0fe68caf2c74305c23271b7c221421ba1a8b62a5a3d0865af4b32c2c26956583bb826f65aac3968eb2d4044cff0e32db16506201f0db4a73fd5663c0d8ae9bd8760a64e36427e8b06f3b89278d7f980a982d5291df5ed05e59e6da75f0a51c3caf8834d49327aec670e0ac8bfb3df257f260519cfb4fdadc108cc3db9319420d2685bfabe605a0ccea020d2865d9af14f4e3da06a45023450ead96ba0bf665a5935dd02d6dc5ae778136fd996fcdbd5ec8423b931c4a00f9333863338dd7a4c7d4f432a81f2cb4aef11a2dcfd4f38d1a2fd5c5699a0e2911a378ed992335647c62c1742f781baa9d62f75f1d34061438a6b537038a2eb96ac1994ef21e6ca294558cfed77b43e84d0737b962b6265bdd5264e34e388863087141ee73c37bbdad44a306d6d01202c33684c9846c0ab8672c2ae0dc215fccd47088561c8f5a297ee801a2932ad8f87439ae6dfcc4fb1ec02a895fc38757f2ae2437030cd8d3cf44654ab53a8aae980ba8a2c7f816b4e0ab7b07b9d9d6f1a1cc61c7474e491d4a39e50931456dc194c48cadcd4baa145e2f115497098c40846fe099d852fb62dfff3ae491d6edded0974968418054abcc9205fe70a858a7a0e98f55fecca60aeeae68b9f725ecf643c7362873a56bdcac43cb4fc0785f84719d47bf12ce2bb5576632def2c881f10dba013cad3a3559eed014eecbe9a312bd7d7dcf6e7312de36a3ad310a72a24f12c5ae9e2ea43c8f4a5f7ada4dddebf352c3ce865cab0478783b45be54b36fee788b84e9d13cf229a2ddafdef61b8538636ff0f1e4b9fa2a236ff74608be595941aced141ad1700b30ec1ee709d8692d224ebc67d3fef441ef4e9a8419598086ee01c632f503a068a0ebaff69a50b6bbfc32b72f954cd02348e5f6e67f3cbc7017963238f82292bef830cbc763c1bfc6c8acc3ba5871759c6b2010922bb50cf793f54d0c3c5b59637381fcc03902b29c227881147b9c3f6357c863580058bd483b8a74e1c1c4f53f6ce8e614290cf499d4b74bf68d48c6cc8eec4b2d714a9e9e828207b70fe9830b25a4c40c91715b683ffbb0fdf3c5856cfaec220cbf400ecd80551c69c9b001481b27f54bb2fcd75355bc2046830507c625419eb677dd06cd06b591ed7a388b12b9af78e3f78897aca4b6e7a646a650ffc4a4bb866d758d3fa9da20520e8aa15ea370ad0ceb9e973097467aa22b3d94dddad3d516d873460906f8953e58011b5a08dc5f26bd428d11eab34a871d9249946d58446826f2ffb9fbb93fb020983073c785ea260aa15df12d07fe549d3a7ba96088767eb4c276617b768d86b323d4957c842777560b4533a548f3561643f2b1b7dc1e23ecfdc4152af084d57977571dbdaf3c777b559f65e9e60e794c57314bdf8c8d9a1f75055c40c52ae0fc5d6b9f4355e968d0186b3f9570b69a686f0b7b80c14e7dd188cc59325a9cc35026022c8b9918fa2fff5fd09eae04e4b4a5945e032ccdb72c5fa3e60edc932973dd21fbf48f333f881829d1c1e2752b7f61d4fb063e9735609819e7f373704c629d1fc2ab5fa0323211c6ca6db1fdd2f4fc82084ccc3ba373625b760ede4d89189844aa1639ee46f1e4b97e1f7a4ad73b7",
"spend_index": [
0,
1,
1110732603,
4294967295
],
"result": [
"a76937970d2a6cbb89815985e1c250fe926653d190acf2c89948710cdb0c665a",
"67c0a507a7ab1bdedcd53ed21fea39e218fc0c20881e25df91224c0c86cf5a51",
"28825f9efc56ee11571b204d728ce9c584bea95267e832a673dd2bcfe8323d49",
"065c5a476e658952244105c9a461c8bebadfdc82bfaa8f2149488efd88176e6e"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 5,
"Witness": false,
"Version": 272222305,
"scriptSigs": true
},
"hex_tx": "61c8391009518e09c300000000000000000000000000000000000000000000000000000000453a077a00f5322949e2eda1b3000000000000000000000000000000000000000000000000000000003c8bf33dfac0cf7f4a6b5c1d40b03812966620314f8a6225837a06feb6216fa82036c0ba8d70489215b4616e8aa341aaf83c3662a3a958b76c3f9ae7819a5a22b8fe0d9bd2d2c330c1a7f7fe4b860db1a60a6ac8d4cbf177a87532ef0263570c377183344bdcae19ada6594e012c5731651560342ded3b48b96acdb0c6be50f58169bed868c13c27229dc7a0945fcd7ae1ee00c4d1ab417cba72fbc589b8eb4bc22c020a424488da43cc41eac899d62e01cea5cb30da6c0ae2ba47ad77a60c4bfeba8b5370a0bdccde64835d7918f0d70747d5d2a06309b128e92fb81f4a21af39514a8e37cd11072542d8b3bcb0d20390aefa426d6f3c0b8eb70e012c14e3196442d03c24a58300000000000000000000000000000000000000000000000000000000381b152ffd340117dc059b024bcbeeaab8fdc630ab9c87882eee6f7fc1c8fb78fc2c723119fe5eb3fb7a042add14a3e7014471cd103b9b64b7daf954db237c874f728a74093b08f3dcbc0771238f610bd5a2c1e10561abbb310b0d84d69bc53e95d18e834192a1a855745fcd97ac55ae35c1547d67624fd82ce69d6c8dfe3be57937d97dab84a69509634e32806618585ed7c722350757ce2ba0d8c8d4e20b5de264aacdf368ce4bf0dba4b018c5cd824e44b920978cf36de74aededa0c969175523f7a15257b83a7bf1b51cfe8e5b15a13ea6e8d0de34556e6c3b3f086f589082bf86800f7d2be765d47a6f6ad36b02d04b8b2d2b7ce73e979a2434e3f9855f1d9806b42cd58cc6ab4836ae630885d8a9b69b6dd652b61fe39af0cef3deb8b834376c5350aa2c4014d397f1b21dcf0c3ac025d2e566de0564be350b1c7b62f53b8c1900000000000000000000000000000000000000000000000000000000108c7fe70039110cd93375fc270000000000000000000000000000000000000000000000000000000096c1158fe70940a6a817da0da129ec2b31f8597f593a774f10e9793178dd889a1eb6ea459cc5ba66452c6c360d1b1957be78d17aa782f85b55488b10a4e26cbd0b973589f5fd713f18f2ace2e53b9d5540db88794998a6bc8b0060b85569e0582181fb04fbcd3ebdd5518e4a82101d1158577b57c176131fcab97c5b30941a9f042515cfcb12397c4a12962d655c51757bd3ee7da31cb50716f7e1c2bdbc4e88866149f118085ebb0bf79dc8653464a5c944d994e937f5f06b3888838d67d255b5f77efc1ff73956477d9fd16a2d37736d1b0aacf3c3f4881093fb41d5417b8e2a1f70e64cadde534077e273a5dc435bf61da07800000000000000000000000000000000000000000000000000000000de3a04c3fd1c01d0095f5b3571d99a651bc79ccfc06463aad8e701d70bab6a4ea89cfd3b0a72e02c9e4902c866a9cf6683074d7ef1be4ca9e8838375c3d1776695d02b73acad2f20b4579a4547d0e05f52931411b8b5ac6a00f63d4c9454d12209dc80b25252ec0e2b50034a1822b4b5581166236aca296afbd76ea4644bd17b0a80fb7d101de07067878ede3d179e8039af76cbd89a39274da70b4f02acd1d5762ed99f1f075d7ba53891fe2b81d8e256797f7ec6da5ed472fc02512c5e00987dc3a8241d50b648d0e8ece70fc70f4c04ea6fa039fc7988645ed9072c253a9025207a593a59f462a2e42f2ddee41620d11dc31310e0224c005c19b444ecc78fbe8e256f489352f0e81dd7af6a52cba9560157cf8339e7781829efcceb6f9bb06506aec38fcf18b4cc5ab2000000000000000000000000000000000000000000000000000000002d11889b5761d5011ffef2b4bf421afe3820812f8bb46b0a4caa46255025edc12dbb403834369e4a6a563130a636917fc9255a8f66aeac3ad5a1cb699126dfd8c2e54f0b3dd0ecc43ba66be98e23804f1f46c9874ca7624eb0293ab1c0e20b296c3fd8d10000000000000000000000000000000000000000000000000000000032187b311012248dbd1e7325bd0f5f9ac534e217374b070cd132c88a86000000000000000000000000000000000000000000000000000000006ccfb6db00aac41921057c645006896fa637c88be739c1364acfc641c44095a047f212d9edd51ff417f0cb95e6e5b4bf175cf5bf7f471d8049f19b7472ff0e2fb9ee0212cd22b68b5cd845e5a657604ce44a54f1c9257f55365874ab996feee51d5eb1cbf64e49fcc7a59a2c6ba06f96070090f318c7fc1f8739cad50a557adc405e66136a1fa086fd01a84b11bf783310f791f51288ffb063b14dbfa9a491aa8ab72c36e61e552f468d831aff3a639dac505b07eb9e37ed8e783c7f53f4380b61d3c5d3f931537bd29da2ca65498d719a149b89dbeb6748a42908c15b1535b8d53338c8b098268b7d87cd72b348cbb2e5962575a2443d0c9f3af9aca6b1922c4e89d8629a31676b8e9eb56a1af1f80ab64096c327d8f3b1be930e03fde7b887bebecd8c1ba7b43058502edc1dc41d298338decc8919c254435a8ed69dd1d4dd0aaf042e63fff946d38ed0a5a01e1bdd135e2a9c83d9b1269a10ca5cb4c65f8df4c686e681d27eee6056640ab273e8b5501980287a20e6a68588bfc5362044d2dce957e6b0c77bf7b063fad2678ea20bd10d8191fb81f02d844f696a60e203478b07d7ca753d66b2f81f40b3afd6740a46280725c8ac171dc361857d6e53b3348a4c122d72206f8c045ab87f937ab78654e9f448a39013c808ac58e1fb6b3be406bc53b40d30d7ff0d79a544ee5be60b67213394cc8bb9d086792e03da60208f0647e11706423142306a65a7f2d7f0cf08a402cba8d6ba34caf114ab20cdcf22350424d849a9514ac6ddb96a737be9c01acc919409ad32c74bf2b97d23c68e70917a63d8fa28b87e38f66570281ba2cad85c95477a700a6f6e070ebf0c2b90efd14ac153ecb8d885699a53a98bfa5babf3ce2fffbb744b476590c291643fcd5d8d0a8f2f40c8fdf3bea971cefe5229c5fa5eb00535b57965ef4c0f4a300e8a2f4dbd1d5b128dfd6df48e480f250f68a80b4473cb65dd8001d014f3856592562673ac8877b3d470032122404df93a6d562460cfb33f1919949cb4802987cdb4f1843302b1045602f0b1321082671c854f5b7caf3381f6707dd34809080f01cf999eb62f01efd0157101f62a9a6879d25dd557a3dfbfa7b11af27fc61a4cfb164c3f554db0c421910f9dc06054675ce7615f0b99f5da60fe82d391279854d3566b220f303f49541eeea5b67c997f72f1bb67a42d4e6334c8de11cb2f791a817e05fdb08d812743a7402bce9197e29ebfd9e999de913ca8769bc0e674612c0d567def8c1402f35fab9c6c81edcc03a8f7d975e0e7ab2627e83313e9ce4f9b12d56bafc2b8ce1397d0ad4643e7eec4db82673643e64c5cb833c19c13c0b74c96a4544e1d1cf33fe97f4a374980f4ff2116d582a784c8ebe01e31a31e1192eb78d6140670f9e4480588682e09edcc2ed7f2705305e058bc5d70694b94d3c3a6628abf900cb9a5c7964859535c49cad5fd5d875f8816340b392ae24577128ab5d1c9de7a8425",
"spend_index": [
0,
1,
2869676934,
4294967295
],
"result": [
"ee6b346a4e975ff06aa71b2d00045a53a5e11c31f6e7b3f82f21484bb5cf8566",
"b9057ab45662d92efae0349b7f66fd857fbdeb10cc4ddc98b2f2e51a461fb30c",
"94528b90a2039bc506108d367bbf257a5c06e72fc58fbff1cea4a5ef33e4698b",
"7240f3929afc6c1a7094bcaee7f4d084539b6d454edc2368730a7708d4a7e6db"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 6,
"Witness": false,
"Version": -1826872246,
"scriptSigs": false
},
"hex_tx": "4a241c9302d12365ec00000000000000000000000000000000000000000000000000000000108ebb5200e960a377c5c83a81000000000000000000000000000000000000000000000000000000005a87644600bdf1d4cc060f618f5e1d2e4c43c8fcb5ec9822975995457d6f02f0e9b6922319ce2d3bca0325ce352e7726c00509268931c90b66d7c6daf1d8f664a7087ed8a8597a42df0984e9780618666ad36a9aa691c87c85a5714f3e0364d41eead90b63c1ee77626b3a84a4a7e66e02f68ed431f1a954549064889fb35ca43bd5afb682c4492dfc44c86ef03e4a5aa3eb22e346030de38487ac0095317f36db93c2293157e8d56968ba9761adbac0d411110c30674c4b14ef284cba11187691a72a1ef66c8cb1b58133e458dbe3517be8260cadb1f9b2c4104b6b42626a1322db0cc82b61385816f84cc544277fc53a7cbdbb09d7f65ff6d77159203bcedb0adef81e10c3354091fd7020ebe20bf853bddaf795596ab0c02e70af157d1559013681a7f54d0294877fbcfabe137138be3ef74dd35bdf7af6572d41b4b4b5027a60132b438cb37cb63aa7d2f1ecb6617ebea1cc7b9e7bfa500c647f04d8307a88c4e0537d68e5c6a0fe9980e3d60ba1b84e25043580e9f991d25236edf7cdbe9d57741f3ac9ea35f3583e33e51cd8f479cdc53903491fd3eb390c7decd2e42c11c566e632ffc3180bc7f441243d27c9d083a842c85ff88ae29119d379d894c0480eb9cc793fcc200f9ccb6ab3771be7cf2a54004c46b22be8095cd6b9f4476762581aff09c128298006ebf3ff3cb6a281554dfdb52f8e6ef4b0a1bda1c77b2ccd185e8ca098ffc40cbbbbc41b3a2e5fd3d07d9b3567a008d5c8046ea4213801f1c8f57e1c23ddd04d490f9f38493d1ad2727039676e22359d55633ed1719e5dbbf3fd51b47011b48fef1693f2c10094bf52f87f705c1442f2537daf0ce67a3b1246c5126214ee0bd216e218ae22f94c0fc61b7a21675bc8fa8a38743e483d0faa8261d629c847448d7cd53ebf30c474a83bf7ada56f9b55d6c2d511a7e0c16457bb66ea518379ac91bda11c765ea0e355539d43baec4092855fd8a0f484f50a64087dea748a75a696670b776cb2481f65e2e392b0a35527199f68bea64e78c04306a0451b32a5e59c2a4082050af27e99f447836051265bdc57370f9ec7852f213accfdfefddaab52e8965c94e1fa95658d7a029edb97196c94ef594adbc8b6b1431533aa4b8aa7753d1e5a8088ab64a53c6dada3835279811eb0fa4913b31ed418c8bb5be24e8b315546f8b82c90990f360a4eb000c8b45a5d72bd1d91381c018e12e5101b5fd7f1a13fbb45b003d474406edc7ce34b9a2d593bf7caacc4b52d438ee3d8f00a418accdc2c7344e51688894201410385a7a3948fe15f9ea44423e7c3042928cd367a690afab83af5cd2b890c0d69a2b6118da7af34199b4cc06bd4905715748779b4d7be96467479368b4aff7121308b960388193533612c021c65ea62f2ca0d74ee11cb2680ba25a21eef49adfacaf098ec17a4d5be2c2b451743c5a140b22e28fe96a22903dfcc6a63f1f37be56f8f8880a60aac3ed947a9f4541a830e9023c8769655597205a607c4166c283585036e614ca444cb9878d15a1ae3894da69ebf609d7b2094becac5441150fdf6eddcd24ea6cf4d00002ce72daaa305b8649f55dfa370148976582c3a589a5fe9d7fdb23580172720a23d316cb81a83d83d5b440720a3b6981f774dba3c11dfbdccb31d160f72cd8839b3a67a08bbf4ac144a9c6fb1a7f01a6d4177e50788a0b9a5395882e741ed0c65f717f566b02f9e4c3997f46b0a52c3cbc9809aeec5d55ebac828a21142901f5d9ea10040fb9aab0083fa88a7456c9ea748c698f21d92",
"spend_index": [
0,
1,
575568086,
4294967295
],
"result": [
"5dd5906f251a5a753ba3ef3749f2c31171f4441a800ef9997179d439a81d5410",
"2769f08ead076d90d001028dcad018c11d21d71b70a618cba5dd00787c008507",
"4611f46892da7ef37639e6242550dc7722072b3a20eb1f63ce190d92e92978c5",
"6bd1b98061e20e755f3f82400a850792f9636c4f67984d5657b58bdabcaaf606"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 7,
"Witness": false,
"Version": 1596452751,
"scriptSigs": true
},
"hex_tx": "8fef275f01fe49fdbb000000000000000000000000000000000000000000000000000000003fb453858a65a0959c27b6da7959f75e51d9a20de73c5d5313df615a82bbdd393e1d4be462e6d3f4ac48be4ef5dea637e06fa95aecf8a570547b6fba0ac4756647233c688ff095fd038dbe503e59210b38605f8405b51a469c2afd2766ca8e8437f9eccec71b586eabf524dd35d0acab8378d09d55044730e9572b803429f304f1d21f3a45938c2fdd2806f01f5708219546fa07dc9bc0903817ed4ac886ed3fff82070238dd889d3f39b7855ea48ac42844ca8cf7aaf21fdc2462255a5f3eaa9991c7676f9a606403cca61af4da1f47bdc29ef4b07d664a74bc76a5136f351418a64db6b83340d7fa2c1e9f62b92917295bfb1e5932e7a07e397e374424f62b546ec1a0d2c319aede4e7073c02a8e5fa72feb556bada1d8f3fc6b3a391ce7ad957c92eed821576e428ea72c9d18a3f6bf1e0983910ddb1525e0a9cd3690c78919849487e94c9c203136da237f548a2824fbcf3872f9a885dcf5dcbaa4f979e8054bf9c8440ecc67f709f11801c8b77f53d2bec233401aea58edc418bb52fbeeeb73de750afd6d6991d98ed5526a27ce76e6024173af3b55e9e67c0b7c7328c8a9098af189a472b09894c4a9f43792ff5c6ed92e98152eb79b9d86ba613c7e187201868998e95d92b6bd9f335f68dfc6c84fe654507be9e20e01b262b4c3099c33130e59192181a5dfe82b8d76ac53d0870905e807056c77d753cb0dfc2887973345a676bf0c245e2ccbce2d21f665d461424ee04e7fa3cc97b7bbfb65aa5a03b843cfb14ea058c7abe066ffb9262efbf3460029a59fae824a0421af6642c8276a9ed14c0622944877f3c22b0d7197cad24487fc9fa3c81cb9868224c4141226714bac6b21298fdecdb58d759e7e4af629de124514536827ef1bd153e552e6176da597705e6e9234194e8a28f87be47ec9b4ce9bc07566a7186009a8d0d7d8c2cd475ebbf10814f6e51d2a6a4d1766d977b644275fbd2302505e5ba0bc1228a39c778671c0d4c5bacb822bf1074bfb680182691149dff7187689f92d84f494192302a279cfc369d8e15551558f71ae1afe737a8285bb629c9d91917406bbab845c2869537a9c3c0a550d1ddea96366c817d6130c5e450fbc0352063e9720f80ae4fdf2f1ceedae79d16b3458b75a72bd69ef08d0a110e510d54ae0e52ae44f1ddd510a74ad04f901883615d3bdafbc76d917a10fcdd96bd205fa6b18175ead4db6149b436957f388991defe8a8bd0aa6813d684babd9c6868c180fdc20ba6c7c12d17ae590380a355c7b7e5b8c0bf385c45281ea80e5306c41443eaeeda6bae67432cb606ae1da4aacde09daf6db8f5c034aa9e3fe17b770bf439eb743e7ff68864114e0ca33ab6de41b67119b5ea9c26feeab700eb190d9e94bbbc09eaeb060c89549b3618158a9440d8f51e94f09d0fd542f713b12b2aff73373c48f4348a12944cc486f151d678da06b732ee4da6adae212640075fa692e295b95a042cc4a7643913c08b3872489f0a07b3a008ff943e599501f60d6a60843eef1a7323ca96610bcc77f03f4a36ac0d3e625c515c8803e603362fd76e6d6aead7816636a9dbb15d3684f995a0f9be4b070811f9d7edd8c31f11567e7c9adf35d918a005eb6baf9081590497c1f6f9e882271d1e374d21df74a07c0f136971964f69ce019699a3071efe791ae7aad8cdca4a86709916ec854b57ac31c8b93fe6a824b9793a5d8e4151c07331c8eca48c6fe4b09b56bc42f1fedf9e9def8a0f734d832d6e2cd9b78f049c06d9f26310e536aba69d16efc7aeabc5136414ecda08c0dd8f4725e692243df16e17ddc2acd76c138a02c798ef539c2b048bbfa98692f20659bd1a8bc17f59067ac729c0358af46153b674597a0a2c2f8523f4c21e42198c838a8ef94664c5a4bd691f4af43f7afb570017cf78ec311c148457b780515dc70e9aed0bdc978fd90b74bd75b327a96e0c8bb69871e17e6617b38b3de51b044250b6e4d910fc810cd36d82ec14a9e176946150dd691a40f8f8e52574a9fa78d226bc6a0dbfe4b94f7ed9d3619f4fa8379863e273b569b14dcb4714332de37402f9f0ee5d97a441f9ce5200025286bc6b37ea58ce5dc679f695de3c6ba067eab629365332a28ae02fde53679125b5d93c7f760455cab4582a492374f5555594169b11e6af3799d780f0eda7e88f51949208a6abddd1fa80e3f35636852e68c7bc0b09faa53286a57ab82ce770fdd443e6859f4036da74169d701cb04b37361422635fe1b3b5a7ab26f79d996cdccde795bf000",
"spend_index": [
0,
1,
2439581743,
4294967295
],
"result": [
"0561d3777d16886c59dc321139a81652a2a26d0d3aacc2c8a4395abc2ed72106",
"26743f36d47a4672e1a8ea8830b07602e6b1c678a197671cf8a48c73add9ea5f",
"f196979a9156393464a226205342856f82fcc62abbc261ab8c2946f01acbbbb5",
"41776e4b5ef0612e56e84a77efa8df83a3554d84f4014c4c5df3e1560562a5bb"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 1,
"Witness": false,
"Version": -992228038,
"scriptSigs": false
},
"hex_tx": "3acddbc402bc0caa1000000000000000000000000000000000000000000000000000000000037880d9002373515e48d037ba00000000000000000000000000000000000000000000000000000000fb034aa200a3c107b4017f2ac44961d7e119c8a65a431d1ce4aea903feac3ba4a98980c1867d9db4b80697309cac4d2f756348ffcb8484d8a5eff8c82a5f1a9cab33558e98ef446b0358ca6c6bfdad11a07834e3109b9609d318295ea58cdb80ed4c0e40cd6e994fc58703fbcf603cf966136a3b9ea86531381adacb45f0ad0999346663d732a9313125a821c094cb1a55dfe031c91332853f0ba4ebd62b20ff6e968f7dcb69a128ebb28ca1739c8e799c3a4cada5c9ea33b0c49d6fc3413a82305f8f59b30a6b97b6c11c69e30075abca1248ec560f13fd7b9a66304fd75e",
"spend_index": [
0,
1,
666533160,
4294967295
],
"result": [
"1974f6d3689556f16961d392d2a2bf6665774a95d3991a3c207c2169926ca6b3",
"496674f8a4c0b3b346643d324779120d5be39e88cc3a5d7be38c4616c4653644",
"02c31a6cf436367f5ded051aed47d0965cdbbfb8e14fcec9833f7f0c44e9d035",
"988c1e9159cddabc70e14486dcacfe2ea64cef3aa4d81c2c246ff6600cccf5a6"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 8,
"Witness": false,
"Version": -664652085,
"scriptSigs": true
},
"hex_tx": "cb3662d8027bcbf7f60000000000000000000000000000000000000000000000000000000095016521fd770136bc66af182202911250cee6c5b1038e5b4b853d5efc59c1700253f3585183d380c54f08b805994b8887917f0af61d64decbc672140c8aecbdabe3930ed585851b5590c33497e90c337852b0fad85246907f3a9768cb3b6537630fee802f9dcd4c7fb24001c4108d5c9124c36a8a9ec5ae26396244454237e9e8148a22ea0190054f39da11b8ac77fc13bc0bc6e2097caddd89973a6cc6867b3dfa2bb765337402621db7d6efb80ec92aef6f5f411ff67e5329567a0a2aa1edcea25552eedf2bf26c8cefddfd7ab778beeb540de8423f7cebc89af8d20b148c7657e0ef7993d88a70a6b091695f156d9c097df181de8e01ff636bbf7a8b1e2ea29b5832a6f5af3ef6c80e7e178d23a0b0e51e4a689617b95441c4bd767ac5330717813b1d10413626ed1b77a489aa363573d34fd54f07d1857b98bbe6ca549a5bf55fa412995ea7e8ca13b8aee7082d42f03a073f11eeec959189483c6b2a072f388e0bc126b9fdebf142a67be0b3475514b5fae1e271331d2d5865ef9ed150771547258e1d00000000000000000000000000000000000000000000000000000000b454ae62fd0701e6da317e90912ab6cc63214153758de06c9cdf5d46e3643e61f7dc6d0026123dc1bcd10e37ee3ef44c5f025d4ae537b8e3ab685089cc233d897fb089b2986692e35f22d84591af1a7b3fcc7cb5848f5037c99ae16c07fc99549820dfa158da97773b86fd38061f8324de927217bb7d28000b43303be10aced03637cecb33565cfe11f69b27f247e80e3d3aa1afce145bcb53e5e592c72dbffdd2600bb7f7b27852e6e436bda1224f152ff63e038b72f1fd71f5e53c9f7ab22974ae453505dd48a3c88b526e229417006b12c3796cb5184fb4c1bb0c189ddfc55ca77196bb9a11f00eac4599324cec962100d99a035917a29ea61bbfca5dfbd84a903334c104d2e0b9209085cd7a4b90c7db08e3ec36a15f65a215c8d14435e90a9c908b64ec88b815ed0aa7b2c2d592193acefc7b3e02c8c9908c3718ad2d35d139e1c997ff2f121cc636b1da9e4903fe47de4cede8ec6c08a5e23129562acc8868eecf8642c142fc2b5cf9cbc792a17d58387bf945df6cd136059c191ee1f3f8d8e4aa919c84217e558e9514ac7541997be3e1608ab76700ddf83e9d0abd78af7fa47c167f8ed8f840de5afee83fe0275697e8dc42f2449e07bbaf7f62f560912f05fa91849de6688445c1d07b66019367ad7d5b83d58187c8c93b404bb3024d8e98084cea773e8791e756c87e31323e72908e67e69788368e6cbfda79e3fbc66155deea140059acd53e626f1ff91d9f311fa7656c4a789b0ff413c55b6be5c53032f4ca9ed128e0d58d1b6c55dcdb59f7b90a4e1c4607510d6209a8bf995953138906ab3c2d967a280e4c2811ff57ba4fa0f67035e2bf9024106b1ed612f2009224439b1b2842ffde61deea4b9814bd8a5ff977529a5668afc59eb2763a93e064579cb05ac385181f374bf2d7c18f1c7af3df634251d1e5e3b953d124389982de3245d86a4e9c1946936dd3b55c917bf38a1c8395b056114d065008c8919645852c1e3b8822b3e7f338885b10dc74ab947f53a2f6b380c0b69f4d051dd026db658bc2f022f41ccc25e1da8eb30315033512836dda46c4674e46378d3674ffe8d0746a5a82fc7dc283e636a7d0931e71a59068b45d209bd70640775672388db9f5650b7a71ae0edf65fdd05ac1958fd0327868d569c23d35d400e2fcb784fe12314bd3b1f5338f7d93a26034f60d36208c71e7dd7928da1f0895caa301988e9f86ec972d1e7a12c3bd4b6609f14f704681523b01a25552c4bc77b217c0a7ae0a71f5dd8ce13c46515414c48379c89a114a65357c3dce83608347ef99b062080226368353b2273d3c7f94fa5f5c5cd0df9fd80b05a34f411e949da1850e0a453565fb0890ec10c165a8abf1cdf4606ae66fdebac10174f0ce40cf32f237b145db90b6fd915ad12e4b85077450f59d63f0ee9cb9ee48c777f8357766a70dbb68d2ad2b7ba33cd85c6e3be0a90d561813b82dc114b8d08a04ed742f11715accd1382eea179f73f51de77345a132711d425d6b5bbec08b1d6ff6df487132c7fe9be2c05abfd7f9059584533c503f3ff989e1ffd2bb622af3016f319c18abaf0ac8963163ff3dfaa1b52b50c1d06ee489c99e43aabdde819f6032cd57a0e2979c6a487b57b93a062d19829f55c38a3657b564aedc969184b65ca0b038be1aa54c931b3daf73c421c2ab4a7ec7fa65a1f7141fe97e8876bb1082822ae63d6985d58de4f1454880817c1e2a61eeded0933faa2336cde273b30da047ebc7b34fb802824947b0c1c7c0b133affe55154f88ff9071ceec83f479c1fdba0a4cf30521870191a4118b5d002c4ccfea5f91744b66d8e00ba1c11b208c720ffb77ef03ed229cdefba3facb3cb5ee939c9b1d2a7a0f20c85df17597d69d133466f234276e9fd6d3569ba2a4b2d4fa9d937181567dd2cb352c696a66bf6622f86f4d4a418820f1034f829506b687f62d3b22f225356a873e1caefa8c141d533b28dcc1b41b1aa5304214127e7a95b02d82d0ec6dc7e0b77dac914b59fd29e5ee9ab659067d43ec1972a3ed0f25b7ef70bd6f5e8520f91cf39ffdc2f0cb02a4385a4cedba018500ba734712b6d62356e6495f049c189222ad5063b8028ee2104e6ae32b3519d23a265ac7cb6efdb277763ff9e1dbee1f8789b77cbec15f186a2e55ef28980ee68950c864ee5a9bedabb0e9d38276617d9298c42ef7c62a9b3153db10b0971026fd7ef55570f75d5cfc66ae26d15d3f2b85533da7defff5cf5c892a9d693bc87243c2b385b25eb15f18bd1cab3307ae314bf572467b54957810f6a37b2fc55508e265c9c09d4f129b941a1221df796ff99dbc8a9d1ab46926388a1730c8f701c6c0057a51304796a57a49afe3c95515f126554997d55e1c4102fc068d48a12126e392d9f66a1e1aad2e9a6bb00dda31a787d8875b65d20fde8d5fe2e0618be0207cd6cddf6e18bcac2b9c92debf0c0a05d1f617c8f09569e462c5f5a5f2d4d59ae6bcc229bd8106b12e0694224992f946b944820fc2f2dd747cd20cbe21a68f6b0b79af7ff47a4481a150858bf8e0255393f20e4f06749e2ac0c2f255ea32a5349d4f055c631cea35f8e5fc1c3dd709659cb965c6536cc9d7d6d7b0bb0b215b26f7d530ef742e0d8562eb331db50308d99208b9d5dde4558dc0859cfddbf2be1f6f508b451ddaae6762dafe0c04fcdb7e68badf27540dcb175a1e3f6a6e3851261de8a357482b80af1850d923a16494a290c129c60f9ec0ffd19ea8ea0f97b6af",
"spend_index": [
0,
1,
828453430,
4294967295
],
"result": [
"14223bb95cb5089ace31b5dd2fa54e633b9dd60cbe9622794ac6c7578255aeab",
"797f7aee1d48be9a28fc4f9316e689bb1ef5d309d0ad51a7f44e598fe96fe9d7",
"d9377c0a4b98b538853c775bd335bd2dfa620252880e9eb757f13553e32e6d0e",
"745147cc47733cf8bc8a5a562cbb61e3175f36e679dc61f198f0b6fe3bf3bc6b"
]
},
{
"desc": {
"Inputs": 6,
"Outputs": 1,
"Witness": false,
"Version": -1931027793,
"scriptSigs": false
},
"hex_tx": "afdae68c0620c4e058000000000000000000000000000000000000000000000000000000004f8d2d1e00650104588feead99000000000000000000000000000000000000000000000000000000001ac764b2005f8ef43b135c885b000000000000000000000000000000000000000000000000000000009f440d9a00541c069521d13cd000000000000000000000000000000000000000000000000000000000f6618135006f84fa6b678234430000000000000000000000000000000000000000000000000000000080dd391f00e4d2bd306fba136f00000000000000000000000000000000000000000000000000000000768c6d4d00257affc6013b885e35b58f727dc8b179bb70124ab89e49025858610b85f42f7ee3371540dfcf56395b5cc643d6d11a3ab736b7e4b57a4787665a7a3260fb0b213ada90e0eae735919c031f4774cb907b55ecf41c0fa8e4b6ee17b6a27988ee342d9359a138c0dd6d30f02c5810b1478ac0003f54a635a76028d2e542555072ea3eb1e8e0daed2aac38e4d2202ae2568f2b6ff839df9d1bff6df340d29f5c2f26919478b59cb14efa6fa2379238384974fc913b5471ec00eb97a4213d66d26286dbfa092dac2c2cab41d3a242f3a58374a3b38d4622716840a6d0",
"spend_index": [
0,
1,
3362444138,
4294967295
],
"result": [
"67ab9ace43b9095f407f06235f14dd2f0de435cc176d84ccf7753f09d526a916",
"c8941602c1acf44bc263663f5d24ccdb050d58a0fc6a5a52d3c65e91b7a55768",
"a072439c88ad5d89e8f8ab06b07850788e54ecac24ea2875f025b71ac699db88",
"bbdb0d1a66f26cf1b26885c4a2163f7c4aaa4f9377413a94e5797bf45dd2a5b4"
]
},
{
"desc": {
"Inputs": 9,
"Outputs": 4,
"Witness": false,
"Version": -874883095,
"scriptSigs": true
},
"hex_tx": "e957dacb098545a2a20000000000000000000000000000000000000000000000000000000075fd30694825ebcd8f1e2e8342da01866f2f98334bcd4bcf63bd59af5d4c5e97ae1ee3f745a4d091cf2b4c2028be3d4afade8169a1cbe16f518784a42942cc2716c621f880c89f479fcab98aa39daf8c84e79ba7e200000000000000000000000000000000000000000000000000000000e6b2d11bc0ff4a5aa6810da2dbc4958b61a3f34de17d7bfe136ee243fd1136ea24d03b7fce5d98bce0a82405d8febe95aa7ec484ba72dcd918637687f646e38707a800968d8a96f7b4f6900041b1052a3ece6012706f1efa746fb5d1f8bb870d73eb0ebed1c54e980ddf5479244f7663002c94a83954006e6530e086e14014a1e53b3b8f93213b8a4c5343f337247ddbf471043d976c0fe27ce5fa25a5f3f7a4d1b8b679b179e3bd8075e711a7dd3c0953a673b6c7b14ee99f3dba804cda975bd187714b7f6b44972d68ec8ad400000000000000000000000000000000000000000000000000000000063af4f1009623c5357dae487500000000000000000000000000000000000000000000000000000000c2820587fd9d012809830ed0ee43648113c614a60ec62defa4627c78c4e0f74d2c5fec35e45ede7cd9122c86c2594c32cab8f78a6a2698bbb98f89bda48cc43cad7bf76116296b1f821f3fa60bb9ad18ed76c20d72ad8b62ae4afce66c6613807c1871c5db1c8487b80cc274ac7976a43fcda0c047ed385c853860dc9c8568d490303cbbf66f863ea1e1a621453539388561df7993139eed6a9a0c1d6fa4703aea5a522149d50b7fbe4e4b47bd763a19b1b70b24ba1cdaefadb6aad561ec5de926d8c17c8aeb3796ca3c93e2237025ddbfaacf1813ae29f75608913a183542977fca8f8cd280345cc61abe67a4c5b5e3a9a633330346bd9c6738f6a5e4f8e4f254863676745104a3076e2a3753fcc267ec596a77cbfe303f11f3881f753db96227bf782e8a31960c866b97e92d4a44fcc3af9ab8986ec6598a28ae9db0c222825ed28726ec00a091b536085737904bd01da260453ff9ccbc79a166eb21c4c00a6c0a2f4ab70cd5354abbc89b64adeb1995e2e39246855bbf335c4005b529d65a983f95452c88c299ec05296c53269204990eb481c5040eb1567ff8c132ec54b26ead680b59ad557be911759300000000000000000000000000000000000000000000000000000000c6fb0db0836334fdcb4c67336f070dcc70d24d625c5097c9b99e707776b7c1832b6682909c5daad5b83670510a6bde4d0b86ce0c96b74efdc6226b1a1f83c165afe56dea14455129b8c7fe5bc8de45ec4d77b8b38eee153f2a83fec943f58512c4432b76795b8885fe86cad5bc1bd65b518ae0e699b6c909efed50c6da3352647ef7791e8dbddd0192c01ef12881995e00000000000000000000000000000000000000000000000000000000435021bd00439c012c2bc78a9e00000000000000000000000000000000000000000000000000000000e9f9cabe003d9de2afdbc8746c0000000000000000000000000000000000000000000000000000000024fdd004fd9c01c3fb32ee1feaf1fdc4682dd4ef32de4a67869a89885783b0afa845136886b5f30aaf0241aa02a4815cfe2f7f2cce227a3bb5eb84d79789af7849d47f6230acbe4455231c2ff7ee5a30dc6d169a041a2aa1c3b753296f3b5cc82523a650afdd714404af6db979ef892dd4fbaba72354f30f686873491170ad12740e8b9547420fc5ba34444dbda398115c1fdd5c9284d98ded2d59a4220a2e52a8c954f1d17f150316f80c9d987175c080f8a8edc9a33bbc82413cd9cd8c6eff80875ef196bf0585e9306c348fc140016a99c66506e59109ebfb1a8e0120b3f557efc9915ca78244353d891fbc7e853a28486346834d0f750113bc34bf2c6b4c26e794df2df14778ca1a42ebf35033b8ab0747bf7d1a046dabe6cdc33061092d8aa9c10f6e5c207a84143606523a754405b362a2b3c514291066fc8f6849ca7d5ab9710d6cb5567a54f3f9b574a5f35da31930c5bd1a3b85d76b8cfde87c24357328110ba6c8531926639d65b386ef12b5b9c4acce40049a9f67ebe63a109a24a825354156a5ed403025b2109f6812f1b014eaba101ea6023940e39617279db6d1d762c38a626ca477fe4300000000000000000000000000000000000000000000000000000000d4f9b9e4005e92b09e040dfbac33a2ea2755c8262493bd17e8ba8591a83afa080308cda50b3ae9b5ce8601fb832476635cb38c22f0ced832dfce9179cccb2c47d243c2f0c55091dc7740a25366000618ac960e792cb1aeacb175ba9d3131659e9982f0a4faec22124975c92815cd010e061a04e2714c709dc3cb0555df751d5bf612c36ea45fce6043af9f5792b779c3bff965247d524e64e250d7b456f2767b021ce4949e015cb493e2c611301e8105c927ef3a9ae15b08032212b352d27d8e5a0497c211e5bb7ae996d8069b4fcc999a9c87a25ffad12cb1605658c7e10e2c577c5fc82a506744b0e97ba5e6ba06fb899fa58f761e046136c15715cdcb85c4033a05b326590ba85fb4e6374d425fa0c83069369ec7e4e79ca8a5199a6a5021e3b5b19681e9356e364d5ac65c37b15ca11ae3a69ffc0458a9cec356a29e27fa161d0b4ca746121cb4d8a7fc36c80ad0169fa58a034dd58bbd79683f225137d953e8906c17f8c40f8e61df754871d18e29950621dd33ba886677f8ff42b780f3b1b8e9b762f3d1af1256bc6f5a41cfe78b2b8bb9ec0e7f97b48ae7e645186a101d72f995ada4ac2cb3766a81c4be4ce6143d731bc8615a082a911e3d41523abd1367b455c86a6798c7a0d285c47259cddcd96c9c72e2e1d3858fed2d7d494d2ae56d42d963a767c74b133004b6289a35466609721dfb8c7104d989525af345649b980aa64c2dd2e5b22dff9d75b86ba49c7ee81b2a872ef4ba2ec76a4da4fc73e2448feb0b9f4b2aed0abd7b7d3ab0985b1052f1f1c4354ca63034050a2c440a369f39ec8366fd65edb0aab19907d18f34d573886cbe99e9ffb104136a663dd3b5475f23f1e76ee4f9e28f4b487a6367d336d88b6aba9d2439508a0747863c0f5fbf3d074ac863b7df9fa7cf663b89ad51c2faa53de17fe38f5305dc1097cf1c23cbb33a5e6511a6ffe751415043d4210ce46a79dd6e00cddfcdc785bbddab5c903256c71d5765ff455c8bfe511f0b649a3f8071014f02f03d2c6e14762a1dd45c3d9544a4c9981352038cb08b13bb708fe8a28b4345b4bdb4add8c5efb4953a155484961c6dee57a4e389bec716e8c22e772e48f0545a0d9d3230043d2c3f5e5ea9f70c0a0dde26a2fdba059fd80c276860160ec6afdac9ce9b397c0d25c4ae2cc48a508bc28ebef0abb8e6cb3651211f7c",
"spend_index": [
0,
1,
162187532,
4294967295
],
"result": [
"0b14c77350be266662c94ab6e5f76050b4a0469ea1015aab3cf625bd35068cf8",
"db8732b5313cd230d6009e4ff51699d60a04e4353e591e3cbc3171af44ca5c5e",
"66da7e700214af7983f5b53dbae29faabd2189a67dba51601ca7f11e9d34d5fe",
"3070c3e90d0b5390886a34cb53e241c5a2319460a649a34e529dc26a15d4e1cc"
]
},
{
"desc": {
"Inputs": 1,
"Outputs": 6,
"Witness": false,
"Version": -958545809,
"scriptSigs": false
},
"hex_tx": "6fc0ddc601e38aa54c00000000000000000000000000000000000000000000000000000000873f54f9000d0bbad606fec9a289a0acc269c877da865916769ae8cc62ce89f4ea26e28f9f40bf05b52a829561155aae42e922a1dd18f540c85745c59e58ff76fb3301d098a7ad8634c2aa050cc83beb144bbb01170a4c1bf1ca1ce186433f67826a965ebb65a60358ac6855446dbf18393d22d8b87775031f98103793650ea36e99e9989c3f53490849378abb56fe00bc4330883644377541fc89c42661a8362a6f1693111491319afe1042c8c0b4f72434c2c778f4fb54cecf3ff89e775e817254e95fc04be0c436dc7e25ffd0f004851aba8796c6bf77e54aef1793264784af7739c846243d520b907967e6b3a79a582fecd923914b066718a8232658e7374b45c38473952343e45ba311a05412db5c745f5da4726313d07c0c5a24f773ce47a9d67957c0679f3a42a094d9478ff9ab0a87cce41e65b4af111478e6a7c613508fe6acca9cc4db0685849380a7e83a9796bc7f22eaaad7cb1c21aaac860eb4b653ad4d71b27d6f092059d9899dafe6589dfe571c24819d82e92afe96596900fe5dc48dd6c2d441416347f400e15d1b799727274350a510829755ba0cf1f675bc88e0a3b20a6201b38421bc293a4026bee02778c83f3b19c341f5d93eb71e69e4ebff461c884413a22f30b27c85a981f740e528dafe7a0dc9a5b4fc025bd01916c122946110cf049825032e8e7e758db978b2f66d5e24deaa245ffc2ebacc91f881b7a6843e43ca4b9a41caceb531b948fc74e92f9d457e06915476b1b15f03b7c53ed8f126e9304ee119b7a818ec9d0030d1a37490f7e69c8adc1b39c5c05899c08c28bb6b76c1dafa14a0b7f3fee2accbcbd01e50ab1c3d1eee738a866bf5a79ece5a4c962fd32f3aa20709fd7b45f0beb643ac3ba33480c1d8bc7c6bec514a6d8ec41fc8d88a5e0199abbb814edd7e706530a5a55c260034e081bdee78ebc1a8ce732c3b3ba02d0f5e38b0bbf6cae18794976581bacfc3b9d7d537757a36ab1fa5f4ccc8892160e736d69016ffae3dd8e6cfe5da67316c42ca4bd899d1f5304a830939b68c512c1d8f0a1cc341b538313136077d9205ed88615cc2a7a5c7d2d106e80d77c3f32e73534ef6dadcf5d9e0b87e5842b6fabe4358710ea71942a3489ee69a77027f7b5c053b4254fb6cb7aab584eaf515d469f1e58b707fec1c9f335ce7f04505c5ece43fd8bf944ce0c4b1cc510528c826d016caccfc30cbc87ca721a25cd9e8514b192fc03dac8baa93e61185b61b7d0b3e6adb979716251ee883553076b0653fe2658f9bcfba7c765ce79249a60e44a5aaaf4228f6eaafbf6e5d4a1626bd0e07ec7fab15a7c30bf4cbd1976a8e56baa6918204af3f0766f58041d00819faab5eefef348bb1c1e486429d7ba37c2da29bd6aa21e574242c544eb26ed5ea4c0e8d48e05cdce9f2ead031b2ae8cd46896beb9441b60c332512f5f1ad0bdb71aa52eb7ba6e69e91effd34be469cc4a51a1729e7197750e019616d26bec795e6f66c8572716eb8d8443d7039d7b5a37b53ff73090531e943e95e708b1106b09346f6e17c9b1a1dd8c34c943794299e38723a38119b9b9dc67da4f1bbf8d273251932d8d1fc78a4afcb2e45d59c92fb16c8735f6f370c25edf6e43ae0b72d24ce7b027e5d09778569dfd2e542a9de12d495ee952e4ff98f082c36be41a464425cbd8b14e49a0c23e978d5bb4bf901fd8b82160599cfe2d09bb10c5adcc59c55cfee9502308f4cd1985c615b2a288c5c97e416293e160b328a43cdce05e1d6c1555084761a439a2bd7cd686a5231fd3",
"spend_index": [
0,
1,
3791416821,
4294967295
],
"result": [
"2e5006ac1922ac0c1ba24205e9adad753b39e7b10ada6a0a73caad4626a1535d",
"e3d7d29935fa2dbd398b89c234b3138091ce1c28a384970d745226e973bad9f1",
"c75c2b038cdc9f9af15f6b8a92bafc2369db3c1794354c40860ed783e20bb81e",
"bfe8372f7fdf65775f70a5ad3576192001c460aca3f57eb560facc45ada13f0a"
]
},
{
"desc": {
"Inputs": 3,
"Outputs": 3,
"Witness": false,
"Version": 28001504,
"scriptSigs": true
},
"hex_tx": "e044ab010340fa7ac1000000000000000000000000000000000000000000000000000000007cfa2e5917675ccc65ec2e4f6a5805c9ce83cea2bace928f8d70e25aaca507b0aea1dcfa00000000000000000000000000000000000000000000000000000000e10b5859fdb001877400ea9b1efa85855559c057c74c71e0e5c3959b36aed3f7203cb8bb86d73691348b0963223e8f780cf6347dbb73d0272be706d7a5e4c443e764c6d3a7cf6b477e06d95e49512340bb87a579721db5b7274fae15ee19545dd479a386a87d4a7c7e1d3a488e572e18f30cdf93bf2355945b299140675b3dff9f0ba3cd2ef22cfb2a4eb7d3d80980473310efc821bfe8fa56112ca4ce7994dcb269d4e41c39c118c2e555f89a120dfc2f8e47b7822fa709595f63e48a2e2b4b58bbc1d526f3f42237ee4f4a068c351b3b3e0d05024ca5c7b75a0e2e8cc5fb55177b8ea9a166109ac000515f30a59412be6f33e963d96899d3363ca50ea14ca78ffd6f29d2c78ef195fda6313a3deda1b592a2ce0e0ee4dadb1208f9f99e14078e484578d6fa88d91bcedfacc53b695d175c613b10ef42c5b279249c741b92c525200d52801c50afac12ec1b502f80e14765479af03ec65071cba119b68ba26f65284ae935414cab6667a0b643a44edea4b41bf9f0698e55cbaa9db64bf9b5c1cff02f485c1af6dd7ef0a16d8ca3ee1b1dc4118ffe250bdb113c834c3dddd1800bd55ff81956ea4054eeeed296af81add5f00801f9fdbabc8d29b958e947a6000000000000000000000000000000000000000000000000000000006362e53cfd6b01d40085bb5cb824f485eff1864e3d4749b50a38308fb6e2eee2b8595834b4bd89a33adab0dce1d55a1dad7453e60d4367435478a27d4ec517c6a8f578fb71bb2d6f504ac9d1db3a508cbe07324af806480af1218795faf985b97213f4e24f13acf39790c2a059e4a6e0ded11fd80906e71632cd6fc14708b4d3ec5d9e7e246d80f8c16cb37184c3f5ee897d2313cd103dc8446bac19d46f7835bc84749275f550d6d2b26e0298223898a342d86fd0f2e1025f97f847a11643cf74bd402f9fdfd73955305ffd3e98a60f703700190b676fe2b165b2666135266da41fb878eb02ab4740703594b80e2cd4745deb573b8c24982253709e713c77f1aaf00656623e62855b46449019d2590ef572a22615dcf438450a5321a008f1c82387db66fb4fe7f425811bad034df990724f37afbfdb610e6fabecbfcee59a124c0eccd8887832b739e3312eeb5ef1891ea02a7cc0609feed848548f48573ed5ed4c80e35844feb0f03e795469033fdcbcae946a312603a9d820f3b114ce1bc810c835828e295c467a41651a88e631884f46cfc19231eeb980d8010b9d9990c688280ec250da2cf6b4c80ef26ecccd58d68f38657131641694ac3811a5032dd3eba2867c4b25d837f60941d7bc691b1964e8dfebff94ea0ade2649d53c18a65767a6503b12772d1d7584a6bcd9a25bca845235d12393ba6f147861e79f2d145fd3691d315210d445be9f970d927c1937eb71031d61de998c910c4ab8f02f5489fb50e7f6276261c9da4ff7faaa226acbd24acc021f149d2daaefd15868136187a5eaa35876cac95c239f9ad5badc9d6bc8651d4c17338a92cb88328eb391c887ddbe7b57b7999bfc66f8b88867ac15a618e3f8be4e4dbd10d96872c627cdfe645fc78a38bc0fb087a34266cf5990a764221b1b4ca2ab92d37266cacb0091f8802ccdff63ca4787edfa0ff24df50e2255dc79619bfa756215b3fdb1539730a28c56baae728ebf0b6efe5063f37f2b36fffd185dbd5606657c7f96c2b75e6c8d7014e2cc4c514a4fce5adf7ff4f60f1ba90d9dbd3693cd6b3e86f125bd2aff4ddca60ab72f6afc7392d30ede4470092e83e92ad0cc938e98f8e49bf332eddf4cc50cc84cd0817a24ef5189c0da12a9e572a49a0ceabb6ee7c953a477cb089d597f54a5a873ff6e1e49d6dba7099fdcdaa82054d64cd4f8ef7c282775bafc31cfd435e669d102e7aa1ca7769fdc63e68e51039541eee399f20cf3f5e3a863d3e962a124031dd08a8d8d0043c35903537e03ce98d041dbfda7e679e07e4726f70ce6ceb957b15de5c88a9516ed39598098a21978eed2dcde79b10ae8378b951af7ec9ce672f56a12b2718ce991b2d88694daebab4ba9ed00215d67556d0e3c88164cf8619c812611022f0195843eed22",
"spend_index": [
0,
1,
3820598746,
4294967295
],
"result": [
"a052c1319b824ac2c74620fe9e34b98e7704ff278e29e9d23b412106f23c4cc3",
"df732fdf2991619c2c1c8e5e0cc03dfe12f224259a5fc5578689571566280ca7",
"925ff3fc61a3204a96a40efc87b5c6830a0f1a1791204d12cfca674d0e1f4498",
"4f8f73c50d9fac235513880b77dbeb50cd5a37b9488a6d11828d0fdc49bb63c6"
]
},
{
"desc": {
"Inputs": 2,
"Outputs": 2,
"Witness": false,
"Version": 365301493,
"scriptSigs": false
},
"hex_tx": "f50ec615021d38a93e00000000000000000000000000000000000000000000000000000000f31203eb002037e7ffd9301c6800000000000000000000000000000000000000000000000000000000d3fcbbaa00fb8133f202fa8882e48115c743c8e2d189ebda48f2358eae7232b1cbb268237cb7e56a298523d9d195f916c0ab03156cbaa63861ef45f5e66e1e40125f65e3889722e69b82a4c7c3cdfdc28259beb010c63b43356472e08b36e4872bb15b0a180a47a75d3b17f066b4d0126923f69a28f7daecfc60c523605a4dcbd9bbfe25543744004643f121fa5b1089d4898a920b776d1cfdb466102ed3426eb1202b857420a9dc350a3b2b359dc6e10e0e572fc7492dc2ab4d243e67d7067adc190f8e91158cc691365b374d80801ed126b03f2cd25fd2fc82f63c373c6772503264c8d76efd7523cb2b950a8de0f9be4f3334e335c4aa724a94c273ca23e899633417ba9433f6cb9f33d82fd55e6e5c24c21897821cbe79c7e191a9bd72a108c4f6bc23277e1f3a7ba7a0be9614c6175e64334100785b59386b8e5629d459f72972d8c4b218f3b3eb0786f8f71f8f0a1ec9cac6beb70a778419d03d03909801ad795869a7826b39f682917de9b2791d49951e67f8993956e43ab9bec8e8469ab1de37fc57f3a21ca084a45bd55bb3a9cbe102d47d920ce5cdd4446c801160a41be9601936412d03fe24a54ebf8570",
"spend_index": [
0,
1,
701516357,
4294967295
],
"result": [
"d132f573cccb094cff83da9ef8e921e025c5c1c882c0566feab1b4823cf79563",
"c9bb3447a0d33de729b44d1e6a712e68af64b6c9238d1d824999ead42baf9f67",
"16d589f35d842209bcaed71275bda304a5e486bc962c96b0ad933a169f623ac1",
"0b703dfabbc5645f1840cb2c647a7f991d768e7640fbcf87d1277c580c60ef81"
]
},
"Inserted without comma at end to make diffs cleaner..."
]
================================================
FILE: bip-0119/vectors/tx_invalid.json
================================================
[
["The following are deserialized transactions which are invalid."],
["They are in the form"],
["[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],"],
["serializedTransaction, verifyFlags, [{\"if_unset\": [\"flag A\", ...], \"then_unset\": [\"flag X\", ...]}]?]"],
["Use BADTX for verifyFlags if it is expected to fail CheckTransaction()"],
["Objects that are only a single string (like this one) are ignored"],
["CheckTemplateVerify (CTV) Tests"],
["Modified Segwit OP_CTV Spend Failed if Amount Mutated"],
[[["10bf165531fbdfac386f018d92d72dce3ad73af1f183f6fac2c7a2a1050aa51b",
0,
"0x00 0x20 0x9e650578b4f13cde08d16211f3635239e22ba3e108ba7f5fa4bd6c12f8c8219a",
155000]],
"020000000001011ba50a05a1a2c7c2faf683f1f13ad73ace2dd7928d016f38acdffb315516bf100000000000000000000ae90300000000000017a9142b697af70a75926b158a2ea0aab8054eb18490ac87d00700000000000017a9143177919dae74db1c4cd3e6e69861091c6aee9eb287b80b00000000000017a91417d751e7c17c8264e90e4831fed9c47804b2bbc887a00f00000000000017a914a46167b1fbca936b56dda9710a0c16a53fd32fe687881300000000000017a914b4a5ddbdda32760d1c61dd131007fd7e67d650e187701700000000000017a91480909aab0729614b1162d86563cbfb0c71d5bc9e87581b00000000000017a914997c99e26f67463a1f9770003f90603360408bed87401f00000000000017a9149fef27cd2e724889aa522ac6b5eb35de7582727487282300000000000017a914c7c616d8323c7046de863e2301ec0c7884626e9687102700000000000017a914b590ca292351b64cbf725bad01c3ba6da808ab0b870122200a2891d90df11c7714549c76b80b29c86d544110d958a6dabcfcd5cda1612427b300000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,WITNESS,P2SH"],
["Modified Segwit OP_CTV Spend Failed if # inputs Mutated"],
[[["7438c73c9a554540dce173b485e888683e9ae5beae3ae94142e77ae2cc024e3c",
0,
"0x00 0x20 0xc19287614d027e87b85ace418cb0fc2d89241392370f0f7cf2ebb06b861c85f0",
155000],
["24040d2cd61f2ecb67e9fe5634c1d90e59b6b16028ff03003cf20f398ce27e44",
0,
"1",
155000]],
"020000000001023c4e02cce27ae74241e93aaebee59a3e6888e885b473e1dc4045559a3cc73874000000000000000000447ee28c390ff23c0003ff2860b1b6590ed9c13456fee967cb2e1fd62c0d04240000000000000000000ae90300000000000017a91406651b0a47731127630ccc27d07fb9afc041846987d00700000000000017a914c758d7ce652d5ed562253ed00e9afc34ea1f76bf87b80b00000000000017a914fe8740b477b23838679c7eaa6e452e66c58a72bc87a00f00000000000017a914cc07d98fc32e2ff65f62076f2824d63bd5a1628787881300000000000017a914acfb84e8356788c7a8312194d1833e5d5677d58e87701700000000000017a91409aad9fbb6609e4486fa5b04afbbde40659388f787581b00000000000017a914ffd3dc8f12ebb700dd45a6a58914347533b6728587401f00000000000017a914781456255e72a09dfab2211dc151165c62ab7af987282300000000000017a914ee01dfa11feb2bc68b22d6909052647c8c001ec787102700000000000017a9145dd4e76cb2cef90e09f181c55fdc42717f3d948787012220cf100c0bb5dc85c104d87c31e7b57a4a7791cc2091dc87ddaac40c91edda7f6bb30000000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,WITNESS,P2SH"],
["Wrong Size CTV Argument is Discouraged"],
[[["13e313be0d1eab290bcf2b58f4ad76c3f4fd46b2ac4273c607cdc7f5a4170794",
0,
"0x00 0x20 0xaeba7cb39e708a34dd186698a80cc34e70bb92921a01f853ac691bb572b52d62",
155000]],
"02000000000101940717a4f5c7cd07c67342acb246fdf4c376adf4582bcf0b29ab1e0dbe13e3130000000000000000000ae90300000000000017a914f0ccedba146f6390e5961b2a0a39cfba046c312987d00700000000000017a91458d4792223eebb552801d6690b5985513fbddaca87b80b00000000000017a914774b6fe872b65890c610ec6edda928703fe8503e87a00f00000000000017a9148ad37662e56b5f2e472e4bdc205f0dcde8708fd787881300000000000017a9149e8680d850f172186f4e16cee442f0d0121fd46e87701700000000000017a9141394792d48889f70878ce2ee3b151de33d4b774987581b00000000000017a9142444dbb85cf5dfa3e94d2a970a4d4bb795495df687401f00000000000017a914b0437ba6b526e697e695d4f8a53482d26547b64f87282300000000000017a91408ceb5466bc28db2122f954ca59d4a4a08fc133b87102700000000000017a91486f51c990634abc769d6d9d01608ff99f93b050387010251b300000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,WITNESS,P2SH,DISCOURAGE_UPGRADABLE_NOPS", [
{
"if_unset":["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset":["DISCOURAGE_UPGRADABLE_NOPS"]
}
]],
["Empty Stack is Rejected for CTV"],
[[["e658e5b94eba5931faf2379a61a75a05b153648690527d35f7143bed462a6ebc",
0,
"0x00 0x20 0x6c9cc4747e7d287ac1abf8c65152a78d369213583e306b7d3163e12c561abaa2",
155000]],
"02000000000101bc6e2a46ed3b14f7357d5290866453b1055aa7619a37f2fa3159ba4eb9e558e60000000000000000000ae90300000000000017a914b038d0ca030a6d6bc4a06bda13ae1413ce96f37e87d00700000000000017a914fa5716162fb8f5f3cafdce1c1f5533e182c83f4d87b80b00000000000017a91417d10dea89621354333f4dfcbdafe18ec6a794da87a00f00000000000017a9142abb09f63aaecdfbe0e92fedc0afedf19194360187881300000000000017a914aab8b0219014272348de62cbc195e20151b7735787701700000000000017a914a507b83449359c82a195fc9bab99fa1b7c8289eb87581b00000000000017a91401ea6e7336fb9d5e5f36994eecade840ba938d0687401f00000000000017a914e5a474adbd25d66bb70c9b0b6a27f3eebf70b3f587282300000000000017a914d4ae33b227632cf0434f054782558baf9aa6e42d87102700000000000017a9147e4cca8f6c63cb7a56dd3c6edd2acbd031813de9870106b3746375685100000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,WITNESS,P2SH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["Wrong Size Stack Argument is Discouraged for CTV"],
[[["e658e5b94eba5931faf2379a61a75a05b153648690527d35f7143bed462a6ebc",
0,
"0x00 0x20 0x6c9cc4747e7d287ac1abf8c65152a78d369213583e306b7d3163e12c561abaa2",
155000]],
"02000000000101bc6e2a46ed3b14f7357d5290866453b1055aa7619a37f2fa3159ba4eb9e558e60000000000000000000ae90300000000000017a914b038d0ca030a6d6bc4a06bda13ae1413ce96f37e87d00700000000000017a914fa5716162fb8f5f3cafdce1c1f5533e182c83f4d87b80b00000000000017a91417d10dea89621354333f4dfcbdafe18ec6a794da87a00f00000000000017a9142abb09f63aaecdfbe0e92fedc0afedf19194360187881300000000000017a914aab8b0219014272348de62cbc195e20151b7735787701700000000000017a914a507b83449359c82a195fc9bab99fa1b7c8289eb87581b00000000000017a91401ea6e7336fb9d5e5f36994eecade840ba938d0687401f00000000000017a914e5a474adbd25d66bb70c9b0b6a27f3eebf70b3f587282300000000000017a914d4ae33b227632cf0434f054782558baf9aa6e42d87102700000000000017a9147e4cca8f6c63cb7a56dd3c6edd2acbd031813de98702015106b3746375685100000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,WITNESS,P2SH,DISCOURAGE_UPGRADABLE_NOPS",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["Wrong TX Hash passed via the stack fails CTV"],
[[["1303ae3fc607b6eb3a4da63d3d7f4722b595db87890943618e11c3905662cae4",
0,
"0x00 0x20 0x6c9cc4747e7d287ac1abf8c65152a78d369213583e306b7d3163e12c561abaa2",
155000]],
"02000000000101e4ca625690c3118e6143098987db95b522477f3d3da64d3aebb607c63fae03130000000000000000000ae90300000000000017a9145850541d205b7b1feb1bc10112f9d739fa9a7dc287d00700000000000017a914d76b85e77e20777d5ec9d7d9998ae0c062d4669087b80b00000000000017a914c79f4a39b0580e4ec90e1b4989fc6124e4135cc187a00f00000000000017a91469635f1f4c06d66591282a02303b1435ee888d9487881300000000000017a91410d3b9b2aaffae25b6098169e2dc69928849215387701700000000000017a91456e4a3e5a3a49b9a66240288e79a8a5e8e31d05587581b00000000000017a9143936403d1a70b32c1e0e6920f9cd99cbc8a8345787401f00000000000017a9146ec4fa5a4e329f9d92ea29b65fa48c6ec1470ffa87282300000000000017a914f66743d56210c98bce8a44742b2ecfa9b7f48fdb87102700000000000017a914555c65f1c355993b46003311931eb08cf457209b870220a2638b51a692e6a8b39e87c431edde4fc1ada3dedaf9665875ac8353af44c50706b3746375685100000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,WITNESS,P2SH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["Embedded CTV Impossible with Bare P2SH due to hash cycle"],
[[["6a869fd9a0395f35e412ad3eb7fffa61a59263b1ad16aeb5fcc30e032bc3a8bf",
0,
"OP_HASH160 0x14 0x40aec8967698985eb369afd3ad3dc571110e6a10 OP_EQUAL",
155000]],
"0200000001bfa8c32b030ec3fcb5ae16adb16392a561faffb73ead12e4355f39a0d99f866a000000002322203b8d241649e612058fd2f1b4decbe9141284f0e4dd297d95b0da01a5d8791e4bb3000000000ae90300000000000017a914b04d55bbfedf606a08795fb0c2655bb3212f2bde87d00700000000000017a914d079c2cfad655234e68159422727eefa78811b4787b80b00000000000017a9145ea3edd87eb790af8051da692f4d59e5be6ffd4b87a00f00000000000017a914e17e2c4f4fcae1ef0d5ef96c740565426009ca2187881300000000000017a9144769d9f3b6fdf14f1223d9e7f11be7873bcbcde387701700000000000017a914064529bab7b89253159c9043ef128f37f78add7a87581b00000000000017a9147bae64476db031d744b442ddee9af3e60ef1e4ea87401f00000000000017a914dd2d96d0ba673c0b9d5950223c334f19f2b6f4a487282300000000000017a9148abaaa7b977855f96afacea4c79e3caf5e7482c487102700000000000017a9140dab14b1ee04aea522639ee27d29a5f6a57758c18700000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH,P2SH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["CTV at pos 2 with >1 Input Fails if too few inputs"],
[[["eeda9ea077b04abec103ffbba6bcf41cd67cdfdabe5ccc6ed766b9cd4ed4808a",
0,
"0x20 0x3e123dbe62352fa40471c195aebd3cdec43cca8728520c8a2d5737009fa05b0b OP_CHECKTEMPLATEVERIFY",
155000]],
"02000000018a80d44ecdb966d76ecc5cbedadf7cd61cf4bca6bbff03c1be4ab077a09edaee0000000000000000000ae80300000000000017a9144dd991d2f69eed133bb9d16e298703c830e1fb2387d00700000000000017a9147a50ac55b0af704dfffc797c507db803488ad44787b80b00000000000017a914caab97b53be0b75526e011bc49b0101365f611b887a00f00000000000017a91448c947e1b16103782a7dcba1dd5896936fbc7d2587881300000000000017a914ff075d852727e7e32ff5e11b13d254cb553fb73287701700000000000017a914761069764474d5ef5d0e068e88e4ebe2edd2336087581b00000000000017a914cd76c979ed6421f5d39380b5eb3d0dc7f56e864b87401f00000000000017a91417e7563571166469e14275be7ef00d91927eee0387282300000000000017a9140f9ddd36a76392fec584f05b34d33282fbd4921287102700000000000017a91417603536acce13cf7496387f8169a7f832f08f4c8700000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["CTV at pos 2 with >1 Input Fails if inputs in wrong order"],
[[["eeda9ea077b04abec103ffbba6bcf41cd67cdfdabe5ccc6ed766b9cd4ed4808a",
0,
"0x20 0x3e123dbe62352fa40471c195aebd3cdec43cca8728520c8a2d5737009fa05b0b OP_CHECKTEMPLATEVERIFY",
155000],
["b6d623f1e5eaaaa83a21739f60ac173818ce6b9e13ca18ddda74e9dbe6124c0b", 0, "1", 155000]],
"02000000028a80d44ecdb966d76ecc5cbedadf7cd61cf4bca6bbff03c1be4ab077a09edaee0000000000000000000b4c12e6dbe974dadd18ca139e6bce183817ac609f73213aa8aaeae5f123d6b60000000000000000000ae80300000000000017a9144dd991d2f69eed133bb9d16e298703c830e1fb2387d00700000000000017a9147a50ac55b0af704dfffc797c507db803488ad44787b80b00000000000017a914caab97b53be0b75526e011bc49b0101365f611b887a00f00000000000017a91448c947e1b16103782a7dcba1dd5896936fbc7d2587881300000000000017a914ff075d852727e7e32ff5e11b13d254cb553fb73287701700000000000017a914761069764474d5ef5d0e068e88e4ebe2edd2336087581b00000000000017a914cd76c979ed6421f5d39380b5eb3d0dc7f56e864b87401f00000000000017a91417e7563571166469e14275be7ef00d91927eee0387282300000000000017a9140f9ddd36a76392fec584f05b34d33282fbd4921287102700000000000017a91417603536acce13cf7496387f8169a7f832f08f4c8700000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["CTV at pos 2 with >1 Input Fails if scriptSig of other input modified"],
[[["eeda9ea077b04abec103ffbba6bcf41cd67cdfdabe5ccc6ed766b9cd4ed4808a",
0,
"0x20 0x3e123dbe62352fa40471c195aebd3cdec43cca8728520c8a2d5737009fa05b0b OP_CHECKTEMPLATEVERIFY",
155000],
["b6d623f1e5eaaaa83a21739f60ac173818ce6b9e13ca18ddda74e9dbe6124c0b", 0, "1", 155000]],
"02000000020b4c12e6dbe974dadd18ca139e6bce183817ac609f73213aa8aaeae5f123d6b6000000000151000000008a80d44ecdb966d76ecc5cbedadf7cd61cf4bca6bbff03c1be4ab077a09edaee0000000000000000000ae80300000000000017a9144dd991d2f69eed133bb9d16e298703c830e1fb2387d00700000000000017a9147a50ac55b0af704dfffc797c507db803488ad44787b80b00000000000017a914caab97b53be0b75526e011bc49b0101365f611b887a00f00000000000017a91448c947e1b16103782a7dcba1dd5896936fbc7d2587881300000000000017a914ff075d852727e7e32ff5e11b13d254cb553fb73287701700000000000017a914761069764474d5ef5d0e068e88e4ebe2edd2336087581b00000000000017a914cd76c979ed6421f5d39380b5eb3d0dc7f56e864b87401f00000000000017a91417e7563571166469e14275be7ef00d91927eee0387282300000000000017a9140f9ddd36a76392fec584f05b34d33282fbd4921287102700000000000017a91417603536acce13cf7496387f8169a7f832f08f4c8700000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["CTV at pos 1 with specific scriptsigs fails with incorrect scriptSig"],
[[["a2522fa96033c5736f3142ff616426cd03a3d0f077f609e22c5a33a96e04e597",
0,
"0x20 0x4870387ef3dc7b392294140a323ec7b38dc138710f0931ce27f386a57128ea63 OP_CHECKTEMPLATEVERIFY",
155000],
["b6d623f1e5eaaaa83a21739f60ac173818ce6b9e13ca18ddda74e9dbe6124c0b", 0, "1", 155000]],
"020000000297e5046ea9335a2ce209f677f0d0a303cd266461ff42316f73c53360a92f52a2000000000151000000000b4c12e6dbe974dadd18ca139e6bce183817ac609f73213aa8aaeae5f123d6b6000000000151000000000ae80300000000000017a9143f163a8747557345ce2e6fe00c1894f2f281795e87d00700000000000017a9144cf13dfda93a7413b7e646611735656e5457657087b80b00000000000017a914868998b49df649c37a88d48c9d4a5b37290e507287a00f00000000000017a914034f9914a77571a6396482e9881745c92c3037c687881300000000000017a914a8238003e1732e2baf4334a8546d72be99af9bae87701700000000000017a91491dbac5d67d5941115a03fc7eaec09f31a5b4dfc87581b00000000000017a914e0c0f19fec3b2993b9c116c798b5429d4515596687401f00000000000017a914d6b40d98d94530f1a1eb57614680813c81a95ccd87282300000000000017a914fb0bfb072bb79611a4323981828108a3cf54b0a687102700000000000017a9149e2d11f06ba667e981b802af10be8dabd08eafff8700000000",
"DEFAULT_CHECK_TEMPLATE_VERIFY_HASH",
[{"if_unset": ["DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
"then_unset": ["DISCOURAGE_UPGRADABLE_NOPS"]}]],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
================================================
FILE: bip-0119/vectors/tx_valid.json
================================================
[
["The following are deserialized transactions which are valid."],
["They are in the form"],
["[[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...],"],
["serializedTransaction, excluded verifyFlags, always included verifyFlags?, skip excluded one by one?]"],
["Objects that are only a single string (like this one) are ignored"],
["Check that CTV is Processed with a Taproot Spend"],
[[["f90521604b56c392ffa17a01bcae5914b8cf7728cc6cec00d90838818cc5465f", 0, "1 0x20 0x24f5fe807bcee7774dc515f0b7ee8d6ae39eefd1b590264c52ff867e22c49419", 155000]],
"020000000001015f46c58c813808d900ec6ccc2877cfb81459aebc017aa1ff92c3564b602105f90000000000000000000ae80300000000000017a914ce0036ae7d49f06967dd92cc1ffff4a878c457f987d00700000000000017a91406e00c3b362e65e03507a2858d7b6499b668669887b80b00000000000017a9142ee42c65592c59b69bfefbd03781140c67e5232487a00f00000000000017a9146b3df16a1e6651d582ca6598900cb4f2d6c9dfb887881300000000000017a914877d55932d4f38b476d4db27e4efbe159ff0a07187701700000000000017a91441e9dc892e861d252d513d594ba833cd6bc8917087581b00000000000017a914b93075800c693dcc78b0553bf9d1cf879d76a02487401f00000000000017a914e9f0ea3a2cae0ad01114e2ec3502ef08bbc50af487282300000000000017a9149a645b5293bdf8be72cb9d1460bce7d64445cfad87102700000000000017a91451e5d6b2ee24ae128234c92245df3624620ea7d3870222209eb65498bfcd4eb90e61c2c5e323a9c16c8bfd8d53ba649915bcdb572099c12fb321c0b7e0105780185688d998a8f8438aa07637a5799755688ec80175cb26c0406e0200000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["Check that CTV upgradability works (taproot)"],
[[["f90521604b56c392ffa17a01bcae5914b8cf7728cc6cec00d90838818cc5465f", 0, "1 0x20 0x24f5fe807bcee7774dc515f0b7ee8d6ae39eefd1b590264c52ff867e22c49419", 155000]],
"020000000001015f46c58c813808d900ec6ccc2877cfb81459aebc017aa1ff92c3564b602105f90000000000000000000ae80300000000000017a914ce0036ae7d49f06967dd92cc1ffff4a878c457f987d00700000000000017a91406e00c3b362e65e03507a2858d7b6499b668669887b80b00000000000017a9142ee42c65592c59b69bfefbd03781140c67e5232487a00f00000000000017a9146b3df16a1e6651d582ca6598900cb4f2d6c9dfb887881300000000000017a914877d55932d4f38b476d4db27e4efbe159ff0a07187701700000000000017a91441e9dc892e861d252d513d594ba833cd6bc8917087581b00000000000017a914b93075800c693dcc78b0553bf9d1cf879d76a02487401f00000000000017a914e9f0ea3a2cae0ad01114e2ec3502ef08bbc50af487282300000000000017a9149a645b5293bdf8be72cb9d1460bce7d64445cfad87102700000000000017a91451e5d6b2ee24ae128234c92245df3624620ea7d3870222209eb65498bfcd4eb90e61c2c5e323a9c16c8bfd8d53ba649915bcdb572099c12fb321c0b7e0105780185688d998a8f8438aa07637a5799755688ec80175cb26c0406e0200000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["Segwit v0 CTV Spend"],
[[["c16621d89637274011a8fb02ac487d283367f33d36de8c1ec8e323e55cb149cb",
0,
"0x00 0x20 0xf47ad51491d952cb1fad0d3f208dde482561d2170ebbbbc08e2e0292eeb4ec3d",
155000]],
"02000000000101cb49b15ce523e3c81e8cde363df36733287d48ac02fba81140273796d82166c10000000000000000000ae80300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d1870122207427029cbb0a48361ba1b83e4fff21918618477be3d217d83b2ff846815305f6b300000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["Check that CTV upgradability works (Segwit v0)"],
[[["c16621d89637274011a8fb02ac487d283367f33d36de8c1ec8e323e55cb149cb",
0,
"0x00 0x20 0xf47ad51491d952cb1fad0d3f208dde482561d2170ebbbbc08e2e0292eeb4ec3d",
155000]],
"02000000000101cb49b15ce523e3c81e8cde363df36733287d48ac02fba81140273796d82166c10000000000000000000ae80300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d1870122207427029cbb0a48361ba1b83e4fff21918618477be3d217d83b2ff846815305f6b300000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["CTV reserves different sized args for future upgrades"],
[[["e8e9805801b7fb44814531de0dd498b955651b9c25a85a043d73f18970622647",
0,
"0x00 0x20 0x65f15821061635e6807f06701bf0a12d8e89dcff88df5968bd0822c9dbb52f1c",
155000]],
"020000000001014726627089f1733d045aa8259c1b6555b998d40dde31458144fbb7015880e9e80000000000000000000ae90300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d18702015101b300000000",
"DISCOURAGE_UPGRADABLE_NOPS"],
["CheckTemplateVerify Argument from Witness Stack"],
[[["e8e9805801b7fb44814531de0dd498b955651b9c25a85a043d73f18970622647",
0,
"0x00 0x20 0x65f15821061635e6807f06701bf0a12d8e89dcff88df5968bd0822c9dbb52f1c",
155000]],
"020000000001014726627089f1733d045aa8259c1b6555b998d40dde31458144fbb7015880e9e80000000000000000000ae90300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d18702204d5783a61241bdef19c3480e094cc933c91d2bde995c8c50407099184b501f4301b300000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["CheckTemplateVerify Argument from Witness Stack"],
[[["e8e9805801b7fb44814531de0dd498b955651b9c25a85a043d73f18970622647",
0,
"0x00 0x20 0x65f15821061635e6807f06701bf0a12d8e89dcff88df5968bd0822c9dbb52f1c",
155000]],
"020000000001014726627089f1733d045aa8259c1b6555b998d40dde31458144fbb7015880e9e80000000000000000000ae90300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d18702204d5783a61241bdef19c3480e094cc933c91d2bde995c8c50407099184b501f4301b300000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["BEGIN CTV congestion control tree level with 4 levels:"],
["CTV congestion control tree level 0"],
[[["d0246d069143263bca9a2b176fcf64bd8e4975c7670ed33659b4b8f88d3e7446",
0,
"0x20 0x10618b50aa1120e9e940bbea8b6d081019e38fbb9b956b0ab4f61631d05727ca OP_CHECKTEMPLATEVERIFY",
16600]],
"020000000146743e8df8b8b45936d30e67c775498ebd64cf6f172b9aca3b264391066d24d000000000000000000002781e0000000000002220bceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800b3781e00000000000022201210e50077518896fd1661bffc2c1e88ad6e204ec4e8755407b42a97347c1e1bb300000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["CTV congestion control tree level 1"],
[[["b69f866d47ebb75eeecfbc3b9b641f926f11035b64ff27a5a5e88b9c065bddf5",
0,
"0x20 0xbceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800 OP_CHECKTEMPLATEVERIFY",
7800]],
"0200000001f5dd5b069c8be8a5a527ff645b03116f921f649b3bbccfee5eb7eb476d869fb600000000000000000002480d00000000000022204c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2b3480d0000000000002220805bddd8b95a3cf3729b62703de37a1533b11634de76aa4a18605b640f1f3208b300000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["CTV congestion control tree level 2"],
[[["7d331a33880504fa94478c9687f3f41322ec76f81edad8e72491cbb81eea4754",
0,
"0x20 0x4c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2 OP_CHECKTEMPLATEVERIFY",
3400]],
"02000000015447ea1eb8cb9124e7d8da1ef876ec2213f4f387968c4794fa040588331a337d00000000000000000002b004000000000000222084ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079b3b0040000000000002220241af26179a8e861cca473244723978127c16531f71fbcc33563c4f099651f8fb300000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["CTV congestion control tree level 3"],
[[["e630b2357e02d1611a0615ce3964c408823ce3269974bd94e57ddea96900da70",
0,
"0x20 0x84ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079 OP_CHECKTEMPLATEVERIFY",
1200]],
"020000000170da0069a9de7de594bd749926e33c8208c46439ce15061a61d1027e35b230e60000000000000000000264000000000000001600141ca3bdf6bd2b1fc27420316a0d13f81fcdb85cb0640000000000000016001489d611c79700d6b4ae73d853ed49b86621d5802100000000",
"DISCOURAGE_UPGRADABLE_NOPS", "NONE", true],
["END"],
["BEGIN CTV congestion control tree level with 4 levels:"],
["CTV congestion control tree level 0"],
[[["d0246d069143263bca9a2b176fcf64bd8e4975c7670ed33659b4b8f88d3e7446",
0,
"0x20 0x10618b50aa1120e9e940bbea8b6d081019e38fbb9b956b0ab4f61631d05727ca OP_CHECKTEMPLATEVERIFY",
16600]],
"020000000146743e8df8b8b45936d30e67c775498ebd64cf6f172b9aca3b264391066d24d000000000000000000002781e0000000000002220bceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800b3781e00000000000022201210e50077518896fd1661bffc2c1e88ad6e204ec4e8755407b42a97347c1e1bb300000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["CTV congestion control tree level 1"],
[[["b69f866d47ebb75eeecfbc3b9b641f926f11035b64ff27a5a5e88b9c065bddf5",
0,
"0x20 0xbceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800 OP_CHECKTEMPLATEVERIFY",
7800]],
"0200000001f5dd5b069c8be8a5a527ff645b03116f921f649b3bbccfee5eb7eb476d869fb600000000000000000002480d00000000000022204c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2b3480d0000000000002220805bddd8b95a3cf3729b62703de37a1533b11634de76aa4a18605b640f1f3208b300000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["CTV congestion control tree level 2"],
[[["7d331a33880504fa94478c9687f3f41322ec76f81edad8e72491cbb81eea4754",
0,
"0x20 0x4c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2 OP_CHECKTEMPLATEVERIFY",
3400]],
"02000000015447ea1eb8cb9124e7d8da1ef876ec2213f4f387968c4794fa040588331a337d00000000000000000002b004000000000000222084ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079b3b0040000000000002220241af26179a8e861cca473244723978127c16531f71fbcc33563c4f099651f8fb300000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["CTV congestion control tree level 3"],
[[["e630b2357e02d1611a0615ce3964c408823ce3269974bd94e57ddea96900da70",
0,
"0x20 0x84ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079 OP_CHECKTEMPLATEVERIFY",
1200]],
"020000000170da0069a9de7de594bd749926e33c8208c46439ce15061a61d1027e35b230e60000000000000000000264000000000000001600141ca3bdf6bd2b1fc27420316a0d13f81fcdb85cb0640000000000000016001489d611c79700d6b4ae73d853ed49b86621d5802100000000",
"NONE", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["END"],
["Test CTV with a specific scriptsig"],
[[["32858fe9a6348d4ee5fcfce78f6dbca0b54dff169ff4cc41439adca4e5d30746",
0,
"1",
155000],
["357722dce671e5aa52abd617002baa8d5d970cef43feca3bf2d4c8b1e5d53d11",
0,
"0x20 0x08a5903863a0562c0b5608521a8a77ca02e669eb01f3981eede6bf6f2f38c2c2 OP_CHECKTEMPLATEVERIFY",
155000]],
"0200000002113dd5e5b1c8d4f23bcafe43ef0c975d8daa2b0017d6ab52aae571e6dc227735000000000151000000004607d3e5a4dc9a4341ccf49f16ff4db5a0bc6d8fe7fcfce54e8d34a6e98f8532000000000100000000000ae80300000000000017a9146422bb825e07ab99ab915223ac67f195a4fb761987d00700000000000017a914cc9fa001f8c9ff9dfdecf0ec1356d37c808aec2d87b80b00000000000017a914092f42f35fd05eaf816a090ad8f1adec8394132d87a00f00000000000017a9147cfd2a76093289ebabf860d3071b92756dbde1b787881300000000000017a914c3d81e1a59c256bff75c535878e1701943a9e48987701700000000000017a914029ddf1319c05ff38cd974ba99fdcf1cb4b88b9687581b00000000000017a9148c95279a9fd452ad7b1cb7a35fd08e7ff55946af87401f00000000000017a9149216fef0f965b2f1890a420aa725cb86ba47a9c087282300000000000017a9141424c24d8cd907a36310db639ec7d194c62d620087102700000000000017a9145b278b155e6dd103b4bf5ba78e4a95c16926c9bd8700000000",
"DISCOURAGE_UPGRADABLE_NOPS,CLEANSTACK", "NONE", true],
[[["32858fe9a6348d4ee5fcfce78f6dbca0b54dff169ff4cc41439adca4e5d30746",
0,
"1",
155000],
["357722dce671e5aa52abd617002baa8d5d970cef43feca3bf2d4c8b1e5d53d11",
0,
"0x20 0x08a5903863a0562c0b5608521a8a77ca02e669eb01f3981eede6bf6f2f38c2c2 OP_CHECKTEMPLATEVERIFY",
155000]],
"0200000002113dd5e5b1c8d4f23bcafe43ef0c975d8daa2b0017d6ab52aae571e6dc227735000000000151000000004607d3e5a4dc9a4341ccf49f16ff4db5a0bc6d8fe7fcfce54e8d34a6e98f8532000000000100000000000ae80300000000000017a9146422bb825e07ab99ab915223ac67f195a4fb761987d00700000000000017a914cc9fa001f8c9ff9dfdecf0ec1356d37c808aec2d87b80b00000000000017a914092f42f35fd05eaf816a090ad8f1adec8394132d87a00f00000000000017a9147cfd2a76093289ebabf860d3071b92756dbde1b787881300000000000017a914c3d81e1a59c256bff75c535878e1701943a9e48987701700000000000017a914029ddf1319c05ff38cd974ba99fdcf1cb4b88b9687581b00000000000017a9148c95279a9fd452ad7b1cb7a35fd08e7ff55946af87401f00000000000017a9149216fef0f965b2f1890a420aa725cb86ba47a9c087282300000000000017a9141424c24d8cd907a36310db639ec7d194c62d620087102700000000000017a9145b278b155e6dd103b4bf5ba78e4a95c16926c9bd8700000000",
"CLEANSTACK", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["Test CTV with a specific scriptsig at different index"],
[[["e2f2baee9c59389b34e39742ce05debf64aaa7a00fbdab88614f4d3c133186d5",
0,
"1",
155000],
["c88e4b769a9211d2bca7516dbeacf250585dc825e41e34a65607a444b97fb782",
0,
"0x20 0xcc06acb181a8e9893c53c92fcfcb56fc004a360964af02cfd15b9f3321385f86 OP_CHECKTEMPLATEVERIFY",
155000]],
"0200000002d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000001510000000082b77fb944a40756a6341ee425c85d5850f2acbe6d51a7bcd211929a764b8ec8000000000100000000000ae80300000000000017a914d63e77972529f4db5b32efaa4e06f66ae0b5dc0987d00700000000000017a91488b6705f8c9568c52b55ed712c257f84f64a49f587b80b00000000000017a9142be57e9a179f8d9ff8f33a788d4b54512ea9e36087a00f00000000000017a91429261b4f65796f618908de9f51669014e2e2e04f87881300000000000017a914e3a1e1d24cbba3ca9369248082988bad3ceafcfb87701700000000000017a91403801b0a9591f3b5a00a5ea60fb34dc12b4a691187581b00000000000017a91465248bc2c732db2d88db0b0d677c1514b101025b87401f00000000000017a91420021e3dc4e80c7192c1a3cd04026d22d0f8d38287282300000000000017a914df27596dbff2028791bd7692846e65d16d8fed0d87102700000000000017a9142ed128e911cab04d3277d3635f79d5e3d7e6f4c48700000000",
"DISCOURAGE_UPGRADABLE_NOPS,CLEANSTACK", "NONE", true],
[[["e2f2baee9c59389b34e39742ce05debf64aaa7a00fbdab88614f4d3c133186d5",
0,
"1",
155000],
["c88e4b769a9211d2bca7516dbeacf250585dc825e41e34a65607a444b97fb782",
0,
"0x20 0xcc06acb181a8e9893c53c92fcfcb56fc004a360964af02cfd15b9f3321385f86 OP_CHECKTEMPLATEVERIFY",
155000]],
"0200000002d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000001510000000082b77fb944a40756a6341ee425c85d5850f2acbe6d51a7bcd211929a764b8ec8000000000100000000000ae80300000000000017a914d63e77972529f4db5b32efaa4e06f66ae0b5dc0987d00700000000000017a91488b6705f8c9568c52b55ed712c257f84f64a49f587b80b00000000000017a9142be57e9a179f8d9ff8f33a788d4b54512ea9e36087a00f00000000000017a91429261b4f65796f618908de9f51669014e2e2e04f87881300000000000017a914e3a1e1d24cbba3ca9369248082988bad3ceafcfb87701700000000000017a91403801b0a9591f3b5a00a5ea60fb34dc12b4a691187581b00000000000017a91465248bc2c732db2d88db0b0d677c1514b101025b87401f00000000000017a91420021e3dc4e80c7192c1a3cd04026d22d0f8d38287282300000000000017a914df27596dbff2028791bd7692846e65d16d8fed0d87102700000000000017a9142ed128e911cab04d3277d3635f79d5e3d7e6f4c48700000000",
"CLEANSTACK", "DEFAULT_CHECK_TEMPLATE_VERIFY_HASH"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
================================================
FILE: bip-0119.mediawiki
================================================
==Abstract==
This BIP proposes a new opcode, OP_CHECKTEMPLATEVERIFY, to be activated
as a change to the semantics of OP_NOP4.
==Summary==
OP_CHECKTEMPLATEVERIFY uses opcode OP_NOP4 (0xb3) as a soft fork upgrade.
OP_CHECKTEMPLATEVERIFY does the following:
* There is at least one element on the stack, fail otherwise
* The element on the stack is 32 bytes long, NOP otherwise
* The DefaultCheckTemplateVerifyHash of the transaction at the current input index is equal to the element on the stack, fail otherwise
The DefaultCheckTemplateVerifyHash commits to the serialized version, locktime, scriptSigs hash (if any
non-null scriptSigs), number of inputs, sequences hash, number of outputs, outputs hash, and
currently executing input index.
The recommended standardness rules additionally:
* Reject non-32 byte as SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS.
==Motivation==
This BIP introduces a transaction template, a simple spending restriction that
pattern matches a transaction against a hashed transaction specification.
OP_CHECKTEMPLATEVERIFY reduces many of the trust, interactivity, and storage
requirements inherent with the use of pre-signing in applications.
For more details on applications, please see the references.
==Detailed Specification==
The below code is the main logic for verifying CHECKTEMPLATEVERIFY, described
in pythonic pseudocode. The canonical specification for the semantics of
OP_CHECKTEMPLATEVERIFY as implemented in C++ in the context of Bitcoin Core can
be seen in the reference implementation.
The execution of the opcode is as follows:
def execute_bip_119(self):
# Before soft-fork activation / failed activation
# continue to treat as NOP4
if not self.flags.script_verify_default_check_template_verify_hash:
# Potentially set for node-local policy to discourage premature use
if self.flags.script_verify_discourage_upgradable_nops:
return self.errors_with(errors.script_err_discourage_upgradable_nops)
return self.return_as_nop()
# CTV always requires at least one stack argument
if len(self.stack) < 1:
return self.errors_with(errors.script_err_invalid_stack_operation)
# CTV only verifies the hash against a 32 byte argument
if len(self.stack[-1]) == 32:
# Ensure the precomputed data required for anti-DoS is available,
# or cache it on first use
if self.context.precomputed_ctv_data == None:
self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data()
# If the hashes do not match, return error
if stack[-1] != self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data):
return self.errors_with(errors.script_err_template_mismatch)
return self.return_as_nop()
# future upgrade can add semantics for this opcode with different length args
# so discourage use when applicable
if self.flags.script_verify_discourage_upgradable_nops:
return self.errors_with(errors.script_err_discourage_upgradable_nops)
else:
return self.return_as_nop()
The computation of this hash can be implemented as specified below (where self
is the transaction type). Care must be taken that in any validation context,
the precomputed data must be initialized to prevent Denial-of-Service attacks.
Any implementation *must* cache these parts of the hash computation to avoid
quadratic hashing DoS. All variable length computations must be precomputed
including hashes of the scriptsigs, sequences, and outputs. See the section
"Denial of Service and Validation Costs" below. This is not a performance
optimization.
def ser_compact_size(l):
r = b""
if l < 253:
# Serialize as unsigned char
r = struct.pack("B", l)
elif l < 0x10000:
# Serialize as unsigned char 253 followed by unsigned 2 byte integer (little endian)
r = struct.pack("
A PayToBareDefaultCheckTemplateVerifyHash output matches the following template:
# Extra-fast test for pay-to-basic-standard-template CScripts:
def is_pay_to_bare_default_check_template_verify_hash(self):
return len(self) == 34 and self[0] == 0x20 and self[-1] == OP_CHECKTEMPLATEVERIFY
==Deployment==
Activation logic is elided from this BIP and is more appropriately discussed elsewhere.
Until BIP-119 reaches ACTIVE state and the
SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH flag is enforced, node implementations should (are recommended to)
execute a NOP4 as SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS (to deny entry to the mempool) for policy and must evaluate as
a NOP for consensus (during block validation).
In order to facilitate using CHECKTEMPLATEVERIFY, the common case of a
PayToBareDefaultCheckTemplateVerifyHash
with no scriptSig data may (is recommended to) be made standard to permit relaying. Future bare scripts may be
standardized later as policy changes at the preference of the implementer.
==Reference Implementation==
A reference implementation and tests are available here in the PR to Bitcoin Core https://github.com/bitcoin/bitcoin/pull/21702.
It is not ideal to link to a PR, as it may be rebased and changed, but it is the best place to find
the current implementation and review comments of others.
A recent commit hash in that PR including tests and vectors can be found here https://github.com/jeremyrubin/bitcoin/commit/3109df5616796282786706738994a5b97b8a5a38.
Once the PR is merged, this BIP should be updated to point to the specific code released.
Test vectors are available in [/bip-0119/vectors the bip-0119/vectors
directory] for checking compatibility with the reference implementation and BIP.
==Rationale==
OP_CHECKTEMPLATEVERIFY's design is a small code change and simple to analyze. It is
compatible with future upgrades if new template types are required
for more complex but demonstrably safe use cases.
Below we'll discuss the rules one-by-one:
====The DefaultCheckTemplateVerifyHash of the transaction at the current input index matches the top of the stack====
The set of data committed to is a superset of data which can impact the TXID of the transaction,
other than the inputs. This ensures that for a given known input, the TXIDs can also be known ahead
of time. Otherwise, CHECKTEMPLATEVERIFY would not be usable for Batched Channel Creation constructions
as the redemption TXID could be malleated and pre-signed transactions invalidated, unless the channels
are built using an LN-Symmetry-like protocol. Note that there may be other types of pre-signed contracts that
may or may not be able to use LN-Symmetry-like constructs, therefore making TXIDs predictable makes CTV more
composable with arbitrary sub-protocols.
=====Committing to the version and locktime=====
Were these values not committed, it would be possible to delay the spending of
an output arbitrarily as well as possible to change the TXID.
Committing these values, rather than restricting them to specific values, is
more flexible as it permits users of CHECKTEMPLATEVERIFY to set the version and
locktime as they please.
=====Committing to the ScriptSigs Hash=====
The scriptsig in a segwit transaction must be exactly empty, unless it is a P2SH
segwit transaction in which case it must be only the exact redeemscript. P2SH is incompatible
(unless the P2SH hash is broken) with CHECKTEMPLATEVERIFY because the template hash must commit
to the ScriptSig, which must contain the redeemscript, which is a hash cycle.
To prevent malleability when not using a segwit input, we also commit to the
scriptsig. This makes it possible to use a 2 input CHECKTEMPLATEVERIFY with a legacy pre-signed
spend, as long as the exact scriptsig for the legacy output is committed. This is more robust than
simply disallowing any scriptSig to be set with CHECKTEMPLATEVERIFY.
If no scriptSigs are set in the transaction, there is no purpose in hashing the data or including it
in the DefaultCheckTemplateVerifyHash, so we elide it. It is expected to be common that no scriptSigs will be
set as segwit mandates that the scriptSig must be empty (to avoid malleability).
We commit to the hash rather than the values themselves as this is already
precomputed for each transaction to optimize SIGHASH_ALL signatures.
Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from
script.
=====Committing to the number of inputs=====
If we allow more than one input to be spent in the transaction then it would be
possible for two outputs to request payment to the same set of outputs,
resulting in half the intended payments being discarded, the "half-spend" problem.
Furthermore, the restriction on which inputs can be co-spent is critical for
payments-channel constructs where a stable TXID is a requirement (updates would
need to be signed on all combinations of inputs).
However, there are legitimate use cases for allowing multiple inputs. For
example:
Script paths:
Path A: <+24 hours> OP_CHECKSEQUENCEVERIFY OP_CHECKTEMPLATEVERIFY
Path B: OP_CHECKTEMPLATEVERIFY
In this case, there are 24 hours for the output to, with the addition of a
second output, pay Bob 2 BTC. If 24 hours lapses, then Alice may redeem her 1
BTC from the contract. Both input UTXOs may have the exact same Path B, or only one.
The issue with these constructs is that there are N! orders that the inputs can
be ordered in and it's not generally possible to restrict the ordering.
CHECKTEMPLATEVERIFY allows for users to guarantee the exact number of inputs being
spent. In general, using CHECKTEMPLATEVERIFY with more than one input is difficult
and exposes subtle issues, so multiple inputs should not be used except in
specific applications.
In principle, committing to the Sequences Hash (below) implicitly commits to the number of inputs,
making this field strictly redundant. However, separately committing to this number makes it easier
to construct DefaultCheckTemplateVerifyHash from script.
We treat the number of inputs as a `uint32_t` because Bitcoin's consensus decoding logic limits vectors
to `MAX_SIZE=33554432` and that is larger than `uint16_t` and smaller than `uint32_t`. 32 bits is also
friendly for manipulation using Bitcoin's current math opcodes, should `OP_CAT` be added. Note that
the max inputs in a block is further restricted by the block size to around 25,000, which would fit
into a `uint16_t`, but that is an unnecessary abstraction leak.
=====Committing to the Sequences Hash=====
If we don't commit to the sequences, then the TXID can be malleated. This also allows us to enforce
a relative sequence lock without an OP_CSV. It is insufficient to just pair CHECKTEMPLATEVERIFY
with OP_CSV because OP_CSV enforces a minimum nSequence value, not a literal value.
We commit to the hash rather than the values themselves as this is already
precomputed for each transaction to optimize SIGHASH_ALL signatures.
Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from
script.
=====Committing to the Number of Outputs=====
In principle, committing to the Outputs Hash (below) implicitly commits to the number of outputs,
making this field strictly redundant. However, separately committing to this number makes it easier
to construct DefaultCheckTemplateVerifyHash from script.
We treat the number of outputs as a `uint32_t` because a `COutpoint` index is a `uint32_t`.
Further, Bitcoin's consensus decoding logic limits vectors to `MAX_SIZE=33554432` and that is
larger than `uint16_t` and smaller than `uint32_t`. 32 bits is also friendly for manipulation using
Bitcoin's current math opcodes, should `OP_CAT` be added.
=====Committing to the outputs hash=====
This ensures that spending the UTXO is guaranteed to create the exact outputs
requested.
We commit to the hash rather than the values themselves as this is already
precomputed for each transaction to optimize SIGHASH_ALL signatures.
Committing to the hash additionally makes it simpler to construct DefaultCheckTemplateVerifyHash safely and unambiguously from
script.
=====Committing to the current input's index=====
Committing to the currently executing input's index is not strictly needed for anti-malleability,
however it does restrict the input orderings eliminating a source of malleability for protocol
designers.
However, committing to the index eliminates key-reuse vulnerability to the half-spend problem.
As CHECKTEMPLATEVERIFY scripts commit to being spent at particular index, reused instances of these
scripts cannot be spent at the same index, which implies that they cannot be spent in the same transaction.
This makes it safer to design wallet vault contracts without half-spend vulnerabilities.
Committing to the current index doesn't prevent one from expressing a CHECKTEMPLATEVERIFY which can
be spent at multiple indices. In current script, the CHECKTEMPLATEVERIFY operation can be wrapped
in an OP_IF for each index (or Tapscript branches in the future). If OP_CAT or OP_SHA256STREAM are
added to Bitcoin, the index may simply be passed in by the witness before hashing.
=====Committing to Values by Hash=====
Committing to values by hash makes it easier and more efficient to construct a
DefaultCheckTemplateVerifyHash
from script. Fields which are not intended to be set may be committed to by hash without incurring
O(n) overhead to re-hash.
Furthermore, if OP_SHA256STREAM is added in the future, it may be possible to write a script which
allows adding a single output to a list of outputs without incurring O(n) overhead by committing to
a hash midstate in the script.
=====Using SHA256=====
SHA256 is a 32 byte hash which meets Bitcoin's security standards and is
available already inside of Bitcoin Script for programmatic creation of template
programs.
RIPEMD160, a 20 byte hash, might also be a viable hash in some contexts and has some benefits. For fee efficiency,
RIPEMD160 saves 12 bytes. However, RIPEMD160 was not chosen for BIP-119 because it introduces
risks around the verification of programs created by third parties to be subject to a
[birthday-attack https://bitcoin.stackexchange.com/questions/54841/birthday-attack-on-p2sh] on
transaction preimages.
=====Using Non-Tagged Hashes=====
The Taproot/Schnorr BIPs use Tagged Hashes
(`SHA256(SHA256(tag)||SHA256(tag)||msg)`) to prevent taproot leaves, branches,
tweaks, and signatures from overlapping in a way that might introduce a security
[vulnerability https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-June/016091.html].
OP_CHECKTEMPLATEVERIFY is not subject to this sort of vulnerability as the
hashes are effectively tagged externally, that is, by OP_CHECKTEMPLATEVERIFY
itself and therefore cannot be confused for another hash.
It would be a conservative design decision to make it a tagged hash even if
there was no obvious benefit and no cost. However, in the future, if OP_CAT were
to be introduced to Bitcoin, it would make programs which dynamically build
OP_CHECKTEMPLATEVERIFY hashes less space-efficient. Therefore, bare untagged hashes
are used in BIP-119.
=====The Ordering of Fields=====
Strictly speaking, the ordering of fields is insignificant. However, with a
carefully selected order, the efficiency of future scripts (e.g., those using a
OP_CAT or OP_SHA256STREAM) may be improved (as described in the Future Upgrades
section).
In particular, the order is selected in order of least likely to change to most.
#nVersion
#nLockTime
#scriptSig hash (maybe!)
#input count
#sequences hash
#output count
#outputs hash
#input index
Several fields are infrequently modified. nVersion should change infrequently. nLockTime should
generally be fixed to 0 (in the case of a payment tree, only the *first* lock time is needed to
prevent fee-sniping the root). scriptSig hash should generally not be set at all.
Since there are many possible sequences hash for a given input count, the input count comes before
the sequences hash.
Since there are many possible outputs hashes for a given out count, the output count comes before
the outputs hash.
Since we're generally using a single input to many output design, we're more likely to modify the
outputs hash than the inputs hash.
We usually have just a single input on a CHECKTEMPLATEVERIFY script, which would suggest that it
does not make sense for input index to be the last field. However, given the desirability of being
able to express a "don't care" index easily (e.g., for decentralized kickstarter-type transactions),
this value is placed last.
===Design Tradeoffs and Risks===
CHECKTEMPLATEVERIFY's design limits script authors to relatively precise template matching. The
structure of CHECKTEMPLATEVERIFY template is such that most of the transaction details must be known
exactly at the time of construction, with the exception of the inputs.
CHECKTEMPLATEVERIFY can be nested -- that is, a transaction that is created by spending an output with a
` OP_CHECKTEMPLATEVERIFY` restriction may create outputs with ` OP_CHECKTEMPLATEVERIFY` restrictions.
This expansion is inherently finite, as re-creating an output with a script containing the hash `` from a transaction
spending an output with the hash `` creates a hash cycle. This can also be thought of as each template hash `` having
a "path height" of the longest chain of possible unbroken `OP_CHECKTEMPLATEVERIFY` verifying transactions, and the path height is
strictly decreasing.
Furthermore, templates are restricted to be spendable as a known number of inputs only and
at a specific input index, preventing unintentional introduction of the 'half spend' problem.
Templates, as restricted as they are, bear some risks.
====Denial of Service and Validation Costs====
CTV is designed to be able to be validated very cheaply without introducing DoS, either by checking a
precomputed hash or computing a hash of fixed length arguments (some of which may be cached from more
expensive computations).
In particular, CTV requires that clients cache the computation of a hash over all the scriptSigs, sequences,
and outputs. Before CTV, the hash of the scriptSigs was not required. CTV also requires that the presence of
any non-empty scriptSig be hashed, but this can be handled as a part of the scriptSigs hash.
As such, evaluating a CTV hash during consensus is always O(1) computation when the caches are available.
These caches usually must be available due to similar issues in CHECKSIG behavior. Computing the caches
is O(T) (the size of the transaction).
An example of a script that could experience a DoS issue without caching is:
CTV CTV CTV... CTV
Such a script would cause the interpreter to compute hashes (supposing N CTV's) over O(N*T) data.
If the scriptSigs non-nullity is not cached, then the O(T) transaction could be scanned over O(N)
times as well (although cheaper than hashing, still a DoS). As such, CTV caches hashes and computations
over all variable length fields in a transaction.
For CTV, the Denial-of-Service exposure and validation costs are relatively clear. Implementers must be careful
to correctly code CTV to make use of existing caches and cache the (new for CTV) computations over scriptSigs.
Other more flexible proposals may have a more difficult time solving DoS issues as more complex template computations may
be less cacheable and expose issues around quadratic hashing, it is a tradeoff CTV makes in favor of cheap and secure
validation at the expense of flexibility. For example, if CTV allowed the hashing only select outputs by a bitmask,
caching of all combinations of outputs would not be possible and would cause a quadratic hashing DoS vulnerability.
====Permanently Unspendable Outputs====
The preimage argument passed to CHECKTEMPLATEVERIFY may be unknown or otherwise unsatisfiable.
However, requiring knowledge that an address is spendable from is incompatible with sender's ability
to spend to any address (especially, OP_RETURN). If a sender needs to know the template can be spent
from before sending, they may request a signature of a provably non-transaction challenge string
from the leaves of the CHECKTEMPLATEVERIFY tree.
====Forwarding Addresses====
Key-reuse with CHECKTEMPLATEVERIFY may be used as a form of "forwarding address contract".
A forwarding address is an address which can automatically execute in a predefined way.
For example, an exchange's hot wallet might use an address which can automatically be moved to a cold
storage address after a relative timeout.
The issue is that reusing addresses in this way can lead to loss of funds.
Suppose one creates a template address which forwards 1 BTC to cold storage.
Creating an output to this address with less than 1 BTC will be frozen permanently.
Paying more than 1 BTC will lead to the funds in excess of 1BTC to be paid as a large miner fee.
CHECKTEMPLATEVERIFY could commit to the exact amount of bitcoin provided by the inputs/amount of fee
paid, but as this is a user error and not a malleability issue this is not done.
Future soft-forks could introduce opcodes which allow conditionalizing which template or script
branches may be used based on inspecting the amount of funds available in a transaction
As a general best practice, it is incumbent on Bitcoin users to not reuse any address unless you are
certain that the address is acceptable for the payment attempted. This limitation and risk is not
unique to CHECKTEMPLATEVERIFY. For example, atomic swap scripts are single use once the hash is
revealed. Future Taproot scripts may contain many logical branches that would be unsafe for being
spent to multiple times (e.g., a Hash Time Lock branch should be instantiated with unique hashes
each time it is used). Keys which have signed a SIGHASH_ANYPREVOUT transaction can similarly become
reuse-unsafe.
Because CHECKTEMPLATEVERIFY commits to the input index currently being spent, reused-keys are
guaranteed to execute in separate transactions which reduces the risk of "half-spend" type issues.
====NOP-Default and Recommended Standardness Rules====
If the argument length is not exactly 32, CHECKTEMPLATEVERIFY treats it as a NOP during
consensus validation. Implementations are recommended to fail in such circumstances during non-consensus
relaying and mempool validation. In particular, making an invalid-length argument a failure aids future
soft-forks upgrades to be able to rely on the tighter standard restrictions to safely loosen
the restrictions for standardness while tightening them for consensus with the upgrade's rules.
The standardness rules may lead an unscrupulous script developer to accidentally rely on the
stricter standardness rules to be enforced during consensus. Should that developer submit a
transaction directly to the network relying on standardness rejection, a standardness-invalid but
consensus-valid transaction may be caused, leading to a potential loss of funds.
====Feature Redundancy====
There are other opcodes that, if implemented, could make the CHECKTEMPLATEVERIFY's functionality redundant.
However, given CHECKTEMPLATEVERIFY's simple semantics and low on chain cost it's likely that it
would continue to be favored even if redundant with other capabilities. Or, in the case of opcodes
such as OP_VAULT, OP_CHECKCONTRACTVERIFY, and OP_TXHASH, OP_CHECKTEMPLATEVERIFY is a part of their
currently proposed implementations.
More powerful opcodes, like OP_COV proposed in MES16 or OP_TXHASH, would also bring some benefits in terms of
improving the ability to pay fees endogenously rather than relying on exogenous child-pays-for-parent or
other fee paying mechanisms such as transaction sponsors. However, these features come at substantially
increased complexity and room for behaviors unintended by the application developer.
Alternatively, SIGHASH_ANYPREVOUTANYSCRIPT can be used to implement something similar to templates,
via a scriptPubKey like:
OP_CHECKSIG
SIGHASH_ANYPREVOUTANYSCRIPT capabilities
above are similar to what CHECKTEMPLATEVERIFY offers. The key functional
difference between SIGHASH_ANYPREVOUTANYSCRIPT and OP_CHECKTEMPLATEVERIFY is
that OP_CHECKTEMPLATEVERIFY restricts the number of additional inputs and
precludes dynamically determined change outputs while
SIGHASH_ANYPREVOUTANYSCRIPT can be combined with SIGHASH_SINGLE or
SIGHASH_ANYONECANPAY. For the additional inputs, OP_CHECKTEMPLATEVERIFY also
commits to the scriptsig and sequence, which allows for specifying specific P2SH
scripts (or segwit v0 P2SH) which have some use cases. Furthermore,
CHECKTEMPLATEVERIFY has benefits in terms of script size (depending on choice of
PK, SIGHASH_ANYPREVOUTANYSCRIPT may use about 2x-3x the bytes) and verification
speed, as OP_CHECKTEMPLATEVERIFY requires only hash computation rather than
signature operations. This can be significant when constructing large payment
trees or programmatic compilations. CHECKTEMPLATEVERIFY also has a feature-wise
benefit in that it provides a robust pathway for future template upgrades, as proposed
in OP_TXHASH.
OP_CHECKSIGFROMSTACKVERIFY along with OP_CAT may also be used to emulate
CHECKTEMPLATEVERIFY. However such constructions are more complicated to implement in application
scripts than CHECKTEMPLATEVERIFY, and encumber additional verification overhead absent
from CHECKTEMPLATEVERIFY.
Given the simplicity of this approach to implement and analyze, and the benefits realizable by user
applications, CHECKTEMPLATEVERIFY's single template based approach is proposed in lieu of a generalized
system for specifying transactions in script.
====Future Upgrades====
This section describes updates to OP_CHECKTEMPLATEVERIFY that are possible in
the future as well as synergies with other possible upgrades.
=====CHECKTEMPLATEVERIFY Versions=====
OP_CHECKTEMPLATEVERIFY currently only verifies properties of 32 byte arguments.
In the future, meaning could be ascribed to other length arguments. For
example, a 33-byte argument could just the last byte as a control program. In
that case, DefaultCheckTemplateVerifyHash could be computed when the flag byte
is set to CTVHASH_ALL. Other programs could be added similar to a SIGHASH_TYPE.
For example, CTVHASH_GROUP could read data from the Taproot Annex for
compatibility with SIGHASH_GROUP type proposals and allow dynamic malleability
of which indexes get hashed for bundling.
The work done for the OP_TXHASH pre-BIP details one approach to upgrading the
OP_CHECKTEMPLATEVERIFY semantics.
=====OP_CHECKSIGFROMSTACKVERIFY=====
Were both OP_CHECKTEMPLATEVERIFY and OP_CHECKSIGFROMSTACKVERIFY to be added to
Bitcoin, it would be possible to implement a variant of LN-Symmetry's floating
transactions using the following script:
witness(S+n):
program(S): OP_CHECKTEMPLATEVERIFY OP_CHECKSIGFROMSTACKVERIFY OP_CHECKLOCKTIMEVERIFY
Compared to SIGHASH_ANYPREVOUTANYSCRIPT, because OP_CHECKTEMPLATEVERIFY does not
allow something similar to SIGHASH_ANYONECANPAY or SIGHASH_SINGLE, protocol
implementers might sign transactions with Ephemeral Anchors or additional Inputs
for paying fees or an alternative such as transaction sponsors might be considered.
Note that this use of OP_CHECKSIGFROMSTACKVERIFY and OP_CHECKTEMPLATEVERIFY, without the ` OP_CHECKLOCKTIMEVERIFY` ratchet,
enables a form of self-reproducing automata address with a one-time-trusted-setup, albeit with limited utility given the specifics
of OP_CHECKTEMPLATEVERIFY's DefaultCheckTemplateVerifyHash. In comparison, SIGHASH_ANYPREVOUT enables a more
powerful self-reproducing automata (colloquially called SpookChains), that uses a variety of combinations of SIGHASH flags
to be able to restrict state transitions based on amount.
=====OP_AMOUNTVERIFY=====
An opcode which verifies the exact amount that is being spent in the
transaction, the amount paid as fees, or made available in a given output could
be used to make safer OP_CHECKTEMPLATEVERIFY addresses. For instance, if the
OP_CHECKTEMPLATEVERIFY program P expects exactly S satoshis, sending S-1
satoshis would result in a frozen UTXO and sending S+n satoshis would result in
n satoshis being paid to fee. A range check could restrict the program to only
apply for expected values and default to a keypath otherwise, e.g.:
IF OP_AMOUNTVERIFY OP_GREATER CHECKSIG ELSE OP_CHECKTEMPLATEVERIFY
=====OP_CAT/OP_SHA256STREAM=====
OP_CHECKTEMPLATEVERIFY is (as described in the Ordering of Fields section)
efficient for specifying transactions dynamically from script should Bitcoin get enhanced
data manipulation opcodes.
As an example, the following code checks an input index argument and
concatenates it to the template and checks the template matches the transaction.
OP_SIZE 4 OP_EQUALVERIFY
OP_SWAP OP_CAT OP_SHA256 OP_CHECKTEMPLATEVERIFY
Note that were OP_CAT to be introduced with a size limit, e.g. 520 bytes, one would be limited
to use it to introspect transactions with 12 inputs and 12 outputs (depending on script type).
== Backwards Compatibility ==
OP_CHECKTEMPLATEVERIFY replaces a OP_NOP4 with stricter verification semantics. Therefore, scripts
which previously were valid will cease to be valid with this change. Stricter verification semantics
for an OP_NOP are a soft fork, so existing software will be fully functional without upgrade except
for mining and block validation. Similar soft forks for OP_CHECKSEQUENCEVERIFY and OP_CHECKLOCKTIMEVERIFY
(see BIP-0065 and BIP-0112) have similarly changed OP_NOP semantics without introducing compatibility issues.
In contrast to previous forks, OP_CHECKTEMPLATEVERIFY's reference implementation does not allow transactions with spending
scripts using it to be accepted to the mempool or relayed under standard policy until the new rule is active. Other implementations
are recommended to follow this rule as well, but not required.
Older wallet software will be able to accept spends from OP_CHECKTEMPLATEVERIFY outputs, but will
require an upgrade in order to treat PayToBareDefaultCheckTemplateVerifyHash chains with a confirmed ancestor as
being "trusted" (i.e., eligible for spending before the transaction is confirmed).
Backports of OP_CHECKTEMPLATEVERIFY can be trivially prepared (see the reference implementation)
for older node versions that can be patched but not upgraded to a newer major release.
== Script Compatibility ==
OP_CHECKTEMPLATEVERIFY is made available in all script versions. Application developers should
note that P2SH and P2SH Segwit, which reveal the program in the scriptSig, may not use ` CTV`
like fragments in their program as the scriptSig commitment creates a hash cycle.
== References ==
*[https://utxos.org utxos.org informational site]
*[https://covenants.info covenant informational site]
*[https://learn.sapio-lang.org Sapio Bitcoin smart contract language]
*[https://rubin.io/advent21 27 Blog Posts on building smart contracts with Sapio and CTV, including examples described here.]
*[https://www.youtube.com/watch?v=YxsjdIl0034&t=2451 Scaling Bitcoin Presentation]
*[https://bitcoinops.org/en/newsletters/2019/05/29/ Optech Newsletter Covering OP_CHECKOUTPUTSHASHVERIFY]
*[https://rubin.io/public/pdfs/multi-txn-contracts.pdf Structuring Multi Transaction Contracts in Bitcoin]
*[https://github.com/jeremyrubin/lazuli Lazuli Notes (ECDSA based N-of-N Signatures for Certified Post-Dated UTXOs)]
*[https://web.archive.org/web/20220203124718/https://fc16.ifca.ai/bitcoin/papers/MES16.pdf Bitcoin Covenants]
*[https://bitcointalk.org/index.php?topic=278122.0 CoinCovenants using SCIP signatures, an amusingly bad idea.]
*[https://fc17.ifca.ai/bitcoin/papers/bitcoin17-final28.pdf Enhancing Bitcoin Transactions with Covenants]
*[https://github.com/jamesob/simple-ctv-vault Simple CTV Vaults]
*[https://github.com/kanzure/python-vaults Python Vaults]
*[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-January/019808.html CTV Dramatically Improves DLCs]
*[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-April/020225.html Calculus of Covenants]
*[https://rubin.io/bitcoin/2021/12/10/advent-13/ Payment Pools with CTV]
*[https://rubin.io/bitcoin/2021/12/11/advent-14/ Channels with CTV]
*[https://rubin.io/bitcoin/2021/12/09/advent-12/ Congestion Control with CTV]
*[https://rubin.io/bitcoin/2021/12/07/advent-10/ Building Vaults on Bitcoin]
*[https://arkdev.info/ (Ark Labs) Ark Documentation]
*[https://docs.second.tech/protocol/intro/ (Second) Ark Documentation]
*[https://rubin.io/bitcoin/2022/09/14/drivechain-apo/ SpookChains]
*[https://github.com/bitcoin/bips/pull/1500 OP_TXHASH]
===Note on Similar Alternatives===
An earlier version of CHECKTEMPLATEVERIFY, CHECKOUTPUTSHASHVERIFY, is withdrawn
in favor of CHECKTEMPLATEVERIFY. CHECKOUTPUTSHASHVERIFY did not commit to the
version or lock time and was thus insecure.
CHECKTEMPLATEVERIFY could also be implemented as an extension to Taproot, and was
proposed this way earlier. However, particular applications may want to use OP_CHECKTEMPLATEVERIFY
in bare legacy scripts to maximize efficiency.
CHECKTEMPLATEVERIFY has also been previously referred to as OP_SECURETHEBAG, which is mentioned here
to aid in searching and referencing discussion on this BIP.
==Copyright==
This document is licensed under the 3-clause BSD license.
================================================
FILE: bip-0120.mediawiki
================================================
BIP: 120
Layer: Applications
Title: Proof of Payment
Authors: Kalle Rosenbaum
Status: Closed
Type: Specification
Assigned: 2015-07-28
== Abstract ==
This BIP describes a system called Proof of Payment, PoP. It is used to prove that a wallet has the credentials that were used to sign a previously generated transaction. Or simply put, it lets you prove that you have made a payment.
== Motivation ==
There are several scenarios in which it would be useful to prove that you have paid for something. For example:
* A pre-paid hotel room where your PoP functions as a key to the door.
* An online video rental service where you pay for a video and watch it on any device.
* An ad-sign where you pay in advance for e.g. 2 weeks exclusivity. During this period you can upload new content to the sign whenever you like using PoP.
* Log in to a pay site using a PoP.
* A parking lot you pay for monthly and the car authenticates itself using PoP.
* A lottery where all participants pay to the same address, and the winner is selected among the transactions to that address. You exchange the prize for a PoP for the winning transaction.
With Proof of Payment, these use cases can be achieved without any personal information (user name, password, e-mail address, etc) being involved.
== Rationale ==
Desirable properties:
# A PoP should be generated on demand.
# It should only be usable once to avoid issues due to theft.
# It should be able to create a PoP for any payment, regardless of script type (P2SH, P2PKH, etc.).
# It should prove that you have enough credentials to unlock all the inputs of the proven transaction.
# It should be easy to implement by wallets and servers to ease adoption.
Current methods of proving a payment:
* In BIP0070, the PaymentRequest together with the transactions fulfilling the request makes some sort of proof. However, it does not meet 1, 2 or 4 and it obviously only meets 3 if the payment is made through BIP0070. Also, there's no standard way to request/provide the proof. If standardized it would probably meet 5.
* Signing messages, chosen by the server, with the private keys used to sign the transaction. This could meet 1 and 2 but probably not 3. This is not standardized either. 4 Could be met if designed so.
If an input script type is P2SH, any satisfying script should do, just as if it was a payment. For M-of-N multisig scripts, that would mean that any set of M keys should be sufficient, not necessarily the same set of M keys that signed the transaction. This is important because strictly demanding the same set of M keys would defeat the purpose of a multisig address.
== Specification ==
=== Data structure ===
A proof of payment for a transaction T, here called PoP(T), is used to prove that one has ownership of the credentials needed to unlock all the inputs of T. It has the exact same structure as a bitcoin transaction with the same inputs as T and in the same order as in T, but with each sequence number set to 0. There is exactly one output, here called the pop output, with value 0. The pop output must have the following format:
OP_RETURN
{|
! Field !! Size [B] !! Description
|-
| <version> || 2 || Version, little endian, currently 0x01 0x00
|-
| <txid> || 32 || The transaction to prove
|-
| <nonce> || 6 || Random data
|}
The lock_time of the PoP must be set to 499999999 to prevent the PoP from being included in a block, should it appear on the bitcoin p2p network. This is also the reason for setting the sequence numbers to 0, since sequence number of ffffffff would make lock_time ineffective. This specification demands that all input sequence numbers are 0, not just one of them, which would be sufficient to make lock_time effective. This is for simplicity reasons.
An illustration of the PoP data structure and its original payment is shown below.
T
+------------------------------------------------+
|inputs | outputs |
| Value,Sequence | Value,Script |
+------------------------------------------------+
|input0 1,ffffffff | 0,pay to A |
|input1 3,ffffffff | 2,OP_RETURN |
|input2 4,ffffffff | 1,pay to B |
| | 4,pay to C |
+------------------------------------------------+
PoP(T)
+-------------------------------------------------------------+
| inputs | outputs |
| Value,Sequence | Value,Script |
+-------------------------------------------------------------+
|input0 1,00000000 | 0,OP_RETURN |
|input1 3,00000000 | |
|input2 4,00000000 | |
+-------------------------------------------------------------+
| lock_time=499999999 |
+-------------------------------------------------------------+
The PoP is signed using the same signing process that is used for bitcoin transactions.
The purpose of the nonce is to make it harder to use a stolen PoP; Once the PoP has reached the server, that PoP is useless since the server will generate a new nonce for every PoP request.
=== Process ===
# A proof of payment request is sent from the server to the wallet. The PoP request contains:
## a random nonce
## a destination where to send the PoP, for example a https URL
## data hinting the wallet which transaction to create a proof for. For example:
##* txid, if known by the server
##* PaymentRequest.PaymentDetails.merchant_data (in case of a BIP0070 payment)
##* amount, label, message or other information from a BIP0021 URI
# The wallet identifies a transaction T, if possible. Otherwise it asks the user to select among the ones that match the hints in 1.iii.
# The wallet creates an unsigned PoP (UPoP) for T, and asks the user to sign it.
# The user confirms
# The UPoP(T) is signed by the wallet, creating PoP(T).
# The PoP is sent to the destination in 1.ii.
# The server receiving the PoP validates it and responds with “valid” or “invalid”.
# The wallet displays the response in some way to the user.
'''Remarks:'''
* The method of transferring the PoP request at step 1 is not specified here. Instead that is specified in separate specifications, see BIP0121.
* The nonce must be randomly generated by the server for every new PoP request.
=== Validating a PoP ===
The server needs to validate the PoP and reply with "valid" or "invalid". That process is outlined below. If any step fails, the validation is aborted and "invalid" is returned:
# Check the format of the PoP. It must pass normal transaction checks, except that the inputs may already be spent.
# Check that lock_time is 499999999.
# Check that there is exactly one output. This output must have value 0 and conform to the OP_RETURN output format outlined above.
# Check that the nonce is the same as the one requested.
# Check that the inputs of the PoP are exactly the same as in transaction T, except that the sequence numbers must all be 0. The ordering of the inputs must also be the same as in T.
# Run the scripts of all the inputs. All scripts must return true.
# Check that the txid in the PoP output is the transaction you actually want proof for. If you don’t know exactly what transaction you want proof for, check that the transaction actually pays for the product/service you deliver.
# Return "valid".
== Security considerations ==
* Someone can intercept the PoP-request and change any parameter in it. These can be mitigated by using secure connections. Examples of tampered parameters:
** Pop destination - Stealing your PoP.
** label - Trick you to sign an unintended pop or set a label that your wallet doesn't have any record for, resulting in a broken service. Always check the PoP before signing.
** nonce - Your pop will not validate on server.
* Someone can steal a PoP, for example by tampering with the PoP request, and try to use the service hoping to get a matching nonce. Probability per try: 1/(2^48). The server should have a mechanism for detecting a brute force attack of this kind, or at least slow down the process by delaying the PoP request by some 100 ms or so.
* Even if a wallet has no funds it might still be valuable as a generator for PoPs. This makes it important to keep the security of the wallet after it has been emptied.
* Transaction malleability may cause the server to have a different transaction id for a payment than the client's wallet. In that case the wallet will not be able to prove the transaction to the server. Wallets should not rely on the transaction id of the outgoing transaction. Instead it should listen for the transaction on the network and put that in its list of transactions.
== Reference implementation ==
[https://github.com/kallerosenbaum/poppoc PoP Demo server on GitHub]
[https://github.com/kallerosenbaum/wallet PoP-enabled Mycelium fork on GitHub]
== References ==
[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP0021]: URI Scheme
[https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki BIP0070]: Payment Protocol
[https://github.com/bitcoin/bips/blob/master/bip-0121.mediawiki BIP0121]: Proof of Payment URI scheme
================================================
FILE: bip-0121.mediawiki
================================================
BIP: 121
Layer: Applications
Title: Proof of Payment URI scheme
Authors: Kalle Rosenbaum
Status: Closed
Type: Specification
Assigned: 2015-07-27
== Abstract ==
This is a proposal for a URI scheme to be used in the Proof of Payment
process.
== Motivation ==
To make a Proof of Payment, the party that wants the proof needs to
transfer a Proof of Payment request to the wallet software of the
other party. To facilitate that transfer, a new URI scheme
representing the PoP request is proposed. This URI can then be encoded
in QR images or be sent over NFC in order to transfer it to the wallet.
== Specification ==
The specification is the same as BIP0021, with the following
differences:
* The URI scheme is btcpop instead of bitcoin
* The path component, i.e. the address part, is always empty.
* A mandatory p parameter whose value contains the destination for the PoP. This could for example be a https: URL or a mailto: URI.
* A mandatory n parameter representing the nonce, base58 encoded.
* An optional txid parameter containing the Base58 encoded hash of the transaction to prove.
Just as in BIP0021, elements of the query component may contain
characters outside the valid range. These must first be encoded
according to UTF-8, and then each octet of the corresponding UTF-8
sequence must be percent-encoded as described in RFC 3986.
All parameters except p and n are hints to the
wallet on which transaction to create a PoP for.
The extensibility of BIP0021 applies to this scheme as well. For
example, a date parameter or a toaddr parameter
might be useful. req-* parameters are also allowed and obey
the same rules as in BIP0021, clients not supporting a req-*
parameter must consider the URI invalid.
=== Keep URIs short ===
Implementations should keep the URIs as short as possible. This is
because it makes QR decoding more stable. A camera with a scratched
lens or low resolution may run into problems scanning huge QR
codes. This is why the txid parameter is encoded in Base58
instead of the classic hex encoded string. We get away with 44
characters instead of 64. Also, the nonce parameter is Base58
encoded for the same reason.
== Interpretation ==
=== Transaction hints ===
The wallet processing the URI must use the hints in the PoP request to
filter its transaction set. The label, amount and
message parameters must, if present in the URI, exactly match
the data associated with the original payment according to the
following table:
{|
| btcpop: URI parameter || bitcoin: URI parameter || BIP70 PaymentDetails data
|-
| label || label || memo
|-
| amount || amount || sum of outputs.amount
|-
| message || message || -
|}
The txid parameter value must match the transaction hash of
the payment.
After filtering, the resulting transaction set is displayed to the
user who selects one of them to prove. An implementation could also
automatically select a transaction in the filtered set, but
there must still be a way for the user to select freely among the
matching transactions. If the filtered set is empty, no transaction
fits the hints and a message about that is presented to the user. If
the filtered set contains exactly one transaction, which is
preferable, that transaction can be automatically selected.
As a fallback, there must also be a way for the user to select any
transaction from the wallet regardless of the transaction hints. This
can be useful if the metadata of the wallet is lost, possibly due to a
restore from backup.
=== PoP destination p ===
The p parameter value is the destination where to send the
PoP to. This destination is typically a https: URL or a
http: URL, but it could be any type of URI, for example
mailto:. To keep btcpop: URIs short, users should
not make their p parameter unnecessarily long.
==== http: and https: URLs ====
Wallet implementations must support the http: and
https: schemes in which case POST method must be
used. The PoP is sent as a binary serialized transaction. The content
type of the POST request must be set to
application/bitcoin-pop
== Examples ==
Send PoP for a transaction with label "video 42923" to
https://www.example.com/pop/352, using nonce
0x73 0xd5 0x1a 0xbb 0xd8 0x9c:
Send PoP through mail using
mailto:pop@example.com?subject=pop444, amount
is 13370000 satoshis, nonce is 0x6f 0xe 0xfb 0x68 0x92 0xf9.
Note that the ? before subject is OK according to RFC3986,
since the query part starts from the first ?:
Send PoP for transaction with id
cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79
to pizza place at http://pizza.example.com/pop/laszlo111 using nonce 0xfc 0xcc 0x2c 0x35 0xf0 0xb8
== Reference implementation ==
[https://github.com/kallerosenbaum/poppoc PoP Demo server on GitHub]
[https://github.com/kallerosenbaum/wallet PoP-enabled Mycelium fork on GitHub]
== References ==
[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP0021]: URI Scheme
[https://github.com/bitcoin/bips/blob/master/bip-0120.mediawiki BIP0120]: Proof of Payment
[https://www.ietf.org/rfc/rfc3986.txt RFC3986]: Uniform Resource Identifier (URI): Generic Syntax
================================================
FILE: bip-0122.mediawiki
================================================
BIP: 122
Layer: Applications
Title: URI scheme for Blockchain references / exploration
Authors: Marco Pontello
Status: Draft
Type: Specification
Assigned: 2015-08-29
License: PD
Discussion: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-August/010712.html
==Abstract==
This BIP proposes a URI scheme for looking up blocks, transactions and addresses on a Blockchain explorer, or in general to make proper Blockchain references.
==Motivation==
The purpose of this URI scheme is to enable users to handle all the requests for details about blocks, transactions, etc. with their preferred tool (being that a web service or a local application).
Currently a Bitcoin client usually points to an arbitrary blockchain explorer when the user looks for the details of a transaction or allows the user to choose from a set of alternatives.
Resorting to copy + paste into a browser is often required.
The same happens with posts and messages that reference some particular txs or blocks, if they provide links at all.
==Specification==
The URI follow this form:
blockchain:[//]//
Where:
{| class="wikitable"
! style="text-align: center;" | Element
! colspan="2" style="text-align: center;" | Description
! Required?
|-
| chain
| colspan="2" | '''chain ID''' (see below) of the desired chain, leading 0s included. If omitted (which would be the usual case), Bitcoin main net is assumed.
| optional
|-
| rowspan="3" | type
| tx
| for transactions.
| rowspan="3" | required
|-
| block
| for blocks (supports both hash or height).
|-
| address
| for addresses.
|-
| hash
| colspan="2" | the relevant hash to refer to (leading zeros included), or block height.
| required
|}
====ABNF grammar====
----
===Definition of chain ID===
The '''chain ID''' of a chain is the block hash of the corresponding genesis block. For forked chains, it's the block hash of the first block after fork.
So, for example:
Bitcoin main : 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
Bitcoin test : 000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
Bitcoin regtest: 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206
An example of forked chain (Feathercoin, that forked Litecoin):
==Examples==
A transaction on Bitcoin main net:
blockchain:/tx/b462ae6eb8bdae2e060239a2a3ea5d9c3e0f9ef34d9717beb2dcf0ed42cee7da
A block on Bitcoin main net:
blockchain:/block/00000000000000000119af5bcae2926df54ae262e9071a94a99c913cc217cc72
or
blockchain:/block/372338
An address on Bitcoin main net:
blockchain:/address/16EW6Rv9P9AxFDBrZV816dD4sj1EAYUX3f
A transaction on Bitcoin test net:
blockchain://000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943/tx/3b95a766d7a99b87188d6875c8484cb2b310b78459b7816d4dfc3f0f7e04281a
==Rationale==
From the point of view of a wallet (or other Blockchain related tool) developers which need to reference Blockchain data, using this scheme mean that he can simply make it a `blockchain:` link without having to worry about any specific Blockchain explorer or provide a means for the user to select one.
Blockchain explorers in turn will simply offer to handle the `blockchain:` URI schema, the first time the user visit their website, or launch/install the application, or even set themselves if there isn't already one.
Users can link directly to their preferred block explorer (avoiding copy + paste which can be awkward on mobile devices).
== Sample implementation ==
[https://github.com/MarcoPon/blockchain-exploration Demo Blockchain: URI handler on GitHub]
==Acknowledgements==
Thanks to Btc Drak for suggesting support for different networks and Jorge Timon for the suggestion that we could identify each network by its genesis block hash.
Thanks to Richard Moore, Matt Whitlock, Andreas Schildbach for help with the structure and hierarchy of the URI scheme.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0123.mediawiki
================================================
BIP: 123
Title: BIP Classification
Authors: Eric Lombrozo
Status: Deployed
Type: Process
Assigned: 2015-08-26
License: CC0-1.0 OR FSFAP
==Abstract==
This document describes a classification scheme for BIPs.
BIPs are classified by system layers with lower numbered layers involving more intricate interoperability requirements.
The specification defines the layers and sets forth specific criteria for deciding to which layer a particular standards BIP belongs.
==Copyright==
This BIP is dual-licensed under the Creative Commons CC0 1.0 Universal and FSF All Permissive licenses.
==Motivation==
Bitcoin is a system involving a number of different standards. Some standards are absolute requirements for interoperability while others can be considered optional, giving implementers a choice of whether to support them.
In order to have a BIP process which more closely reflects the interoperability requirements, it is necessary to categorize BIPs accordingly. Lower layers present considerably greater challenges in getting standards accepted and deployed.
==Specification==
Standards BIPs are placed in one of four layers:
# Consensus
# Peer Services
# API/RPC
# Applications
Non-standards BIPs may be placed in these layers, or none at all.
===1. Consensus Layer===
The consensus layer defines cryptographic commitment structures. Its purpose is ensuring that anyone can locally evaluate whether a particular state and history is valid, providing settlement guarantees, and assuring eventual convergence.
The consensus layer is not concerned with how messages are propagated on a network.
Disagreements over the consensus layer can result in network partitioning, or forks, where different nodes might end up accepting different incompatible histories. We further subdivide consensus layer changes into soft forks and hard forks.
====Soft Forks====
In a soft fork, some structures that were valid under the old rules are no longer valid under the new rules. Structures that were invalid under the old rules continue to be invalid under the new rules.
====Hard Forks====
In a hard fork, structures that were invalid under the old rules become valid under the new rules.
===2. Peer Services Layer===
The peer services layer specifies how nodes find each other and propagate messages.
Only a subset of all specified peer services are required for basic node interoperability. Nodes can support further optional extensions.
It is always possible to add new services without breaking compatibility with existing services, then gradually deprecate older services. In this manner, the entire network can be upgraded without serious risks of service disruption.
===3. API/RPC Layer===
The API/RPC layer specifies higher level calls accessible to applications. Support for these BIPs is not required for basic network interoperability but might be expected by some client applications.
There's room at this layer to allow for competing standards without breaking basic network interoperability.
===4. Applications Layer===
The applications layer specifies high level structures, abstractions, and conventions that allow different applications to support similar features and share data.
==Classification of existing BIPs==
{| class="wikitable sortable" style="width: auto; text-align: center; font-size: smaller; table-layout: fixed;"
!Number
!Layer
!Title
!Owner
!Type
!Status
|- style="background-color: #cfffcf"
| [[bip-0001.mediawiki|1]]
|
| BIP Purpose and Guidelines
| Amir Taaki
| Process
| Active
|-
| [[bip-0002.mediawiki|2]]
|
| BIP process, revised
| Luke Dashjr
| Process
| Draft
|- style="background-color: #cfffcf"
| [[bip-0009.mediawiki|9]]
|
| Version bits with timeout and delay
| Pieter Wuille, Peter Todd, Greg Maxwell, Rusty Russell
| Informational
| Final
|- style="background-color: #ffcfcf"
| [[bip-0010.mediawiki|10]]
| Applications
| Multi-Sig Transaction Distribution
| Alan Reiner
| Informational
| Withdrawn
|- style="background-color: #cfffcf"
| [[bip-0011.mediawiki|11]]
| Applications
| M-of-N Standard Transactions
| Gavin Andresen
| Standard
| Final
|- style="background-color: #ffcfcf"
| [[bip-0012.mediawiki|12]]
| Consensus (soft fork)
| OP_EVAL
| Gavin Andresen
| Standard
| Withdrawn
|- style="background-color: #cfffcf"
| [[bip-0013.mediawiki|13]]
| Applications
| Address Format for pay-to-script-hash
| Gavin Andresen
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0014.mediawiki|14]]
| Peer Services
| Protocol Version and User Agent
| Amir Taaki, Patrick Strateman
| Standard
| Final
|-
| [[bip-0015.mediawiki|15]]
| Applications
| Aliases
| Amir Taaki
| Standard
| Deferred
|- style="background-color: #cfffcf"
| [[bip-0016.mediawiki|16]]
| Consensus (soft fork)
| Pay to Script Hash
| Gavin Andresen
| Standard
| Final
|- style="background-color: #ffcfcf"
| [[bip-0017.mediawiki|17]]
| Consensus (soft fork)
| OP_CHECKHASHVERIFY (CHV)
| Luke Dashjr
| Standard
| Withdrawn
|- style="background-color: #ffffcf"
| [[bip-0018.mediawiki|18]]
| Consensus (soft fork)
| hashScriptCheck
| Luke Dashjr
| Standard
| Accepted
|-
| [[bip-0019.mediawiki|19]]
| Applications
| M-of-N Standard Transactions (Low SigOp)
| Luke Dashjr
| Standard
| Draft
|- style="background-color: #ffcfcf"
| [[bip-0020.mediawiki|20]]
| Applications
| URI Scheme
| Luke Dashjr
| Standard
| Replaced
|- style="background-color: #cfffcf"
| [[bip-0021.mediawiki|21]]
| Applications
| URI Scheme
| Nils Schneider, Matt Corallo
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0022.mediawiki|22]]
| API/RPC
| getblocktemplate - Fundamentals
| Luke Dashjr
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0023.mediawiki|23]]
| API/RPC
| getblocktemplate - Pooled Mining
| Luke Dashjr
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0030.mediawiki|30]]
| Consensus (soft fork)
| Duplicate transactions
| Pieter Wuille
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0031.mediawiki|31]]
| Peer Services
| Pong message
| Mike Hearn
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0032.mediawiki|32]]
| Applications
| Hierarchical Deterministic Wallets
| Pieter Wuille
| Informational
| Final
|-
| [[bip-0033.mediawiki|33]]
| Peer Services
| Stratized Nodes
| Amir Taaki
| Standard
| Draft
|- style="background-color: #cfffcf"
| [[bip-0034.mediawiki|34]]
| Consensus (soft fork)
| Block v2, Height in Coinbase
| Gavin Andresen
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0035.mediawiki|35]]
| Peer Services
| mempool message
| Jeff Garzik
| Standard
| Final
|-
| [[bip-0036.mediawiki|36]]
| Peer Services
| Custom Services
| Stefan Thomas
| Standard
| Draft
|- style="background-color: #cfffcf"
| [[bip-0037.mediawiki|37]]
| Peer Services
| Connection Bloom filtering
| Mike Hearn, Matt Corallo
| Standard
| Final
|-
| [[bip-0038.mediawiki|38]]
| Applications
| Passphrase-protected private key
| Mike Caldwell, Aaron Voisine
| Standard
| Draft
|- style="background-color: #ffffcf"
| [[bip-0039.mediawiki|39]]
| Applications
| Mnemonic code for generating deterministic keys
| Marek Palatinus, Pavol Rusnak, Aaron Voisine, Sean Bowe
| Standard
| Accepted
|-
| [[bip-0042.mediawiki|42]]
| Consensus (soft fork)
| A finite monetary supply for Bitcoin
| Pieter Wuille
| Standard
| Draft
|-
| [[bip-0043.mediawiki|43]]
| Applications
| Purpose Field for Deterministic Wallets
| Marek Palatinus, Pavol Rusnak
| Informational
| Draft
|- style="background-color: #ffffcf"
| [[bip-0044.mediawiki|44]]
| Applications
| Multi-Account Hierarchy for Deterministic Wallets
| Marek Palatinus, Pavol Rusnak
| Standard
| Accepted
|- style="background-color: #ffffcf"
| [[bip-0045.mediawiki|45]]
| Applications
| Structure for Deterministic P2SH Multisignature Wallets
| Manuel Araoz, Ryan X. Charles, Matias Alejo Garcia
| Standard
| Accepted
|-
| [[bip-0047.mediawiki|47]]
| Applications
| Reusable Payment Codes for Hierarchical Deterministic Wallets
| Justus Ranvier
| Informational
| Draft
|-
| [[bip-0049.mediawiki|49]]
| Applications
| Derivation scheme for P2WPKH-nested-in-P2SH based accounts
| Daniel Weigl
| Informational
| Draft
|- style="background-color: #cfffcf"
| [[bip-0050.mediawiki|50]]
|
| March 2013 Chain Fork Post-Mortem
| Gavin Andresen
| Informational
| Final
|-
| [[bip-0060.mediawiki|60]]
| Peer Services
| Fixed Length "version" Message (Relay-Transactions Field)
| Amir Taaki
| Standard
| Draft
|- style="background-color: #cfffcf"
| [[bip-0061.mediawiki|61]]
| Peer Services
| Reject P2P message
| Gavin Andresen
| Standard
| Final
|- style="background-color: #ffcfcf"
| [[bip-0062.mediawiki|62]]
| Consensus (soft fork)
| Dealing with malleability
| Pieter Wuille
| Standard
| Withdrawn
|-
| [[bip-0064.mediawiki|64]]
| Peer Services
| getutxo message
| Mike Hearn
| Standard
| Draft
|- style="background-color: #cfffcf"
| [[bip-0065.mediawiki|65]]
| Consensus (soft fork)
| OP_CHECKLOCKTIMEVERIFY
| Peter Todd
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0066.mediawiki|66]]
| Consensus (soft fork)
| Strict DER signatures
| Pieter Wuille
| Standard
| Final
|- style="background-color: #ffffcf"
| [[bip-0067.mediawiki|67]]
| Applications
| Deterministic Pay-to-script-hash multi-signature addresses through public key sorting
| Thomas Kerin, Jean-Pierre Rupp, Ruben de Vries
| Standard
| Accepted
|- style="background-color: #cfffcf"
| [[bip-0068.mediawiki|68]]
| Consensus (soft fork)
| Relative lock-time using consensus-enforced sequence numbers
| Mark Friedenbach, BtcDrak, Nicolas Dorier, kinoshitajona
| Standard
| Final
|- style="background-color: #ffffcf"
| [[bip-0069.mediawiki|69]]
| Applications
| Lexicographical Indexing of Transaction Inputs and Outputs
| Kristov Atlas
| Informational
| Accepted
|- style="background-color: #cfffcf"
| [[bip-0070.mediawiki|70]]
| Applications
| Payment Protocol
| Gavin Andresen, Mike Hearn
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0071.mediawiki|71]]
| Applications
| Payment Protocol MIME types
| Gavin Andresen
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0072.mediawiki|72]]
| Applications
| bitcoin: uri extensions for Payment Protocol
| Gavin Andresen
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0073.mediawiki|73]]
| Applications
| Use "Accept" header for response type negotiation with Payment Request URLs
| Stephen Pair
| Standard
| Final
|-
| [[bip-0074.mediawiki|74]]
| Applications
| Allow zero value OP_RETURN in Payment Protocol
| Toby Padilla
| Standard
| Draft
|-
| [[bip-0075.mediawiki|75]]
| Applications
| Out of Band Address Exchange using Payment Protocol Encryption
| Justin Newton, Matt David, Aaron Voisine, James MacWhyte
| Standard
| Draft
|-
| [[bip-0080.mediawiki|80]]
|
| Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets
| Justus Ranvier, Jimmy Song
| Informational
| Deferred
|-
| [[bip-0081.mediawiki|81]]
|
| Hierarchy for Colored Voting Pool Deterministic Multisig Wallets
| Justus Ranvier, Jimmy Song
| Informational
| Deferred
|-
| [[bip-0083.mediawiki|83]]
| Applications
| Dynamic Hierarchical Deterministic Key Trees
| Eric Lombrozo
| Standard
| Draft
|-
| [[bip-0099.mediawiki|99]]
|
| Motivation and deployment of consensus rule changes ([soft/hard]forks)
| Jorge Timón
| Informational
| Draft
|- style="background-color: #ffcfcf"
| [[bip-0101.mediawiki|101]]
| Consensus (hard fork)
| Increase maximum block size
| Gavin Andresen
| Standard
| Withdrawn
|-
| [[bip-0102.mediawiki|102]]
| Consensus (hard fork)
| Block size increase to 2MB
| Jeff Garzik
| Standard
| Draft
|-
| [[bip-0103.mediawiki|103]]
| Consensus (hard fork)
| Block size following technological growth
| Pieter Wuille
| Standard
| Draft
|-
| [[bip-0105.mediawiki|105]]
| Consensus (hard fork)
| Consensus based block size retargeting algorithm
| BtcDrak
| Standard
| Draft
|-
| [[bip-0106.mediawiki|106]]
| Consensus (hard fork)
| Dynamically Controlled Bitcoin Block Size Max Cap
| Upal Chakraborty
| Standard
| Draft
|-
| [[bip-0107.mediawiki|107]]
| Consensus (hard fork)
| Dynamic limit on the block size
| Washington Y. Sanchez
| Standard
| Draft
|-
| [[bip-0109.mediawiki|109]]
| Consensus (hard fork)
| Two million byte size limit with sigop and sighash limits
| Gavin Andresen
| Standard
| Draft
|- style="background-color: #ffffcf"
| [[bip-0111.mediawiki|111]]
| Peer Services
| NODE_BLOOM service bit
| Matt Corallo, Peter Todd
| Standard
| Accepted
|- style="background-color: #cfffcf"
| [[bip-0112.mediawiki|112]]
| Consensus (soft fork)
| CHECKSEQUENCEVERIFY
| BtcDrak, Mark Friedenbach, Eric Lombrozo
| Standard
| Final
|- style="background-color: #cfffcf"
| [[bip-0113.mediawiki|113]]
| Consensus (soft fork)
| Median time-past as endpoint for lock-time calculations
| Thomas Kerin, Mark Friedenbach
| Standard
| Final
|-
| [[bip-0114.mediawiki|114]]
| Consensus (soft fork)
| Merkelized Abstract Syntax Tree
| Johnson Lau
| Standard
| Draft
|-
| [[bip-0120.mediawiki|120]]
| Applications
| Proof of Payment
| Kalle Rosenbaum
| Standard
| Draft
|-
| [[bip-0121.mediawiki|121]]
| Applications
| Proof of Payment URI scheme
| Kalle Rosenbaum
| Standard
| Draft
|-
| [[bip-0122.mediawiki|122]]
| Applications
| URI scheme for Blockchain references / exploration
| Marco Pontello
| Standard
| Draft
|-
| [[bip-0123.mediawiki|123]]
|
| BIP Classification
| Eric Lombrozo
| Process
| Draft
|-
| [[bip-0124.mediawiki|124]]
| Applications
| Hierarchical Deterministic Script Templates
| Eric Lombrozo, William Swanson
| Informational
| Draft
|- style="background-color: #ffffcf"
| [[bip-0125.mediawiki|125]]
| Applications
| Opt-in Full Replace-by-Fee Signaling
| David A. Harding, Peter Todd
| Standard
| Accepted
|-
| [[bip-0126.mediawiki|126]]
|
| Best Practices for Heterogeneous Input Script Transactions
| Kristov Atlas
| Informational
| Draft
|- style="background-color: #ffffcf"
| [[bip-0130.mediawiki|130]]
| Peer Services
| sendheaders message
| Suhas Daftuar
| Standard
| Accepted
|-
| [[bip-0131.mediawiki|131]]
| Consensus (hard fork)
| "Coalescing Transaction" Specification (wildcard inputs)
| Chris Priest
| Standard
| Draft
|- style="background-color: #ffcfcf"
| [[bip-0132.mediawiki|132]]
|
| Committee-based BIP Acceptance Process
| Andy Chase
| Process
| Withdrawn
|-
| [[bip-0133.mediawiki|133]]
| Peer Services
| feefilter message
| Alex Morcos
| Standard
| Draft
|-
| [[bip-0134.mediawiki|134]]
| Consensus (hard fork)
| Flexible Transactions
| Tom Zander
| Standard
| Draft
|-
| [[bip-0140.mediawiki|140]]
| Consensus (soft fork)
| Normalized TXID
| Christian Decker
| Standard
| Draft
|-
| [[bip-0141.mediawiki|141]]
| Consensus (soft fork)
| Segregated Witness (Consensus layer)
| Eric Lombrozo, Johnson Lau, Pieter Wuille
| Standard
| Draft
|-
| [[bip-0142.mediawiki|142]]
| Applications
| Address Format for Segregated Witness
| Johnson Lau
| Standard
| Deferred
|-
| [[bip-0143.mediawiki|143]]
| Consensus (soft fork)
| Transaction Signature Verification for Version 0 Witness Program
| Johnson Lau, Pieter Wuille
| Standard
| Draft
|-
| [[bip-0144.mediawiki|144]]
| Peer Services
| Segregated Witness (Peer Services)
| Eric Lombrozo, Pieter Wuille
| Standard
| Draft
|-
| [[bip-0145.mediawiki|145]]
| API/RPC
| getblocktemplate Updates for Segregated Witness
| Luke Dashjr
| Standard
| Draft
|-
| [[bip-0146.mediawiki|146]]
| Consensus (soft fork)
| Dealing with signature encoding malleability
| Johnson Lau, Pieter Wuille
| Standard
| Draft
|-
| [[bip-0147.mediawiki|147]]
| Consensus (soft fork)
| Dealing with dummy stack element malleability
| Johnson Lau
| Standard
| Draft
|-
| [[bip-0150.mediawiki|150]]
| Peer Services
| Peer Authentication
| Jonas Schnelli
| Standard
| Draft
|-
| [[bip-0151.mediawiki|151]]
| Peer Services
| Peer-to-Peer Communication Encryption
| Jonas Schnelli
| Standard
| Draft
|-
| [[bip-0152.mediawiki|152]]
| Peer Services
| Compact Block Relay
| Matt Corallo
| Standard
| Draft
|}
================================================
FILE: bip-0124.mediawiki
================================================
==Abstract==
This BIP defines a script template format that can be used by wallets to deterministically generate scripts with specific authorization policies using the key derivation mechanism defined in BIP32.
==Motivation==
Currently existing wallets typically issue scripts in only a tiny handful of widely used formats. The most popular formats are pay-to-pubkey-hash and m-of-n pay-to-script-hash (BIP16). However, different wallets tend to use mutually incompatible derivation schemes to generate signing keys and construct scripts from them. Moreover, with the advent of hashlocked and timelocked contracts (BIP65, BIP112), it is necessary for different wallets to be able to cooperatively generate even more sophisticated scripts.
In addition, there's a lot of ongoing work in the development of multilayered protocols that use the blockchain as a settlement layer (i.e. the Lightning Network). These efforts require sufficiently generalized templates to allow for rapidly evolving script designs.
This BIP provides a generalized format for constructing a script template that guarantees that different wallets will all produce the same scripts for a given set of derivation paths according to BIP32.
==Specification==
===Keys===
An individual key is determined by a BIP32 derivation path and an index. For convenience, we introduce the following notation:
'''A'''k = (derivation path for A)/k
===Key Groups===
Let '''m'''i denote distinct BIP32 derivation paths. We define a key group of n keys as a set of key derivation paths with a free index k:
{'''K'''k} = { '''m'''1/k, '''m'''2/k, '''m'''3/k, ..., '''m'''n/k }
Key groups are useful for constructing scripts that are symmetric in a set of keys. Scripts are symmetric in a set of keys if the semantics of the script is unaffected by permutations of the keys. Key groups enforce a canonical form and can improve privacy.
===Sorting===
We define a lexicographic sorting of the keys. (TODO: specification of sorting conventions - compressed pubkeys, encoding, etc...)
Define {'''K'''k}j to be the jth element of the sorted keys for derivation index k.
===Script Templates===
We construct script templates by inserting placeholders for data into a script. To denote a placeholder, we use the following notation:
''Script''('''A''') = opcodes ['''A'''] opcodes
We extend this notation to an arbitrary number of placeholders:
''Script''('''X1''', '''X2''', ..., '''Xn''') = opcodes ['''X1'''] opcodes ['''X2'''] opcodes ... opcodes ['''Xn'''] opcodes
We introduce the following convenient notation for sorted key groups:
[{'''K'''k}] = [{'''K'''k}1] [{'''K'''k}2] ... [{'''K'''k}n]
===Operations on Keys===
In some applications, we might want to insert the result of some operation performed on a key rather than the key itself into the script. For example, we might want to insert a Hash160 of key '''A'''k. We can use the following notation:
[''Hash160''('''A'''k)]
===Encoding===
TODO
==Examples==
===2-of-3 Multisig===
The script template is defined by:
''Script''('''X''') = 2 ['''X'''] 3 OP_CHECKMULTISIG
Letting '''K'''k = { '''m'''1/k, '''m'''2/k, '''m'''3/k }, the ''k''th script for this key group is denoted by ''Script''({'''K'''k}).
===1-of-1 or 2-of-3===
The script template is defined by:
''Script''('''A''', '''B''') =
OP_DUP ['''A'''] OP_CHECKSIG
OP_NOTIF
2 ['''B'''] 3 OP_CHECKMULTISIGVERIFY
OP_NOTIF
OP_ENDIF
OP_TRUE
Let '''M'''k = '''m'''/k be a key of a superuser that can authorize all transactions and {'''K'''k} be a key group of three users that can only authorize transactions if at least two of them agree.
The ''k''th script is given by ''Script''('''M'''k, {'''K'''k}).
===Timelocked Contract===
The output is payable to Alice immediately if she knows the private key for '''A'''k. Bob must know the private key for '''B'''k and also wait for a timeout '''t''' before being able to spend the output.
The script template is defined by:
''Script''('''A''', '''B''', '''T''') =
OP_IF
OP_DUP OP_HASH160 [''Hash160''('''A''')] OP_EQUALVERIFY OP_CHECKSIG
OP_ELSE
['''T'''] OP_CHECKLOCKTIMEVERIFY OP_DROP
OP_DUP OP_HASH160 [''Hash160''('''B''')] OP_EQUALVERIFY OP_CHECKSIG
OP_ENDIF
The ''k''th script with timeout '''t''' is given by ''Script''('''A'''k, '''B'''k, '''t''').
==References==
* [[bip-0016.mediawiki|BIP16 - Pay to Script Hash]]
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0065.mediawiki|BIP65 - OP_CHECKLOCKTIMEVERIFY]]
* [[bip-0112.mediawiki|BIP112 - CHECKSEQUENCEVERIFY]]
* [[https://lightning.network/lightning-network-paper.pdf|Lightning Network Whitepaper]]
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0125.mediawiki
================================================
BIP: 125
Layer: Applications
Title: Opt-in Full Replace-by-Fee Signaling
Authors: David A. Harding
Peter Todd
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0125
Status: Deployed
Type: Specification
Assigned: 2015-12-04
License: PD
==Abstract==
Many nodes today will not replace any transaction in their mempool with
another transaction that spends the same inputs, making it difficult for
spenders to adjust their previously-sent transactions to deal with
unexpected confirmation delays or to perform other useful replacements.
The opt-in full Replace-by-Fee (opt-in full-RBF) signaling policy
described here allows spenders to add a signal to a transaction indicating
that they want to be able to replace that transaction in the future.
In response to this signal,
* Nodes may allow transactions containing this signal to be replaced in their mempools.
* The recipient or recipients of a transaction containing this signal may choose not to treat it as payment until it has been confirmed, eliminating the risk that the spender will use allowed replacements to defraud them.
Nodes and recipients may continue to treat transactions without the
signal the same way they treated them before, preserving the existing
status quo.
==Summary==
This policy specifies two ways a transaction can signal that it is
replaceable.
* '''Explicit signaling:''' A transaction is considered to have opted in to allowing replacement of itself if any of its inputs have an nSequence number less than (0xffffffff - 1).
* '''Inherited signaling:''' Transactions that don't explicitly signal replaceability are replaceable under this policy for as long as any one of their ancestors signals replaceability and remains unconfirmed.
===Implementation Details===
The initial implementation expected in Bitcoin Core 0.12.0 uses the following rules:
One or more transactions currently in the mempool (original
transactions) will be replaced by a new transaction (replacement
transaction) that spends one or more of the same inputs if,
# The original transactions signal replaceability explicitly or through inheritance as described in the above Summary section.
# The replacement transaction may only include an unconfirmed input if that input was included in one of the original transactions. (An unconfirmed input spends an output from a currently-unconfirmed transaction.)
# The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
# The replacement transaction must also pay for its own bandwidth at or above the rate set by the node's minimum relay fee setting. For example, if the minimum relay fee is 1 satoshi/byte and the replacement transaction is 500 bytes total, then the replacement must pay a fee at least 500 satoshis higher than the sum of the originals.
# The number of original transactions to be replaced and their descendant transactions which will be evicted from the mempool must not exceed a total of 100 transactions.
The initial implementation may be seen in
[https://github.com/bitcoin/bitcoin/pull/6871 Bitcoin Core PR#6871]
and specifically the master branch commits from
5891f870d68d90408aa5ce5b597fb574f2d2cbca to
16a2f93629f75d182871f288f0396afe6cdc8504 (inclusive).
===Receiving wallet policy===
Wallets that display unconfirmed transactions to users or that provide
data about unconfirmed transactions to automated systems should consider
doing one of the following:
# Conveying additional suspicion about opt-in full-RBF transactions to the user or data consumer.
# Ignoring the opt-in transaction until it has been confirmed.
Because descendant transactions may also be replaceable under this
policy through inherited signaling, any method used to process opt-in
full-RBF transactions should be inherited by any descendant transactions
for as long as any ancestor opt-in full-RBF transactions remain
unconfirmed.
===Spending wallet policy===
Wallets that don't want to signal replaceability should use either a max
sequence number (0xffffffff) or a sequence number of (0xffffffff-1) when
they also want to use locktime; all known wallets currently do this.
They should also take care not to spend any unconfirmed transaction that
signals replaceability explicitly or through inherited signaling; most wallets also
currently do this by not spending any unconfirmed transactions except
for those they created themselves.
Wallets that do want to make replacements should use explicit signaling
and meet the criteria described above in the Implementation Details
section. A
[https://en.bitcoin.it/wiki/Transaction_replacement Bitcoin Wiki page]
has been created to help wallet authors track deployed mempool policies
relating to transaction replacement.
The initial implementation makes use of P2P protocol reject messages for
rejected replacements, allowing P2P clients to determine whether their
replacements were initially accepted by their peers. Standard P2P
lightweight client practice of sending to some peers while listening for
relays from other peers should allow clients to determine whether the
replacement has propagated.
==Motivation==
Satoshi Nakamoto's original Bitcoin implementation provided the
nSequence number field in each input to
[https://github.com/trottier/original-bitcoin/blob/master/src/main.cpp#L434 allow replacement]
of transactions containing that input within the
mempool. When receiving replacements, nodes were supposed to replace
transactions whose inputs had lower sequence numbers with transactions
that had higher sequence numbers.
In that implementation, replacement transactions did not have to pay
additional fees, so there was no direct incentive for miners to
include the replacement and no built-in rate limiting that prevented
overuse of relay node bandwidth. Nakamoto
[https://github.com/bitcoin/bitcoin/commit/05454818dc7ed92f577a1a1ef6798049f17a52e7#diff-118fcbaaba162ba17933c7893247df3aR522 removed replacement]
from Bitcoin version 0.3.12, leaving only the
comment, "Disable replacement feature for now".
Replacing transactions with higher-fee transactions provided a way for
spenders to align their desires with miners, but by the time a
Replace-by-Fee (RBF) patch was available to re-enable replacement, some
receivers had begun to expect that the first version of a transaction
they saw was highly likely to be the version of the transaction to be
confirmed, and so some users advocated that replacement should be
disallowed.
To address those concerns, a variation on RBF was created that
required that the replacement transaction pay all of the same outputs as
the original transaction in equal or greater amount. This was called
RBF First Seen Safe (RBF-FSS), and the original RBF became known as
full-RBF. Although agreeable to recipients who relied on the
first-seen version of a transaction, each use of RBF-FSS required
adding an extra input to a transaction, resulting in wallets being
unable to use it if they had no spare inputs, a loss of privacy when
inputs from different origins get used in the same transaction, and a
wasteful increase in transaction byte size.
Opt-in full-RBF uses Nakamoto's original semantics (with a slight
tweak to allow locktime users to opt-out) to signal that replacement
is possible, providing first-seen users with the ability to ignore
those transactions while also allowing for the efficiency benefits
of full-RBF.
There are no known problematic interactions between opt-in full-RBF and
other uses of nSequence. Specifically, opt-in full-RBF is compatible
with consensus-enforced locktime as provided in the Bitcoin 0.1
implementation, BIP68 (Relative lock-time using consensus-enforced
sequence numbers), and BIP112 (CHECKSEQUENCEVERIFY).
==Deployment==
Now, and since Bitcoin's first release, 100% of the network hash rate
mines transactions using opt-in full-RBF semantics (sequence less than
(0xffffffff - 1)).
Opt-in full-RBF as a default mempool replacement policy among nodes
and miners is expected to become widespread as they upgrade to Bitcoin
Core 0.12.0 (release expected Jan/Feb 2016) and similar node software
such as Bitcoin LJR.
Actual replacement may be unreliable until two conditions have been satisfied:
# Enough nodes have upgraded to support it, providing a relay path for replacements to go from spending wallets to miners controlling significant amounts of hash rate.
# Enough hash rate has upgraded to support replacement, allowing for reasonable probability that a replacement can be mined.
==Backwards compatibility==
At the time opt-in RBF support was added/proposed, no known wallet created transactions by default with nSequence set below (0xffffffff - 1), so no known wallet explicitly signaled replaceability by default. Also no known popular wallet spent other users' unconfirmed transactions by default, so no known wallets signaled inherited replaceability.
==See also==
# [https://en.bitcoin.it/wiki/Transaction_replacement Transaction Replaceability on Bitcoin Wiki] targeted at helping wallet authors use RBF
# Tools for creating opt-in full-RBF transactions: https://github.com/petertodd/replace-by-fee-tools#replace-by-fee-tools
# [https://www.reddit.com/r/Bitcoin/comments/3urm8o/optin_rbf_is_misunderstood_ask_questions_about_it/ Reddit: Questions about opt-in RBF] targeted at helping community members understand opt-in full-RBF
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0126.mediawiki
================================================
==Abstract==
When a Bitcoin transaction contains inputs that reference previous transaction outputs sent to different Bitcoin addresses, personally identifiable information of the user will leak into the blockchain in an uncontrolled manner. While undesirable, these transactions are frequently unavoidable due to the natural fragmentation of wallet balances over time.
This document proposes a set of best practice guidelines which minimize the uncontrolled disclosure of personally identifiable information by defining standard forms for transactions containing heterogeneous input scripts.
==Copyright==
This BIP is in the public domain.
==Definitions==
* '''Heterogenous input script transaction (HIT)''': A transaction containing multiple inputs where the scripts of the previous transaction outputs being consumed are not identical (e.g. a transaction spending outputs which were sent to more than one Bitcoin address)
* '''Unavoidable heterogeneous input script transaction''': A HIT created as a result of a user’s desire to create a new output with a value larger than the value of his wallet's largest existing unspent output
* '''Intentional heterogeneous input script transaction''': A HIT created as part of a user protection protocol for reducing uncontrolled disclosure of personally-identifying information (PII)
Throughout this procedure, when input scripts are evaluated for uniqueness, "input script" should be interpreted to mean, "the script of the previous output referenced by an input to a transaction".
==Motivations==
The recommendations in this document are designed to accomplish three goals:
# Maximise the effectiveness of user-protecting protocols: Users may find that protection protocols are counterproductive if such transactions have a distinctive fingerprint which renders them ineffective.
# Minimise the adverse consequences of unavoidable heterogeneous input transactions: If unavoidable HITs are indistinguishable from intentional HITs, a user creating an unavoidable HIT benefits from ambiguity with respect to graph analysis.
# Limiting the effect on UTXO set growth: To date, non-standardized intentional HITs tend to increase the network's UTXO set with each transaction; this standard attempts to minimize this effect by standardizing unavoidable and intentional HITs to limit UTXO set growth.
In order to achieve these goals, this specification proposes a set of best practices for heterogeneous input script transaction creation. These practices accommodate all applicable requirements of both intentional and unavoidable HITs while maximising the effectiveness of both in terms of preventing uncontrolled disclosure of PII.
In order to achieve this, two forms of HIT are proposed: Standard form and alternate form.
==Interaction with Other Procedures==
Applications which wish to comply both with this procedure and BIP69 should apply this procedure prior to applying BIP69.
==Standard form heterogeneous input script transaction==
===Rules===
A HIT is Standard form if it adheres to all of the following rules:
# The number of unique output scripts must be equal to the number of unique input scripts (irrespective of the number of inputs and outputs).
# All output scripts must be unique.
# At least one pair of outputs must be of equal value.
# The largest output in the transaction is a member of a set containing at least two identically-sized outputs.
===Rationale===
The requirement for equal numbers of unique input/output scripts instead of equal number of inputs/outputs accommodates user-protecting UTXO selection behavior. Wallets may contain spendable outputs with identical scripts due to intentional or accidental address reuse, or due to dusting attacks. In order to minimise the adverse consequences of address reuse, any time a UTXO is included in a transaction as an input, all UTXOs with the same spending script should also be included in the transaction.
The requirement that all output scripts are unique prevents address reuse. Restricting the number of outputs to the number of unique input scripts prevents this policy from growing the network’s UTXO set. A standard form HIT transaction will always have a number of inputs greater than or equal to the number of outputs.
The requirement for at least one pair of outputs in an intentional HIT to be of equal value results in optimal behavior, and causes intentional HITs to resemble unavoidable HITs.
==Alternate form heterogeneous input script transactions==
The formation of a standard form HIT is not possible in the following cases:
# The HIT is unavoidable, and the user’s wallet contains an insufficient number or size of UTXOs to create a standard form HIT.
# The user wishes to reduce the number of utxos in their wallet, and does not have any sets of utxos with identical scripts.
When one of the following cases exist, a compliant implementation may create an alternate form HIT by constructing a transaction as follows:
===Procedure===
# Find the smallest combination of inputs whose value is at least the value of the desired spend.
## Add these inputs to the transaction.
## Add a spend output to the transaction.
## Add a change output to the transaction containing the difference between the current set of inputs and the desired spend.
# Repeat step 1 to create a second pair of outputs, where one output has the same value as the spend output of the previous step.
# (optional) Repeat step 2 until the desired number of inputs have been consumed and/or the desired number outputs have been created.
# Adjust the change outputs as necessary to pay the desired transaction fee.
Clients which create intentional HITs must have the capability to form alternate form HITs, and must do so for a non-zero fraction of the transactions they create.
===Rules===
An HIT formed via the preceding procedure will adhere to the following conditions:
# The number of unique input scripts must exceed the number of output scripts.
# All output scripts must be unique.
# At least one pair of outputs must be of equal value.
## "Standard outputs" refers to the set of outputs with equal value
## "Standard value" refers to the value of the standard outputs
## "Change outputs" refers to all outputs which are not standard outputs
# For a HIT containing n standard outputs, there must exist at least one possible way to organize the inputs and outputs into n sets, where all sets satisfy the following:
## The set contains one or more inputs, exactly one standard output, and exactly one change output
## An input or output that appears in one set must not appear in any other set
## The sum of the inputs in the set minus the value of the change output is equal to the standard value with a tolerance equal to the transaction fee.
## Change outputs with a value of zero (virtual change outputs) are permitted. The are defined for the purpose of testing whether or not a HIT adheres to this specification but are not present in the version of the transaction which is broadcast to the network.
==Non-compliant heterogeneous input script transactions==
If a user wishes to create an output that is larger than half the total size of their spendable outputs, or if their inputs are not distributed in a manner in which the alternate form procedure can be completed, then the user can not create a transaction which is compliant with this procedure.
==Reference==
* [[bip-0069.mediawiki|BIP69 - Lexicographical Indexing of Transaction Inputs and Outputs]]
================================================
FILE: bip-0127.mediawiki
================================================
==Abstract==
This BIP describes a simple way to construct proof-of-reserves transactions.
This proposal formalizes a standard format for constructing such proofs, easing
their construction with existing wallet infrastructure and enabling general
proof-verification software. It relies on existing standards such as regular
Bitcoin transaction serialization/validation and the BIP 174 PSBT format.
The proposal also includes the description of a PSBT extension for a better
user experience.
==Copyright==
This BIP is licensed under the Creative Commons CC0 1.0 Universal license.
==Motivation==
From the very early days in the history of Bitcoin, there have been companies
managing bitcoins for their users. These users give up control over their coins
in return for a certain service. Inevitably, there have been many cases of
companies losing their users' bitcoins without timely disclosing such events to
the public. Proofs of Reserves are a way for companies managing large amounts
of bitcoins to prove ownership over a given amount of funds. The regular proof
of control helps to ensure that no significant loss has occurred.
While the term proof-of-reserves is not new by any means, the procedure is not
very common among high-value custodian companies. One of the reasons for this
is that every company that wants to perform a proof-of-reserves has to construct
its own way to do so. Accordingly, their users have to understand the
construction of the proof in order to be able to verify it. This raises the bar
of entry both for custodians and for users.
===What this BIP is not doing===
The proof-of-reserve construction described in this document has some known
shortcomings, mostly with regards to its privacy properties. While there exists
research about improved proof-of-reserves mechanisms that have much better
privacy propertiesDagher, Gaby G., Benedikt Bünz, Joseph Bonneau, Jeremy
Clark, and Dan Boneh. "Provisions: Privacy-preserving proofs of solvency for
Bitcoin exchanges." (2015)., this BIP intentionally only formalizes
the de-facto existing method.
==Specification==
Our specification consists of two parts:
# the format for the actual proofs
# a file format used to package a set of proofs and relevant metadata
The final construction should have the following properties:
* flexible proof construction to support complex wallet infrastructures
* easy integration with existing wallet solutions (both hardware and software wallets)
* support for verification via a standard procedure, regardless of publisher of the proof
* proof prevents reuse of proofs by other parties by committing to a message
* allow validating that the issuer had the funds under his control at a certain block, regardless of what happened after that block
===Proof Format===
To allow for maximal compatibility with existing systems, proofs are formatted as regular Bitcoin
transactions. However, one small adaptation to the transaction is made that has two functions:
# make the transaction unspendable to avoid putting funds at risk
# link the proof to the issuer of the proof to prevent copying proofs from other custodians
The resulting construction is a Bitcoin transaction with the following
characteristics:
* The first input (the "commitment input")
** MUST have the txid part of the previous outpoint set to the SHA-256 hash of the commitment message prefixed with "Proof-of-Reserves: "If the message is "Some Message", the txid part should be SHA-256("Proof-of-Reserves: Some Message") with the string encoded as UTF-8. and index 0.
* The remaining inputs
** MUST have signatures that commit to the commitment input (e.g. using SIGHASH_ALL).
* The transaction MUST have a single output that is the exact sum of all the inputs, assuming the commitment input to have 0 value; this means the transaction has no miner fee.
The existence of the first input (which is just a commitment hash) ensures
that this transaction is invalid and can never be confirmed.
===Proof File Format===
In theory, the first part of the specification would be sufficient as a minimum
viable standard. However, there are a number of motivations to extend the
standard with an extra layer of metadata:
# constructing and combining multiple proofs
#:Having thousands of UTXOs spread across different offline and online wallets could make it difficult to construct a single proof transaction with all UTXOs. Allowing multiple proof transactions with the same commitment message and block number gives extra flexibility to custodians with complex wallet infrastructure without making the combined proof less secure.
# metadata for verification
#:Not all systems that will be used for verification have access to a full index of all transactions. However, proofs should be easily verifiable even after some of the UTXOs used in the proof are no longer unspent. Metadata present in the proof allows for relatively efficient verification of proofs even if no transaction index is available.
# potential future improvements
#:The extensible metadata format allows for amending the standard in the future. One potential improvement would be having UTXO set commitments. These would allow the proofs-of-reserves to come with accompanying proofs-of-inclusion of all used UTXOs in the UTXO set at the block of proof construction (making validation even more efficient).
The proposed proof-file format provides a standard way of combining multiple
proofs and associated metadata. The specification of the format is in the
Protocol Buffershttps://github.com/protocolbuffers/protobuf/ format.
syntax = "proto3";
import "google/protobuf/any.proto";
message OutputMeta {
// Identify the outpoint.
bytes txid = 1;
uint32 vout = 2;
// The block hash of the block where this output was created.
bytes block_hash = 3;
}
message FinalProof {
// The proof transaction. Should be able to be parsed like a regular
// Bitcoin transaction.
bytes proof_tx = 1;
// The metadata of the outputs used in the proof transaction.
repeated OutputMeta output_metadata = 2;
}
message ProofOfReserves {
// A version number for this format to enable extending it with
// additional fields.
uint32 version = 1;
// The network magic for the network in which the proofs are valid.
// 0xD9B4BEF9 for mainnet, 0x0709110B for testnet
//TODO consider BIP44 coin type ids instead:
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
uint32 network_magic = 2;
// The commitment message for this proof-of-reserves.
// This message is global for all the proofs.
string message = 3;
// The block at which this proof is supposed to be validated.
// Verification should take into account unspentness of outputs at this
// block height.
bytes block_hash = 4;
// The set of final proof transactions with their output metadata.
repeated FinalProof final_proofs = 5;
// Reserved field that can potentially be used by proof-construction tools.
// It can be ignored for verification.
repeated google.protobuf.Any pending_proofs = 6;
}
The last field, pending_proofs, leaves open some space in the same
file that can be used by proof-construction tools. This allows them to
construct different proofs incrementally without having to switch between file
formats.
===PSBT (BIP 174) extension===
The "commitment input" detailed in the proof format section does not spend an
existing UTXO and thus shouldn't be signed (empty scriptSig and
witness). This can cause some problems when signing this type of transactions.
For example, hardware wallets often require the signer to provide information
about all inputs of transactions they are signing, such as the previous output
or previous transaction; this data obviously doesn't exist for the commitment
inputs.
For most existing devices, it's possible to circumvent these requirements by
providing dummy data or by instructing the device to ignore this specific
input. However, there is still a UX problem. Because the hardware wallet
device doesn't recognize the transaction as a proof-of-reserves transaction it
will think it is signing a regular transaction that is spending all the money
in the UTXOs. Most devices will ask for confirmation with a message along the
lines of "Are you sure you want to send XXX BTC to address [...]?". This is
not the best user experience.
An addition to the BIP 174 PSBT format could help signing devices to recognize proof-of-reserve transactions.
The following field is added to the BIP 174 INPUT map:
* Type: Proof-of-reserves commitment PSBT_IN_POR_COMMITMENT = 0x09
** Key: None. The key must only contain the 1 byte type.
*** {0x09}
** Value: The UTF-8 encoded commitment message string for the proof-of-reserves.
*** {porCommitment}
Wallets processing an input that has this field set
* MUST make sure the txid of the previous outpoint is set to the SHA-256 hash of the prefixed commitment message string, as detailed above;
* MUST assume the input value to be 0 (without requiring the previous output or transaction to be provided);
* SHOULD display the commitment message to ask the user for confirmation before signing any inputs;
* SHOULD only provide signatures with a signature hash that commits to this input;
* SHOULD accept an empty scriptSig for this input (as if the scriptPubKey was OP_TRUE).
==Compatibility==
The proof transaction specification is based on the Bitcoin transaction
serialization protocol and will thus always be compatible with serializers
that can interpret Bitcoin transactions. The protobuf file format is custom
to this BIP and has a version byte to enable updates while attempting to remain
backwards compatible.
==Implementations==
A proof-of-concept implementation of the PSBT extension in the
[https://github.com/rust-bitcoin/rust-bitcoin rust-bitcoin] project can be
found in the psbt-por branch here:
https://github.com/stevenroose/rust-bitcoin/tree/psbt-por
A work-in-progress implementation of a tool that produces and verifies proofs
in the described format can be found here:
https://github.com/stevenroose/reserves
An implementation of the custom proof PSBTs is part of the [https://bitcoindevkit.org/ BDK], and can be found here: https://crates.io/crates/bdk-reserves
== Footnotes ==
================================================
FILE: bip-0128.mediawiki
================================================
== Abstract ==
This document proposes a standard format for saving timelock-recovery plans, to allow different
wallets to generate them, and different services to monitor/execute them.
== Motivation ==
Pre-signed transactions are one way to create a recovery-plan, for use in case of seed loss or
inheritance.
The most common example is a single pre-signed transaction with an nLocktime set to a
future date, as explained in [[bip-0065.mediawiki|BIP-65]].
One limitation of this approach is that in the happy-flow scenario, when the seed is not lost,
and the nLocktime is about to be reached, the user must access their wallet and spend
one of its UTXOs - in order to revoke the pre-signed transaction and prevent it from being able to
move the funds with no cancellation period.
This could be frustrating, for example, for users that split their seed over multiple geographic
locations.
''Timelock-Recovery plans'' are a way to pre-sign a pair of transactions that eventually move the
funds to one or more secondary wallets - with a special nSequence relative-locktime
in the second transaction, so that the user always has a cancellation-period.
Executing and monitoring a ''Timelock-Recovery plan'' thus requires more than broadcasting and
monitoring a single transaction. It also requires mechanisms for accelerating the first
transaction (which does not move most funds to the secondary wallet), for checking whether
the relative-timelock has passed, and a more nuanced handling of reorgs.
This BIP proposes a standard format for exporting ''Timelock-Recovery plans'' from the wallet that
generated them, and importing them into apps/services for monitoring/execution.
=== Comparison with Script-Based Wallets ===
Script-based wallets are another way to create recovery mechanisms, and can use absolute and
relative locktimes using OP_CHECKLOCKTIMEVERIFY ([[bip-0065.mediawiki|BIP-65]]) and
OP_CHECKSEQUENCEVERIFY ([[bip-0112.mediawiki|BIP-112]]).
For example, we can build a script that allows one main key to spend the funds at any time,
and a secondary key to spend the funds only in transactions with nLocktime above a certain
date/block-height, or only in transactions with nSequence above a certain relative
time-gap/number-of-blocks.
This makes the secondary key useful only after an absolute date/block-height, or after
a relative time since the funds were received (each UTXO independently).
This approach does have some advantages over pre-signed transactions, for example the
recovery-mechanism automatically applies to new funds received into the wallet.
However, script-based wallets have some disadvantages over a sequence of
pre-signed transactions:
* Script-based wallets are harder to implement correctly by hardware wallets, and harder to backup properly (i.e. users may forget to backup wallet-descriptors even for basic multisig wallets).
* As of the time of writing, scripts can limit when secondary-keys can be used, but not how they can be used: if the user doesn't touch the wallets' UTXOs for long-enough time, the secondary key will eventually become useable and could move the funds anywhere. This is true whether we measure the time in absolute terms (OP_CHECKLOCKTIMEVERIFY) or relative terms compared to when the wallets' UTXOs were created (OP_CHECKSEQUENCEVERIFY). This means that even in the happy-flow scenario of an untouched wallet, where no recovery is needed, the user must periodically "renew" the recovery-mechanism by spending the UTXO to a new wallet/address. This may be inconvenient in ultra-cold-storage scenarios (i.e. multisig with main keys hidden in different geographic locations). New opcode suggestions, such as OP_CHECKTEMPLATEVERIFY ([[bip-0119.mediawiki|BIP-119]]) and OP_CHECKCONTRACTVERIFY ([[bip-0443.mediawiki|BIP-443]]), discuss possible recovery-mechanisms in which in order for a secondary key to have full control over the funds, some onchain operations must be performed, with a required time-gap between them - giving the user enough time to revoke the whole process and move the funds elsewhere (assuming they still have the main key and the recovery-mechanism was triggered unintentionally). However, these suggestions are still in the discussion phase and even if ever implemented, their adoption may be slow.
* New Bitcoiners today typically don't think of such recovery-mechanisms in advance, and start with a P2WPKH wallet. They can pre-sign transactions with this wallet, but to utilize script-based features they would need to create a new wallet and move the funds there - an operation that might seem intimidating for large amounts.
== Specification ==
A ''Timelock-Recovery plan'' consists of two transactions:
* ''Alert Transaction'': A mostly-consolidation transaction that keeps most funds in the original wallet, except for a fee and a small fixed amount that goes to ''anchor-addresses'' - addresses which can be used to accelerate the ''Alert Transaction'' via CPFP. The majority of funds should remain on the original wallet, in a new previously-unused address which we call the ''alert-address''. We use the term ''Alert Transaction'' because monitoring the blockchain and looking for it should alert the user that the recovery-plan has been initiated (intentionally, unintentionally or maliciously).
* ''Recovery Transaction'': The transaction that moves the funds from the alert-address UTXO from the ''Alert Transaction'' to one or more addresses of secondary wallets (each may receive a different amount). This transaction should have a special nSequence relative-locktime according to the size of cancellation-period requested by the user, following the rules of [[bip-0068.mediawiki|BIP-68]].
With a reliable tool to monitor the blockchain for the ''Alert Transaction''
or the ''Alert Address'', the user can safely store online backups of the recovery plan's
JSON file (or, even without a tool, by checking the blockchain manually from time to time).
If the presigned transactions leak and the ''Alert Transaction'' is broadcast
unintentionally, the user has the cancellation period (expected to be at least a
few days) to prevent most funds from moving by sending them to a new address, thereby
invalidating the ''Recovery Transaction''.
It is important that the ''Alert Transaction'' will be non-malleable (e.g. by using
[[bip-0140.mediawiki|BIP-140]]).
If a malleable ''Alert Transaction'' is used, a malicious miner could replace the
''Alert Transaction'' with a similar transaction with a different txid,
making the ''Recovery Transaction'' invalid (pointing to a non-existent UTXO).
The nLocktime of both transactions should not be higher than the current
block height.
The ''anchor-addresses'' mentioned above, which are used for CPFP acceleration, could possibly
be P2A addresses (described in [[bip-0433.mediawiki|BIP-433]]), or other addresses under the
participants' control (i.e. addresses from the secondary wallets).
As of the time of writing, P2A is not widely adopted, and less-technical users may
struggle using them for CPFP acceleration - so we currently recommend using regular addresses.
=== nSequence calculation ===
Users will specify the cancellation-period in whole days between 2-388.
Following [[bip-0068.mediawiki|BIP-68]], the nSequence can represent a timespan in
units of 512 seconds, when bit (1 << 22) is set. An example calculation is provided below:
n_sequence = (1 << 22) | round(cancellation_period_days * 24 * 60 * 60 / 512)
Users should be notified that the cancellation-period is not guaranteed to be exact (due to miners'
manipulation of block-timestamps).
Less than 2 days of cancellation-period and partial-days are not supported, as they are not useful.
More than 388 days of cancellation-period will overflow the nSequence field bits
allocated for the relative-locktime, and is not supported.
=== JSON format ===
For simplicity, this BIP proposes that a ''Timelock-Recovery plan'' will be saved as a JSON
object.
The JSON object will have the following fields:
* kind (mandatory): must be "timelock-recovery-plan".
* id (mandatory): a non-empty string of up to 100 characters, to represent the plan uniquely (i.e. a UUID, or a server generated ID).
* name (optional): a name for the plan, decided by the user. A string of up to 200 characters.
* description (optional): a description for the plan, decided by the user. A string of up to 10,000 characters.
* created_at (mandatory): an ISO 8601 timestamp of the plan creation time, including timezone offset ('Z' if the timezone is UTC).
* plugin_version (optional): The version of the plugin that generated the plan. A string of up to 100 characters.
* wallet_version (mandatory): The version of the wallet that generated the plan. A string of up to 100 characters.
* wallet_name (mandatory): The human-readable name of the wallet app that generated the plan. A string of up to 100 characters.
* wallet_kind (mandatory): The internal name of the wallet app that generated the plan. A string of up to 100 characters.
* timelock_days (mandatory): The cancellation period in whole days. A number between 2 and 388.
* anchor_amount_sats (mandatory): The amount in satoshis sent to each anchor address in the Alert Transaction. We recommend using 600 sats, which is above the dust limit.
* anchor_addresses (mandatory): An array of up to 10,000 Bitcoin addresses that receive the anchor amount in the Alert Transaction. Each address is a string of up to 100 characters.
* alert_address (mandatory): The Bitcoin address that receives the majority of funds in the Alert Transaction. A string of up to 100 characters.
* alert_inputs (mandatory): An array of up to 2439 inputs spent by the Alert Transaction. Each input is a string in the format "txid:vout" where txid is a 64-character lowercase hexadecimal string and vout is a decimal number of up to 6 digits. The maximal length of 2439 is calculated from a standard transaction of 400,000 wu where each input contains at least 41 bytes.
* alert_tx (mandatory): The raw Alert Transaction in uppercase hexadecimal format. A string of up to 800,000 characters.
* alert_txid (mandatory): The transaction ID of the Alert Transaction. A 64-character lowercase hexadecimal string.
* alert_fee (mandatory): The total fee paid by the Alert Transaction in satoshis. A non-negative integer.
* alert_weight (mandatory): The weight of the Alert Transaction. A positive integer, not higher than 400,000.
* recovery_tx (mandatory): The raw Recovery Transaction in uppercase hexadecimal format. A string of up to 800,000 characters.
* recovery_txid (mandatory): The transaction ID of the Recovery Transaction. A 64-character lowercase hexadecimal string.
* recovery_fee (mandatory): The total fee paid by the Recovery Transaction in satoshis. A non-negative integer.
* recovery_weight (mandatory): The weight of the Recovery Transaction. A positive integer, not higher than 400,000.
* recovery_outputs (mandatory): An array of up to 10,000 outputs from the Recovery Transaction. Each output is a tuple containing: [address, amount_sats, label?] where:
** address is a mandatory Bitcoin address string (up to 100 characters).
** amount_sats is a mandatory positive integer representing the amount in satoshis.
** label is an optional string of up to 200 characters.
* metadata (optional): A string of up to 10,000 characters for additional metadata, for example a digital-signature.
* checksum (mandatory): A checksum for verifying the integrity of the plan. A string of 8 to 64 characters.
=== Checksum Calculation ===
Notice that besides the top-level JSON object, all the internal values are either primitive or
arrays.
This is intentional, so a conversion of the values to JSON strings will be deterministic.
The checksum is calculated by converting the top-level JSON object to an array of
[key, value] pairs, sorting the array, stringifying, calculating the
SHA256 hash of the result in lowercase hexadecimal format, and taking a prefix of at least 8
characters.
"stringifying" in this context means converting the array to a JSON string following
[https://262.ecma-international.org/16.0/index.html#sec-json.stringify ECMAScript's JSON.stringify function specification]
(without additional replacer or space arguments).
This specification covers special cases such as non-ascii characters and newlines.
Optional fields without a value should not be included in the key-value pairs array.
Also, there should not be a key-value pair for the "checksum" field itself.
Code example:
delete recoveryPlanJson.checksum; // In case the checksum was calculated previously and the object was then modified
const checksumData = new TextEncoder().encode(
JSON.stringify(Object.entries(recoveryPlanJson).sort()),
);
const checksum = new Uint8Array(await crypto.subtle.digest('SHA-256', checksumData));
recoveryPlanJson.checksum = Array.from(checksum).map(b => b.toString(16).padStart(2, '0')).join('').slice(0, 8);
Checksum hex string should be at least 8 characters long. Wallets may choose to use a longer
checksum.
== Rationale ==
The JSON object will contain the raw transactions, in addition to other information - some of
which could technically be extracted from the raw transactions. This is intentional, to let
frontend UIs display the plan before uploading it to any service, without the need for
complicated parsing in the frontend.
Backend services that receive the JSON object for monitoring/execution are expected to validate
that the information is consistent with the raw transactions.
Also, if some wallet apps did not implement the specifications correctly, the services could
write custom code based on the wallet_kind, wallet_version and
plugin_version fields.
Servers may decide to put more restrictions on JSON objects, for example to refuse
storing very large transactions.
Notice that the raw transactions (alert_tx and recovery_tx) are expected
to be in uppercase hexadecimal format.
This is useful for frontend UIs to display them as QR codes, which are more compact when using
uppercase-only alphanumeric characters.
=== Monitoring Timelock-Recovery Plans ===
Checking whether the Alert Transaction is valid is trivial, via the
testmempoolaccept RPC call in bitcoin core 0.17+.
However, checking whether the Recovery Transaction is valid is more complex,
since it depends on a UTXO created by the Alert Transaction.
The testmempoolaccept RPC can receive a list of transactions in which the later
transactions may depend on earlier transactions - however in our case the
Recovery Transaction has an nSequence relative-locktime, and therefore
calling testmempoolaccept 'alert-tx' 'recovery-tx' will fail, claiming that the
Alert Transaction UTXO is not confirmed (and the required time window has not passed).
We recommend services that want to verify the entire Timelock-Recovery plan to parse
the Recovery Transaction and check its signatures manually, and reject complicated
spending scripts. Discovering that the Recovery Transaction is invalid only at the
time of execution, could lead to funds being locked forever.
== Reference Implementation ==
JSON files can be generated using the Timelock Recovery plugin on
[https://electrum.org Electrum Wallet]:
https://github.com/spesmilo/electrum/tree/master/electrum/plugins/timelock_recovery
Demo Video: https://drive.google.com/file/d/10uXRouQbH1kz_HC14WnmRnYHa3gPZY8l/preview
Example JSON file:
{
"kind": "timelock-recovery-plan",
"id": "exported-692452189b301b561ed57cbe",
"name": "Recovery Plan ac300e72-7612-497e-96b0-df2fdeda59ea",
"description": "RITREK APP 1.1.0: Trezor Account #1",
"created_at": "2025-11-24T12:39:53.532Z",
"plugin_version": "1.0.1",
"wallet_version": "1.0.1",
"wallet_name": "RITREK Service",
"wallet_kind": "RITREK BACKEND",
"timelock_days": 2,
"anchor_amount_sats": 600,
"anchor_addresses": [
"bc1qnda6x2gxdh3yujd2zjpsd7qzx3awxmlaf9wwlk"
],
"alert_address": "bc1qj0f9sjenwyjs0u7mlgvptjp05z3syzq7mru3ep",
"alert_inputs": [
"a265a485df4c6417019b91379257eb387bceeda96f7bb6311794b8ed358cf104:0",
"2f621c2151f33173983133cbc1000e3b603b8a18423b0379feffe8513171d5d3:0"
],
"alert_tx": "0200000000010204F18C35EDB8941731B67B6FA9EDCE7B38EB579237919B0117644CDF85A465A20000000000FDFFFFFFD3D5713151E8FFFE79033B42188A3B603B0E00C1CB3331987331F351211C622F0000000000FDFFFFFF0258020000000000001600149B7BA329066DE24E49AA148306F802347AE36FFD205600000000000016001493D2584B33712507F3DBFA1815C82FA0A302081E02483045022100DCDBAE77C35EB4A0B3ED0DE5484206AB6B07041BE99B2BBAF0243C125916523C0220396959C3C52B2B1F9E472AEEE7C5D9540531B131C3221DE942754C6D0941397D012103C08FF3ADBA14B742646572BCA6F07AEB910666FB28E4DDDC40E33755E7C869D30248304502210089084472FDA3CF82D6ABC11BF1A5E77C9B423617C8B840F58C02746035B3BA6302203942AA1FA13F952F49FB114D48130A9AAF70151E7D09036D15734DB1F41A8B6001210397064EDED7DAD7D662290DC2847E87C5C27DA8865B89DDB58FDE9A006BA7DB3900000000",
"alert_txid": "f1413fedadaf30697820bcd8f6a393fcc73ea00a15bea3253f89d5658690d2f7",
"alert_fee": 231,
"alert_weight": 834,
"recovery_tx": "02000000000101F7D2908665D5893F25A3BE150AA03EC7FC93A3F6D8BC20786930AFADED3F41F101000000005201400001A6550000000000001600149B7BA329066DE24E49AA148306F802347AE36FFD0247304402204AFF87C2127F5697F300C6522067A8D5E5290CA8D140D2E5BCEF4A36606C5FE5022056673BEC5BB459DFFBD4D266EE95AEF0D701383ED80BD433A02C3C486A826D76012102774DBCD59F2D08EFF718BC09972ADC609FBC31C26B551B3E4EA30A1D43EEDB9700000000",
"recovery_txid": "bc304610e8f282036345e87163d4cba5b16488a3bf2e4d738379d7bda3a0bca3",
"recovery_fee": 122,
"recovery_weight": 437,
"recovery_outputs": [
[
"bc1qnda6x2gxdh3yujd2zjpsd7qzx3awxmlaf9wwlk",
21926,
"My Backup Wallet"
]
],
"metadata": "sig:825d6b3858c175c7fc16da3134030e095c4f9089c3c89722247eeedc08a7ef4f",
"checksum": "92f8b3da"
}
== Copyright ==
This document is licensed under the 2-clause BSD license.
================================================
FILE: bip-0129.mediawiki
================================================
==Introduction==
===Abstract===
This document proposes a mechanism to set up multisig wallets securely.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
The Bitcoin multisig experience has been greatly streamlined under [https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki BIP-0174
(Partially Signed Bitcoin Transaction)]. However, what is still missing is a standardized process for setting up multisig wallets securely across different vendors.
There are a number of concerns when it comes to setting up a multisig wallet:
# Whether the multisig configuration, such as Signer membership, script type, derivation paths and number of signatures required, is correct and not tampered with.
# Whether the keys or the multisig configuration are leaked during the setup.
# Whether the Signer persists the multisig configuration in their respective storage, and under what format.
# Whether the Signer's storage is tamper-proof.
# Whether the Signer subsequently uses the multisig configuration to generate and verify receive and change addresses.
An attacker who can modify the multisig configuration can steal or hold funds for ransom by duping the user into sending funds to the wrong address. An attacker who cannot modify the configuration but can learn about the keys and/or the configuration can monitor transactions in the wallet, resulting in loss of privacy.
This proposal seeks to address concerns #1, #2 and #3: to mitigate the risk of tampering during the initial setup phase, and to define an interoperable multisig configuration format.
Concerns #4 and #5 should be handled by Signers and are out of scope of this proposal.
==Specification==
===Prerequisites===
This proposal assumes the parties in the multisig support [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-0032], [https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki BIP-0322], [https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-0380 Output Script Descriptors] ([https://github.com/bitcoin/bips/blob/master/bip-0381.mediawiki BIP-0381],[https://github.com/bitcoin/bips/blob/master/bip-0382.mediawiki BIP-0382],[https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki BIP-0383]) and [https://tools.ietf.org/html/rfc3686 AES encryption].
===File Extensions===
All descriptor and key records should have a .bsms file extension. Encrypted data should have a .dat extension.
===Newline===
This specification uses line feed (LF) control character \n.
===Roles===
====Coordinator====
The Coordinator initiates the multisig setup. The Coordinator determines what type of multisig is used and the exact policy script. If encryption is enabled, the Coordinator also distributes a shared secret or shared secrets to the parties involved for secure communication. The Coordinator gathers information from the Signers to generate a descriptor record. The Coordinator distributes the descriptor record back to the Signers.
====Signer====
The Signer is any software or hardware that controls the private keys and can sign using those keys. The Signer is a participating member in the multisig. Its responsibilities include providing its key record -- which contains a public key or an Extended Public Key (XPUB) -- to the Coordinator, verifying that its KEY is included in the descriptor record and persisting the descriptor record in its storage.
===Setup Process===
====Round 1====
=====Coordinator=====
* The Coordinator creates a new multisig wallet creation session. The Coordinator constructs the multisig script and its policy parameters, such as the required number of signatures and the total number of Signers (M and N).
* The session should expire after some time period determined by the Coordinator, e.g., 24 hours. The timeout allows the encryption key to have lower entropy.
* If encryption is enabled, the Coordinator distributes a secret TOKEN to each Signer over a secure channel. The Signer can use the TOKEN to derive an ENCRYPTION_KEY. Refer to the [[#Encryption]] section below for details on the TOKEN, the key derivation function and the encryption scheme. Depending on the use case, the Coordinator can decide whether to share one common TOKEN for all Signers, or to have one per Signer.
* If encryption is disabled, the TOKEN is set to 0x00, and all the encryption/decryption steps below can be skipped.
=====Signer=====
* The Signer initiates the multisig wallet creation session by setting the TOKEN. The Signer derives an ENCRYPTION_KEY from the TOKEN. The Signer can keep the session open until a different value for the TOKEN is set.
* The Signer generates a key record by prompting the user for a multisig derivation path and retrieves the KEY at that derivation path. Alternatively, the Signer can choose a path on behalf of the user. If the Signer chooses the path, it should try to avoid reusing KEYs for different wallets.
* The first line in the record must be the specification version (BSMS 1.0 as of this writing). The second line must be the hex-encoded TOKEN. The third line must be the KEY. The KEY is a public key or an XPUB plus the key origin information, written in the descriptor-defined format, i.e.: [{master key fingerprint}/{derivation path}]{KEY}. The fourth line is a text description of the key, 80 characters maximum. The fifth line must be a SIG, whereas SIG is the signature generated by using the private key associated with the public key or XPUB to sign the first four lines. The signature should follow [https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki BIP-0322], legacy format accepted.
* The Signer calculates the Message Authentication Code (MAC) for the record. The first 16 bytes of the MAC serves as the Initialization Vector (IV) for the encryption.
* The Signer encrypts the key record with the ENCRYPTION_KEY and IV.
* The Signer encodes the MAC and the ciphertext into hexadecimal format, then concatenates the results: (MAC || ciphertext).
====Round 2====
=====Coordinator=====
* The Coordinator gathers key records from all participating Signers. The Coordinator verifies that there are exactly N unique key records before the wallet setup session expires.
* For each key record, the Coordinator extracts the MAC from the data, sets IV to the first 16 bytes of the MAC, then decrypts the ciphertext using the ENCRYPTION_KEY and IV.
* The Coordinator verifies that the included MAC is valid given the plaintext.
* The Coordinator verifies that the key records have compatible specification versions.
* The Coordinator verifies that the included SIG is valid given the KEY.
* If all key records look good, the Coordinator fills in all necessary information to generate a descriptor record.
* The first line in the descriptor record must be the specification version (BSMS 1.0 as of this writing). The second line must be a descriptor or a descriptor template. The third line must be a comma-separated list of derivation path restrictions. The paths must start with / and use non-hardened derivation. If there are no template or restrictions, it must say No path restrictions. The fourth line must be the wallet's first address. If there are path restrictions, use the first address from the first path restriction.
* The Coordinator calculates the MAC for the record. The first 16 bytes of the MAC serves as the IV for the encryption..
* The Coordinator encrypts the descriptor record with the ENCRYPTION_KEY and IV.
* The Coordinator encodes the MAC and the ciphertext into hexadecimal format, then concatenates the results: (MAC || ciphertext).
* The Coordinator sends the encrypted descriptor record to all participating Signers.
=====Signer=====
* The Signer imports the descriptor record.
* The Signer extracts the MAC from the data, sets IV to the first 16 bytes of the MAC, then decrypts the ciphertext using the ENCRYPTION_KEY (derived from the open session) and IV.
* The Signer verifies that the included MAC is valid given the plaintext.
* The Signer verifies that it can support the included specification version.
* The Signer verifies that it can support the descriptor or descriptor template.
* The Signer checks that its KEY is included in the descriptor or descriptor template, using path and fingerprint information provided. The check must perform an exact match on the KEYs and not using shortcuts such as matching fingerprints, which is trivial to spoof.
* The Signer verifies that it is compatible with the derivation path restrictions.
* The Signer verifies that the wallet's first address is valid.
* For confirmation, the Signer must display to the user the wallet's first address and policy parameters, including, but not limited to: the derivation path restrictions, M, N, and the position(s) of the Signer's own KEY in the policy script. The total number of Signers, N, is important to prevent a KEY insertion attack. The position is important for scripts where KEY order matters. When applicable, all positions of the KEY must be displayed. The full descriptor or descriptor template must also be available for review upon user request.
* Parties must check with each other that all Signers have the same confirmation (except for the KEY positions).
* If all checks pass, the Signer must persist the descriptor record in its storage.
This completes the setup.
===Encryption===
====The Token====
We define three modes of encryption.
# NO_ENCRYPTION : the TOKEN is set to 0x00. Encryption is disabled.
# STANDARD : the TOKEN is a 64-bit nonce.
# EXTENDED : the TOKEN is a 128-bit nonce.
The TOKEN can be converted to one of these formats:
* A decimal number (recommended). The number must not exceed the maximum value of the nonce.
* A mnemonic phrase using [https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP-0039] word list. This would be 6 words in STANDARD mode. This encoding is not recommended in EXTENDED mode as it can result in potential confusion between seed mnemonics and TOKEN mnemonics.
* A QR code.
* Other formats.
The flexibility in the data format allows each Signer to customize the User Experience based on its respective capabilities.
====Key Derivation====
The key derivation function is [https://tools.ietf.org/html/rfc2898 PBKDF2], with PRF = SHA512. Specifically:
DKey = PBKDF2(PRF, Password, Salt, c, dkLen)
Whereas:
* PRF = SHA512
* Password = "No SPOF"
* Salt = TOKEN
* c = 2048
* dkLen = 256 bits (32 bytes)
* DKey = Derived ENCRYPTION_KEY
====Encryption Scheme====
The encryption scheme is [https://tools.ietf.org/html/rfc3686 AES-256-CTR].
MAC = HMAC-SHA256(HMAC_Key, hex-encoded TOKEN || Data)IV = First 16 bytes of MACCiphertext = AES-256-CTR-Encrypt(Plaintext, DKey, IV)Plaintext = AES-256-CTR-Decrypt(Ciphertext, DKey, IV)
Whereas:
* DKey = ENCRYPTION_KEY
* HMAC_Key = SHA256(ENCRYPTION_KEY)
* Data = the plaintext, e.g. the entire key record in round 1 and the entire descriptor record in round 2
The MAC is to be sent along with the key and descriptor record, as specified above. Because it is a MAC over the entire plaintext, this is essentially an [https://en.wikipedia.org/wiki/Authenticated_encryption#Encrypt-and-MAC_(E&M) Encrypt-and-MAC] form of authenticated encryption.
===Descriptor Template===
The output descriptor language only supports one-dimensional lists. This proposal introduces a descriptor template to represent multi-dimensional lists:
XPUB/**
Whereas /** can be replaced by any number of derivation path restrictions.
A descriptor template must be accompanied by derivation path restrictions. Signers should expand the template into concrete descriptors by replacing /** with the restrictions.
For example, the following template and derivation path restrictions:
* wsh(sortedmulti(2,XPUB1/**,XPUB2/**))
* /0/*,/1/*
Should translate to two concrete descriptors:
* wsh(sortedmulti(2,XPUB1/0/*,XPUB2/0/*))
* wsh(sortedmulti(2,XPUB1/1/*,XPUB2/1/*))
==QR Codes==
For signers that use QR codes to transmit data, key and descriptor records can be converted to QR codes, following [https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md the BCR standard].
Also refer to [https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-015-account.md UR Type Definition for BIP44 Accounts] and [https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-010-output-desc.md UR Type Definition for Bitcoin Output Descriptors] for more details.
==Compatibility==
This specification is not backwards compatible with existing multisig implementations.
BSMS is opt-in, meaning existing multisig implementations can continue working as-is, with the caveat that they are likely to have various pitfalls. Some of the problems with existing solutions have been described in the [[#Motivation]] section.
To comply with this standard, a Signer must be able to persist the descriptor record in its storage.
To use BSMS for a multisig wallet, the user should wait until all participating Signers in the multisig have implemented BSMS.
==Security==
This proposal introduces two layers of protection. The first one is a temporary, secret TOKEN. The second one is the confirmation of the wallet's first address.
The TOKEN is used to encrypt the two rounds of communication between the Signer and the Coordinator. A MAC is also generated from the TOKEN and plaintext to authenticate the data being exchanged. The TOKEN is only needed during the setup phase, and can be safely discarded afterwards. It is not recommended to use the same TOKEN for multiple wallet creation sessions.
The wallet's first address, on the other hand, can be used to verify the integrity of the multisig configuration. An attacker who tampers with the multisig configuration must also change the wallet's first address. Parties must check with each other that all Signers confirm to the same address and policy parameters to reduce the chance of tampering.
==Privacy==
Encryption helps improve the privacy of the wallet by avoiding sharing keys and descriptors in plaintext.
If the parties wish to have stronger privacy, it is recommended to use a higher number of bits for the TOKEN, and to completely erase knowledge of the TOKEN after the multisig wallet has been set up.
==Test Vectors==
===Mode: NO_ENCRYPTION with Public Keys===
====ROUND 1====
* Coordinator
** M-of-N: 1/2
** ADDRESS_TYPE: NATIVE_SEGWIT
** TOKEN: 0x00
* Signer 1
** MASTER_KEY_FINGERPRINT: 59865f44
** PRIVATE_KEY (m/48'/0'/0'/2'): L5TXU4SdD9e6QGgBjxeegJKxt4FgATLG1TCnFM8JLyEkFuyHEqNM
** Public Key (m/48'/0'/0'/2'): 026d15412460ba0d881c21837bb999233896085a9ed4e5445bd637c10e579768ba
** Legacy signature
** signer_1_key.bsms:
==Acknowledgement==
Special thanks to Pavol Rusnak, Dmitry Petukhov, Christopher Allen, Craig Raw, Robert Spigler, Gregory Sanders, Ta Tat Tai, Michael Flaxman, Pieter Wuille, Salvatore Ingala, Ava Chow and others for their feedback on the specification.
==References==
Related mailing list threads:
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-February/018385.html
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-April/018732.html
================================================
FILE: bip-0130.mediawiki
================================================
==Abstract==
Add a new message, "sendheaders", which indicates that a node prefers to receive new block announcements via a "headers" message rather than an "inv".
==Motivation==
Since the introduction of "headers-first" downloading of blocks in 0.10, blocks will not be processed unless
they are able to connect to a (valid) headers chain. Consequently, block relay generally works
as follows:
# A node (N) announces the new tip with an "inv" message, containing the block hash
# A peer (P) responds to the "inv" with a "getheaders" message (to request headers up to the new tip) and a "getdata" message for the new tip itself
# N responds with a "headers" message (with the header for the new block along with any preceding headers unknown to P) and a "block" message containing the new block
However, in the case where a new block is being announced that builds on the tip, it would be generally more efficient if the node N just announced the block header for the new block, rather than just the block hash, and saved the peer from generating and transmitting the getheaders message (and the required block locator).
In the case of a reorg, where 1 or more blocks are disconnected, nodes currently just send an "inv" for the new tip. Peers currently are able to request the new tip immediately, but wait until the headers for the intermediate blocks are delivered before requesting those blocks. By announcing headers from the last fork point leading up to the new tip in the block announcement, peers are able to request all the intermediate blocks immediately.
==Specification==
# The sendheaders message is defined as an empty message where pchCommand == "sendheaders"
# Upon receipt of a "sendheaders" message, the node will be permitted, but not required, to announce new blocks by sending the header of the new block (along with any other blocks that a node believes a peer might need in order for the block to connect).
# Feature discovery is enabled by checking protocol version >= 70012
==Additional constraints==
As support for sendheaders is optional, software that implements this may also optionally impose additional constraints, such as only honoring sendheaders messages shortly after a connection is established.
==Backward compatibility==
Older clients remain fully compatible and interoperable after this change.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/6494
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0131.mediawiki
================================================
==Abstract==
This specification defines a new type of transaction that supplements (not replaces)
normal "non coalescing" bitcoin transactions.
==Motivation==
Normal "non-coalescing" Bitcoin Transactions have one large inefficiency: When you want to spend
from multiple inputs with the exact same scriptPubKey, you have to list each
input separately, along with the same signature multiple times, even though the signature expresses the same information.
This bloats the transaction size and makes it expensive to spend from small value inputs.
Because small value inputs are expensive to send, they remain in the UTXO pool
which full nodes have to keep around. It is believed that long term increase of the UTXO
set can have negative scaling consequences on the network.
If maximum blocksize is made to increase *slower* than the actual number of transactions bitcoin users are sending
to the network, this problem is projected to get worse. In other words, as transaction
fees increase, the minimum economical value of a spending a UTXO will increase.
==Specification==
=== Redefinition of Transaction version ===
First, this BIP redefines the version field on transactions. The first four bytes
are defined as the version number, while the last four bytes are defined as the
transaction type. Type "0000" denotes normal transactions, and "0001" defines
coalescing transaction.
Examples:
version 1 transaction with normal inputs:
version: 10000000
version 2 transaction with normal inputs:
version: 20000000
version 2 transaction with coalescing inputs:
version: 20000001
Essentially the last bit in the version field is set to 1 to enable wildcard inputs for all
inputs present in the transaction.
=== Wildcard inputs ===
A coalescing transaction is formulated the exact same way as a version 1 transaction
with one exception: each input is treated as a "wildcard input".
A wildcard input being the value of all inputs with the exact same scriptPubKey
in a block lower or equal to the block the wildcard input is confirmed into.
== Changes needed to implement ==
The bitcoin code needs to be modified in three places in order to handle Coalescing Transactions.
1. Full Node Coalescing validation - When a full node receives a coalescing transaction, it has to
aggregate the value of all the UTXOs in the blockchain older than the input
with the same scriptPubKey. If this value is greater than or equal to the
amount of all outputs, then that coalescing transaction is valid and can be propagated.
2. Full Node Non-Coalescing validation - When a non-coalescing transaction comes in, the code needs to be modified
to check if each input has not been spent by a coalescing transaction. If there exist any
coalescing transaction in the blockchain with the same scriptPubKey found in a block *after* that input,
then the UTXO has been spent and the transaction is invalid.
3. Wallet - The user facing wallet portion of the reference client should notify
the user when their wallet contains many UTXOs that qualify it to benefit from
a coalescing transaction. Wallets should not simply replace non-coalescing transactions
with coalescing transactions in all instances.
== Isn't this BIP bad because it encourage address re-use? ==
Address re-use comes in two forms: re-use by the ''sender'', and re-use by the ''receiver''.
Re-use by the sender is basically using the same address for the change output. This is generally considered bad
since people looking through your transaction history can determine who you do business with. When
you generate a new address for every change, your privacy is conserved as it is impossible to know which
output is a recipient, and which output is the change output. This BIP has '''no effect''' on re-use
by the sender.
On the other hand, address re-use by the ''receiver'' occurs under completely different circumstances.
When you publish an address and have multiple people send to that address, you are engaging in address re-use
from the receiver. This activity has historically been considered bad because it leads to re-using a private key.
When you re-use a private key too many times, you run the risk of an attacker performing statistical analysis
on the multiple signatures, which can lead to an attacker finding out your private key.
This BIP introduces a way to spend multiple inputs ''without'' re-using the private key. In a sense, this BIP
fixes the problem that makes address re-use bad for the receiver. After this BIP becomes implemented
and deployed, address re-use by the receiver will no longer be considered bad form.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0132.mediawiki
================================================
BIP: 132
Title: Committee-based BIP Acceptance Process
Authors: Andy Chase
Status: Closed
Type: Process
Assigned: 2015-08-31
License: PD
== Abstract ==
The current process for accepting a BIP is not clearly defined. While [https://github.com/bitcoin/bips/blob/master/bip-0001.mediawiki BIP-0001] defines the process for writing and submitting a Bitcoin Improvement Proposal to the community it does not specify the precise method for which BIPs are considered accepted or rejected.
This proposal sets up a method for determining BIP acceptance.
This BIP has two parts:
* It sets up a '''process''' which a BIP goes through for comments and acceptance. The Process is:
** BIP Draft
** Submitted for comments (2 weeks)
** Waiting on opinion (2 weeks)
** BIP becomes either Accepted or Deferred
* It sets up '''committees''' for reviewing comments and indicating acceptance under precise conditions.
** Committees are authorized groups that represent client authors, miners, merchants, and users (each as a segment). Each one must represent at least 1% stake in the Bitcoin ecosystem.
BIP acceptance is defined as at least 70% of the represented percentage stake in 3 out of the 4 Bitcoin segments.
== Copyright ==
This document is placed into the public domain.
== Motivation ==
BIPs represent important improvements to Bitcoin infrastructure, and in order to foster continued innovation, the BIP process must have clearly defined stages and acceptance acknowledgement.
== Rationale ==
A committee system is used to organize the essential concerns of each segment of the Bitcoin ecosystem. Although each segment may have many different viewpoints on each BIP, in order to seek a decisive yes/no on a BIP, a representational authoritative structure is sought. This structure should be fluid, allowing people to move away from committees that do not reflect their views and should be re-validated on each BIP evaluation.
== Weaknesses ==
Each committee submits a declaration including their claim to represent a certain percentage of the Bitcoin ecosystem in some way. Though guidelines are given, it's up to each committee to prove their stake, and it's up to the reader of the opinions to decide if a BIP was truly accepted or rejected.
The author doesn't believe this is a problem because a BIP cannot be forced on client authors, miners, merchants, or users. Ultimately this BIP is a tool for determining whether a BIP is overwhelmingly accepted. If one committee's validity claim becomes the factor that decides whether the BIP will succeed or fail, this process simply didn't return a clear answer and the BIP should be considered deferred.
== Process ==
* '''Submit for Comments.''' The first BIP champion named in the proposal can call a "submit for comments" at any time by posting to the [https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev Dev Mailing List] mailing with the BIP number and a statement that the champion intends to immediately submit the BIP for comments.
** The BIP must have been assigned BIP-number (i.e. been approved by the BIP editor) to be submitted for comments.
* '''Comments.'''
** After a BIP has been submitted for comments, a two-week waiting period begins in which the community should transition from making suggestions about a proposal to publishing their opinions or concerns on the proposal.
* '''Reported Opinions.'''
** After the waiting period has past, committees must submit a summary of the comments which they have received from their represented communities.
** The deadline for this opinion is four weeks after the BIP was submitted for comments.
** Committees cannot reverse their decision after the deadline, but at their request may flag their decision as "likely to change if another submit for comments is called". Committees can change their decision if a resubmit is called.
** Opinions must include:
*** One of the following statements: "Intend to accept", "Intent to implement", "Decline to accept", "Intend to accept, but decline to implement".
*** If rejected, the opinion must cite clear and specific reasons for rejecting including a checklist for what must happen or be change for their committee to accept the proposal.
*** If accepted, the committee must list why they accepted the proposal and also include concerns they have or what about the BIP that, if things changed, would cause the committee to likely reverse their decision if another submit for comments was called.
* '''Accepted.'''
** If at least 70% of the represented percentage stake in 3 out of 4 segments accept a proposal, the BIP is considered accepted.
** If a committee fails to submit an opinion, consider the opinion "Decline to accept".
** The BIP cannot be substantially changed at this point, but can be replaced. Minor changes or clarifications are allowed but must be recorded in the document.
* '''Deferred.'''
** If the acceptance test above is not met, the BIP is sent back into suggestions.
** BIP can be modified and re-submitted for a comments no sooner than two months after the date of the previous submit for comments is called.
** The BIP is marked rejected after two failed submission attempts. A rejected BIP can still be modified and re-submitted.
== Committees ==
'''BIP Committees.'''
* BIP Committees are representational structures that represent critical segments of the Bitcoin ecosystem.
* Each committee must prove and maintain a clear claim that they represent at least 1% of the Bitcoin ecosystem in some form.
* If an organization or community does not meet that requirement, it should conglomerate itself with other communities and organizations so that it does.
* The segments that committees can be based around are:
** Bitcoin software
** Exchanges/Merchants/services/payment processors
** Mining operators
** User communities
* A person may be represented by any number of segments, but a committee cannot re-use the same resource as another committee in the same segment.
'''Committee Declarations.'''
* At any point, a Committee Declaration can be posted.
* This Declaration must contain details about:
** The segment the Committee is representing
** Who the committee claim to represent and it's compositional makeup (if made up of multiple miner orgs, user orgs, companies, clients, etc).
** Proof of claim and minimum 1% stake via:
*** Software: proof of ownership and user base (Min 1% of Bitcoin userbase)
*** Merchant: proof of economic activity (Min 1% of Bitcoin economic activity)
*** Mining: proof of work (Min 1% of Hashpower)
*** For a user organization, auditable signatures qualifies for a valid committee (Min 1% of Bitcoin userbase)
** Who is running the committee, their names and roles
** How represented members can submit comments to the committee
** A code of conduct and code of ethics which the committee promises to abide by
* A committee declaration is accepted if:
** The declaration includes all of the required elements
** The stake is considered valid
** Committee validation is considered when considering the results of opinions submitted by committee on a BIP. A committee must have met the required stake percentage before a BIP is submitted for comments, and have maintained that stake until a valid opinion is submitted.
* Committees can dissolve at any time or submit a declaration at any time
* Declaration must have been submitted no later than the third day following a BIP's request for comments to be eligible for inclusion in a BIP
== BIP Process Management Role ==
BIPs, Opinions, and Committee Declaration must be public at all times.
A BIP Process Manager should be chosen who is in charge of:
* Declaring where and how BIPs, Opinions, and Committee Declaration should be posted and updated officially.
* Maintaining the security and authenticity of BIPs, Opinions, and Committee Declarations
* Publishing advisory documents about what kinds of proof of stakes are valid and what kinds should be rejected.
* Naming a series of successors for the roles of the BIP Process Manager and BIP Editor (BIP-001) as needed.
== Conditions for activation ==
In order for this process BIP to become active, it must succeed by its own rules. At least a 4% sample of the Bitcoin community must be represented, with at least one committee in each segment included. Once at least one committee has submitted a declaration, a request for comments will be called and the process should be completed from there.
================================================
FILE: bip-0133.mediawiki
================================================
==Abstract==
Add a new message, "feefilter", which serves to instruct peers not to send "inv"'s to the node for transactions with fees below the specified fee rate.
==Motivation==
The concept of a limited mempool was introduced in Bitcoin Core 0.12 to provide protection against attacks or spam transactions of low fees that are not being mined. A reject filter was also introduced to help prevent repeated requests for the same transaction that might have been recently rejected for insufficient fee. These methods help keep resource utilization on a node from getting out of control.
However, there are limitations to the effectiveness of these approaches. The reject filter is reset after every block which means transactions that are inv'ed over a longer time period will be rerequested and there is no method to prevent requesting the transaction the first time. Furthermore, inv data is sent at least once either to or from each peer for every transaction accepted to the mempool and there is no mechanism by which to know that an inv sent to a given peer would not result in a getdata request because it represents a transaction with too little fee.
After receiving a feefilter message, a node can know before sending an inv that a given transaction's fee rate is below the minimum currently required by a given peer, and therefore the node can skip relaying an inv for that transaction to that peer.
==Specification==
# The feefilter message is defined as a message containing an int64_t where pchCommand == "feefilter"
# Upon receipt of a "feefilter" message, the node will be permitted, but not required, to filter transaction invs for transactions that fall below the feerate provided in the feefilter message interpreted as satoshis per kilobyte.
# The fee filter is additive with a bloom filter for transactions so if an SPV client were to load a bloom filter and send a feefilter message, transactions would only be relayed if they passed both filters.
# Inv's generated from a mempool message are also subject to a fee filter if it exists.
# Feature discovery is enabled by checking protocol version >= 70013
==Considerations==
The propagation efficiency of transactions across the network should not be adversely affected by this change. In general, transactions which are not accepted to a node's mempool are not relayed by this node and the functionality implemented with this message is meant only to filter those transactions. There could be a small number of edge cases where a node's mempool min fee is actually less than the filter value a peer is aware of and transactions with fee rates between these values will now be newly inhibited.
Feefilter messages are not sent to whitelisted peers if the "-whitelistforcerelay" option is set. In that case, transactions are intended to be relayed even if they are not accepted to the mempool.
There are privacy concerns with deanonymizing a node by the fact that it is broadcasting identifying information about its mempool min fee. To help ameliorate this concern, the implementation quantizes the filter value broadcast with a small amount of randomness, in addition, the messages are broadcast to different peers at individually randomly distributed times.
If a node is using prioritisetransaction to accept transactions whose actual fee rates might fall below the node's mempool min fee, it may want to consider disabling the fee filter to make sure it is exposed to all possible txid's.
==Backward compatibility==
Older clients remain fully compatible and interoperable after this change. Also, clients implementing this BIP can choose to not send any feefilter messages.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/7542
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0134.mediawiki
================================================
==Abstract==
This BIP describes the next step in making Bitcoin's most basic element,
the transaction, more flexible and easier to extend. At the same time this
fixes all known cases of malleability and resolves significant amounts of
technical debt.
==Summary==
Flexible Transactions uses the fact that the first 4 bytes in a transaction
determine the version and that the majority of the clients use a
non-consensus rule (a policy) to not accept transaction version numbers
other than those specifically defined by Bitcoin.
This BIP chooses a new version number, 4, and defines that the data
following the bytes for the version is in a format called Compact Message
Format (CMF). CMF is a flexible, token based format where each token is a
combination of a name, a format and a value. Because the name is added we
can skip unused tokens and we can freely add new tokens in a simple manner
in future. Soft fork upgrades will become much easier and cleaner this
way.
This protocol upgrade cleans up past soft fork changes like BIP68 which
reuse existing fields and do them in a better to maintain and easier
to parse system. It creates the building blocks to allow new features to be
added much cleaner in the future.
It also shows to be possible to remove signatures from transactions with
minimal upgrades of software and still maintain a coherent transaction
history. Tests show that this can reduce space usage to about 75%.
==Motivation==
After 8 years of using essentially the same transaction version and layout
Bitcoin is in need of an upgrade and lessons learned in that time are
taking into account when designing it. The most important detail is that
we have seen a need for more flexibility. For instance when the 'sequence'
fields were introduced in the old transaction format, and later deprecated
again, the end result was that all transactions still were forced to keep
those fields and grow the blockchain while they all were set to the default
value.
The way towards that flexibility is to use a generic concept made popular
various decades ago with the XML format. The idea is that we give each
field a name and this means that new fields can be added or optional fields
can be omitted from individual transactions. Some other ideas are the
standardization of data-formats (like integer and string encoding) so
we create a more consistent system.
One thing we shall not inherit from XML is its text-based format. Instead
we use the [https://github.com/bitcoinclassic/documentation/blob/master/spec/compactmessageformat.md Compact Message Format]
(CMF) which is optimized to keep the size small and fast to parse.
Token based file-formats are not new, systems like XML and HTMl use a
similar system to allow future growth and they have been quite successful
for decades in part because of this property.
Next to that this protocol upgrade will re-order the data-fields which
allows us to cleanly fix the malleability issue which means that future
technologies like Lightning Network will depend on this BIP being deployed.
At the same time, due to this re-ordering of data fields, it becomes very
easy to remove signatures from a transaction without breaking its tx-id,
which is great for future pruning features.
=== Features ===
* Fixes malleability
* Linear scaling of signature checking
* Very flexible future extensibility
* Makes transactions smaller
* Supports the Lightning Network
Additionally, in the v4 (flextrans) format we add the support for the
following proofs;
* input amount. Including the amount means we sign this transaction only if the amount we are spending is the one provided. Wallets that do not have the full UTXO DB can safely sign knowing that if they were lied to about the amount being spent, their signature is useless.
* scriptBase is the combined script of input and output, without signatures naturally. Providing this to a hardware wallet means it knows what output it is spending and can respond properly. Including it in the hash means its signature would be broken if we lied..
* Double spent-proof. Should a node detect a double spent he can notify his peers about this fact. Instead of sending the entire transactions, instead he sends only a proof. The node needs to send two pairs of info that proves that in both transactions the CTxIn are identical.
=== Tokens ===
In the compact message format we define tokens and in this specification we
define how these tokens are named, where they can be placed and which are
optional. To refer to XML, this specification would be the schema of
a transaction.
[https://github.com/bitcoinclassic/documentation/blob/master/spec/compactmessageformat.md CMF]
tokens are triplets of name, format (like PositiveInteger) and value.
Names in this scope are defined much like an enumeration where the actual
integer value (id, below) is equally important to the written name.
If any token found that is not covered in the next table it will make the
transaction that contains it invalid.
{| class="wikitable"
|-
! Name !! id !! Format !! Default Value !! Description
|-
|TxEnd || 0 ||BoolTrue || Required ||A marker that is the end of the transaction
|-
|TxInPrevHash || 1 ||ByteArray|| Required ||TxId we are spending
|-
|TxPrevIndex || 2 ||Integer || 0 ||Index in prev tx we are spending (applied to previous TxInPrevHash)
|-
|TxInputStackItem || 3 ||ByteArray|| ||A 'push' of the input script
|-
|TxInputStackItemContinued||4||ByteArray|| &nsbp; ||Another section for the same input
|-
|TxOutValue || 5 ||Integer || Required ||Amount of Satoshis to transfer
|-
|TxOutScript || 6 ||ByteArray|| Required ||The output script
|-
|TxRelativeBlockLock|| 7 ||Integer || Optional ||Part of the input stating the amount of blocks (max 0XFFFF) after that input was mined, it can be mined
|-
|TxRelativeTimeLock || 8 ||Integer || Optional ||Part of the input stating the amount of time (max 0XFFFF) after that input was mined, it can be mined. 1 Unit is 512 seconds
|-
|CoinbaseMessage || 9 ||ByteArray|| Optional ||A message and some data for a coinbase transaction. Can't be used in combination with any TxIn\* tags
|-
|NOP_1x || 1x || || Optional ||Values that will be ignored by anyone parsing the transaction
|-
|}
=== Scripting changes ===
In Bitcoin transactions version 1, checking of signatures is performed by
various opcodes. The OP_CHECKSIG, OP_CHECKMULTISIG and their equivalents
that immediately VERIFY. These are used to validate the cryptographic
proofs that users have to provide in order to spend outputs.
We additionally have some hashing-types in like SIGHASH_SINGLE that all
specify slightly different subsections of what part of a transaction will
be hashed in order to be signed.
For transactions with version 4 we calculate a sha256 hash for signing an
individual input based on the following content;
# If the hash-type is 0 or 1 we hash the tx-id of the transaction. For other hash types we selectively ignore parts of the transaction exactly like it has always worked. With the caveat that we never serialize any signatures.
# the TxId of the transaction we are spending in this input.
# the index of output of the transaction we are spending in this input.
# the input script we are signing (without the signature, naturally).
# the amount, as a var-int.
# the hash-type as a var-int.
=== Serialization order===
To keep in line with the name Flexible Transactions, there is very little
requirement to have a specific order. The only exception is cases where
there are optional values and reordering would make unclear what is meant.
For this reason the TxInPrevHash always has to be the first token to start
a new input. This is because the TxPrevIndex is optional. The tokens
TxRelativeTimeLock and TxRelativeBlockLock are part of the input and
similarly have to be set after the TxInPrevHash they belong to.
Similarly, the TxInputStackItem always has to be the first and can be
followed by a number of TxInputStackItemContinued items.
At a larger scope we define 3 sections of a transaction.
{| class="wikitable"
!Segment !! Tags !! Description
|-
|Transaction||all not elsewhere used||This section is used to make the TxId
|-
|Signatures||TxInputStackItem, TxInputStackItemContinued||The input-proofs
|-
|TxEnd||TxEnd||
|}
The TxId is calculated by taking the serialized transaction without the
Signatures and the TxEnd and hashing that.
TxEnd is there to allow a parser to know when one transaction in a stream
has ended, allowing the next to be parsed.
=== Block-malleability ===
The effect of leaving the signatures out of the calculation of the
transaction-id implies that the signatures are also not used for the
calculation of the merkle tree. This means that changes in signatures
would not be detectable and open an attack vector.
For this reason the merkle tree is extended to include (append) the hash of
the v4 transactions. The merkle tree will continue to have all the
transactions' tx-ids but appended to that are the v4 hashes that include the
signatures as well. Specifically the hash is taken over a data-blob that
is built up from:
# the tx-id
# The entire bytearray that makes up all of the transactions signatures. This is a serialization of all of the signature tokens, so the TxInputStackItem and TxInputStackItemContinued in the order based on the inputs they are associated with.
=== Future extensibility ===
The NOP_1x wildcard used in the table explaining tokens is actually a list
of 10 values that currently are specified as NOP (no-operation) tags.
Any implementation that supports the v4 transaction format should ignore
this field in a transaction. Interpreting and using the transaction as if
that field was not present at all.
Future software may use these fields to decorate a transaction with
additional data or features. Transaction generating software should not
trivially use these tokens for their own usage without cooperation and
communication with the rest of the Bitcoin ecosystem as miners certainly
have the option to reject transactions that use unknown-to-them tokens.
The amount of tokens that can be added after number 19 is practically
unlimited and they are currently specified to not be allowed in any
transaction and the transaction will be rejected if they are present.
In the future a protocol upgrade may chance that and specify meaning for
any token not yet specified here. Future upgrades should thus be quite a
lot smoother because there is no change in concepts or in format. Just new
data.
==Backwards compatibility ==
Fully validating older clients will not be able to understand or validate
version 4 transactions and will need to be updated to restore that ability.
SPV (simple payment validation) wallets need to be updated to receive or
create the new transaction type.
This BIP introduces a new transaction format without changing or
deprecating the existing one or any of its practices. Therefore it is
backwards compatible for any existing data or parsing-code.
==Reference Implementation==
Bitcoin Classic includes an implementation that is following this spec.
The spec-author rejects the notion of reference implementation. The
specification is always authoritative, the implementation is not.
The official spec can be found at;
https://github.com/bitcoinclassic/documentation/blob/master/spec/transactionv4.md
==Deployment==
To be determined
==References==
[https://github.com/bitcoinclassic/documentation/blob/master/spec/compactmessageformat.md] CMF
==Copyright==
Copyright (c) 2016 Tom Zander
This document is dual-licensed under the Creative-Commons BY-SA license v4.0
and the Open Publication License v1.0 with the following licence-options:
Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.
Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
================================================
FILE: bip-0135.mediawiki
================================================
==Abstract==
BIP9 introduced a mechanism for using the version bits to signal support for
backwards-compatible changes (soft-forks) using a tally over the previous 2016
blocks computed at re-targeting intervals. It provided for a fixed threshold and
non-configurable lock-in interval applicable to all deployments on a chain.
This document describes a generalized signaling scheme which allows each
signaling bit to have its own configurable threshold, window size (number of
blocks over which it is tallied) and a configurable lock-in period.
It extends the semantics of the signaling bits to cover arbitrary consensus
changes, referred to under the general term 'forks'. The same range
of version bits is used for signaling.
The states of the BIP9 state machine and its original parameters (name, bit,
starttime, timeout) are retained. Some state transition conditions are
extended by additional parameters ('threshold', 'windowsize', 'minlockedblocks',
'minlockedtime') to provide for fine-tuning of threshold and grace period.
==Motivation==
The Bitcoin protocol requires a flexible scheme for finding consensus on
protocol changes, to ensure that it can adapt to the needs of the market and
remain competitive as an electronic payment system.
While BIP9 has served the community well for previous deployments, there are
some shortcomings in its approach:
* it specifically applies only to backward-compatible changes
* its fixed 95% threshold is not flexible enough to allow for a 'spectrum of contentiousness' to be represented
* small minorities can veto proposed changes, which can lead to undesirable stagnation
A generalized revision of the BIP9 specification can address these issues
and satisfy the needs of the market for both soft and hard fork changes
as well as more flexible activation thresholds and upgrade (grace) periods.
The proposal should allow more freedom of choice in activation strategies
while remaining backward compatible with respect to existing BIP9-based
deployments.
==Terms and conventions==
The version bits used by this proposal for signaling deployment of forks are
referred to as 'signaling bits' or shortened to 'bits' where unambiguous.
All times in this specification are in seconds since the epoch [1].
Durations / time offsets are in seconds.
The term 'MTP' refers to the 'median time past' which is calculated as the
median nTime of a block and its 10 predecessors. It is treated as a monotonic
clock defined by a chain, and evaluated on the ancestor of a block, i.e.
MTP := '''GetMedianTimePast(block.parent)'''
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119.
==Specification==
===Backward compatibility===
This specification SHALL enable strict backward compatibility with existing
BIP9-based deployments through suitable parameter configuration. Any part of
the specification preventing full backward compatibility SHALL be considered
as erroneous and amended.
As before, a set of configuration parameters SHALL exist for the version bits
for each chain supported by an implementation. This permits each bit to be
configured independently for each chain (mainnet, testnet, etc.)
===Signaling bits===
The signaling bits SHALL comprise the 29 least significant bits of the
nVersion block header field. nVersion is a 32-bit field which is treated as
a little-endian integer.
Signaling bits SHALL be assigned numbers from 0..28 ranging from the least
significant (bit 0) to the most significant (bit 28) in the range.
The top 3 bits of nVersion MUST be set to 001 , yielding a range of possible
nVersion values between [0x20000000...0x3FFFFFFF], inclusive.
If a block's nVersion does not have its top 3 bits set to 001, all its signaling
bits MUST be treated as if they are 0 (see also: 'Tallying' section below).
===Deployment states===
With each block and fork, we associate a deployment state.
The possible states are:
# '''DEFINED''' is the first state that each fork starts out as. The genesis block for any chain SHALL by definition be in this state for each deployment.
# '''STARTED''' for blocks past the starttime.
# '''LOCKED_IN''' after STARTED, if at least threshold out of windowsize blocks have the associated bit set in nVersion, measured at next height that is evenly divisible by the windowsize.
# '''ACTIVE''' for all blocks after the grace period conditions have been met.
# '''FAILED''' if past the timeout time and LOCKED_IN was not reached.
In accordance with BIP9, a block's state SHALL never depend on its own nVersion;
only on that of its ancestors.
===Fork deployment parameters===
Each fork deployment is specified by the following per-chain parameters:
# The '''name''' specifies a very brief description of the fork, reasonable for use as an identifier. For deployments described in a single BIP, it is recommended to use the name "bipN" where N is the appropriate BIP number.
# The '''bit''' determines which bit in the nVersion field of the block is to be used to signal the fork deployment. It is chosen from the set {0,1,2,...,28}.
# The '''starttime''' specifies a minimum median time past (MTP) of a block at which the bit gains its meaning.
# The '''timeout''' specifies a time at which the deployment is considered failed. If the MTP of a block >= timeout and the fork has not yet locked in (including this block's bit state), the deployment is considered failed on all descendants of the block.
# The '''windowsize''' specifies the number of past blocks (including the block under consideration) to be taken into account for locking in a fork.
# The '''threshold''' specifies a number of blocks, in the range of 1..windowsize, which must signal for a fork in order to lock it in. The support is measured when the chain height is evenly divisible by the windowsize. If the windowsize is set to 2016 (as in BIP9) this coincides with the 2016-block re-targeting intervals.
# The '''minlockedblocks''' specifies a minimum number of blocks which a fork must remain in locked-in state before it can become active. Both minlockedblocks and minlockedtime (see below) must be satisfied before a fork can become active.
# The '''minlockedtime''' specifies a minimum grace time, an earliest time after lock-in at which the fork can become active. If the MTP of a block >= (minlockedtime + median time of the block that locked in the fork), then the fork becomes activated. Both minlockedtime and minlockedblocks (see above) must be satisfied before a fork can become active.
===Tallying===
If a block's nVersion does not have its top 3 bits set to 001, all its signaling
bits MUST be treated as if they are '0'.
A signaling bit value of '1' SHALL indicate support of a fork and SHALL count
towards its tally on a chain.
A signaling bit value of '0' SHALL indicate absence of support of a fork and
SHALL NOT count towards its tally on a chain.
The signaling bits SHALL be tallied whenever the head of the active chain
changes (including after reorganizations).
===State transitions===
The following diagram illustrates the generalized state machine:
'''NOTES:'''
The genesis block of any chain SHALL have the state DEFINED for each deployment.
A given deployment SHALL remain in the DEFINED state until it either passes the
starttime (and becomes STARTED) or the timeout time (and becomes FAILED).
Once a deployment has STARTED, the signal for that deployment SHALL be tallied
over the past windowsize blocks whenever a new block is received on that
chain.
A transition from the STARTED state to the LOCKED_IN state SHALL only occur
when all of these are true:
* the height of the received block is an integer multiple of the window size
* the MTP is below the timeout time
* at least threshold out of windowsize blocks have signaled support
A similar height synchronization precondition SHALL exist for the transition from
LOCKED_IN to ACTIVE.
These synchronization conditions are expressed by the "mod(height, windowsize) = 0"
clauses in the diagram, and have been added so that backward compatibility
with BIP9's use of the 2016-block re-targeting periods can be configured for
existing deployments (see above 'Optional full backward compatibility' section).
A transition from LOCKED_IN to ACTIVE state SHALL only occur if the height
synchronization criterion is met and two configurable 'grace period' conditions
are fulfilled:
# current height MUST be at least minlockedblocks above LOCKED_IN height
# MTP must exceed LOCKED_IN time by at least minlockedtime seconds
NOTE: If minlockedtime and minlockedblocks are both set to 0, then the fork will
proceed directly to ACTIVE state once the chain height reaches a multiple of the
windowsize.
The ACTIVE and FAILED states are terminal; a deployment stays in these states
once they are reached.
Deployment states are maintained along block chain branches.
They need re-computation when a reorganization happens.
===New consensus rules===
New consensus rules deployed by a fork SHALL be enforced for each block that has
ACTIVE state.
===Optional operator notifications===
An implementation SHOULD notify the operator when a deployment transitions
to STARTED, LOCKED_IN, ACTIVE or FAILED states.
It is RECOMMENDED that an implementation provide finer-grained notifications
to the operator which allow him/her to track the measured support level for
defined deployments.
An implementation SHOULD warn the operator if the configured (emitted) nVersion
has been overridden to contain bits set to '1' in contravention of the above
non-signaling recommendations for DEFINED forks.
It is RECOMMENDED that an implementation warn the operator if no signal has
been received for a given deployment during a full windowsize period after the
deployment has STARTED. This could indicate that something may be wrong with
the operator's configuration that is causing them not to receive the signal
correctly.
For undefined signals, it is RECOMMENDED that implementation track these and
alert their operators with supportive upgrade notifications, e.g.
* "warning: signaling started on unknown feature on version bit X"
* "warning: signaling on unknown feature reached X% (over last N blocks)"
* "info: signaling ceased on unknown feature (over last M blocks)"
Since parameters of these deployments are unknown, it is RECOMMENDED that
implementations allow the user to configure the emission of such notifications
(e.g. suitable N and M parameters in the messages above, e.g. a best-guess
window of 100 blocks).
===getblocktemplate changes===
The getblocktemplate features introduced in BIP9 remain in effect unmodified.
==Rationale==
The timeout into FAILED state allows eventual reuse of bits if a fork was not
successfully activated.
A fallow period at the conclusion of a fork attempt allows some detection of
buggy clients, and allows time for warnings and software upgrades for
successful forks. The duration of a fallow period is not specified by this
proposal, although a conventional fallow period of 3 months is RECOMMENDED.
Due to the constraints set by BIP 34, BIP 66 and BIP 65, there are only
0x7FFFFFFB possible nVersion values available. This limits to at most 30
independent deployments.
By restricting the top 3 bits to 001 we are left with 29 out of those for
the purposes of this proposal, and support two future upgrades for different
mechanisms (top bits 010 and 011).
==Guidelines==
===Parameter selection guidelines===
The following guidelines are suggested for selecting the parameters for a fork:
# '''name''' SHOULD be selected such that no two forks, concurrent or otherwise, ever use the same name.
# '''bit''' SHOULD be selected such that no two concurrent forks use the same bit. Implementers should make an effort to consult resources such as [2] to establish whether the bit they wish to use can reasonably be assumed to be unclaimed by a concurrent fork, and to announce their use ('claim') of a bit for a fork purpose on various project mailing lists, to reduce chance of collisions.
# '''starttime''' SHOULD be set to some date in the future, approximately one month after a software release date which includes the fork signaling. This allows for some release delays, while preventing triggers as a result of parties running pre-release software.
# '''timeout''' is RECOMMENDED to be 1 year (31536000 seconds) after starttime.
# '''windowsize''' SHOULD be set large enough to allow reception of an adequately precise signal. A good high-resolution value would be 2016 blocks as used in BIP9. It is NOT RECOMMENDED to use a windowsize less than 100 blocks.
# '''threshold''' SHOULD be set as high as possible to ensure a smooth activation based on the estimated support and the nature of the proposed changes. It is strongly RECOMMENDED that threshold >= windowsize / 2 (rounded up) to ensure that a proposal is only activated by majority support.
# '''minlockedblocks''' is RECOMMENDED to be set >= windowsize, to ensure that a full window passes in LOCKED_IN state. Lower values will be ineffective as the transition from LOCKED_IN to ACTIVE is guarded by a synchronization based on the window size.
# '''minlockedtime''' SHOULD only be set > 0 if a minimum LOCKED_IN time period needs be strictly enforced. It is permissible to set minlockedblocks to 0 and only specify minlockedtime, however the synchronization condition means the grace period can only expire once the time has passed AND the chain height is a multiple of the windowsize.
NOTE: If minlockedtime and minlockedblocks are both set to 0, then the fork will
proceed to ACTIVE state when the chain height reaches a multiple of the windowsize.
A later deployment using the same bit is possible as long as the starttime is
after the previous fork's timeout or activation, but it is discouraged until
necessary, and even then recommended to have a pause in between to detect
buggy software.
===Signaling guidelines===
An implementation SHOULD signal '0' on a bit if one of the following holds true:
* the deployment parameters are not DEFINED (not configured or explicitly undefined)
* the deployment is DEFINED and has not yet reached the STARTED state
* the deployment has succeeded (it has become ACTIVE)
* the deployment has FAILED
An implementation SHOULD enable the operator to choose (override) whether to
signal '0' or '1' on a bit, once its deployment has at least reached the STARTED
state.
An implementation SHOULD warn the operator if the configured (emitted) nVersion
has been overridden to contain bits set to '1' in contravention of the above
non-signaling recommendations.
A supporting miner SHOULD signal '1' on a bit for which the deployment
is LOCKED_IN state so that uptake is visible. However, this has no effect on
consensus rules.
Once LOCKED_IN, a deployment proceeds to ACTIVE solely based on the configured
grace period parameters (see 'Fork deployment parameters' above).
A miner SHOULD signal '0' on a bit if they wish to suspend signaling of support
for a fork that is DEFINED in their software.
It is NOT RECOMMENDED to signal '1' for bits where the meaning is undefined
(i.e. bits which are unclaimed by proposals).
===Settings for BIP9 compatibility===
This section lists parameter values which can be used to effect compatibility
with the existing BIP9 versionbits state machine.
The following table describes mainnet compatibility options (95%, 2016 blocks):
{| class="wikitable"
!colspan=3 |
|-
! Parameter !! BIP9 value !! BIP135 value
|-
| name || some_name || some_name
|-
| bit || b || b
|-
| starttime || T_start || T_start
|-
| timeout || T_timeout || T_timeout
|-
| windowsize || n/a || 2016
|-
| threshold || n/a || 1916
|-
| minlockedblocks || n/a || 2016
|-
| minlockedtime || n/a || 0
|}
The following table describes testnet compatibility options (75%, 2016 blocks):
{| class="wikitable"
!colspan=3 |
|-
! Parameter !! BIP9 value !! BIP135 value
|-
| name || some_name || some_name
|-
| bit || b || b
|-
| starttime || T_start || T_start
|-
| timeout || T_timeout || T_timeout
|-
| windowsize || n/a || 2016
|-
| threshold || n/a || 1512
|-
| minlockedblocks || n/a || 2016
|-
| minlockedtime || n/a || 0
|}
==Deployment==
As this BIP is not itself consensus-relevant (Information like BIP9), it can
be rolled out without the use of a BIP9 fork bit.
Backward compatibility through judicious fork configuration parameters should
ensure that it does not interfere with existing known deployments.
By way of design it does not interfere with unknown (undefined) deployments.
==Reference implementation==
A working reference implementation, including tests, can be found in these Pull Requests:
* https://github.com/BitcoinUnlimited/BitcoinUnlimited/pull/458
* https://github.com/bitcoin/bitcoin/pull/10437
Existing unit tests and regression tests have been left active to demonstrate
backward compatibility of the default settings with BIP9.
==References==
[1] http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16
[2] [[https://github.com/bitcoin/bips/blob/master/bip-0009/assignments.mediawiki|List of existing BIP9 deployment proposals]]
==Copyright==
This BIP is dual-licensed under the Creative Commons CC0 1.0 Universal and
FSF All Permissive licenses.
================================================
FILE: bip-0136.mediawiki
================================================
BIP: 136
Layer: Applications
Title: Bech32 Encoded Tx Position References
Authors: Велеслав
Jonas Schnelli
Daniel Pape
Status: Draft
Type: Informational
Assigned: 2017-07-09
License: BSD-2-Clause
== Introduction ==
=== Abstract ===
This document proposes a convenient, human usable encoding to refer to a '''confirmed transaction position''' within the Bitcoin blockchain--known as '''"TxRef"'''. The primary purpose of this encoding is to allow users to refer to a confirmed transaction (and optionally, a particular outpoint index within the transaction) in a standard, reliable, and concise way.
''Please note: Unlike a transaction ID, '''"TxID"''', where there is a strong cryptographic link between the ID and the actual transaction, a '''TxRef''' only provides a weak link to a particular transaction. A '''TxRef''' locates an offset within a blockchain for a transaction, that may - or may not - point to an actual transaction, which in fact may change with reorganisations. We recommend that '''TxRef'''s should be not used for positions within the blockchain having a maturity less than 100 blocks.''
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [https://tools.ietf.org/html/rfc2119 RFC 2119].
=== Copyright ===
This BIP is licensed under the 2-clause BSD license.
=== Motivation ===
Since the first version of Bitcoin, '''TxID'''s have been a core part of the consensus protocol and are routinely used to identify individual transactions between users.
However, for many use-cases they have practical limitations:
* '''TxID'''s are expensive for full nodes to lookup (requiring either a linear scan of the blockchain, or an expensive '''TxID''' index).
* '''TxID'''s require third-party services for SPV wallets to lookup.
* '''TxID'''s are 64 character HEX encoded values.
It is possible to reference transactions not only by their '''TxID''', but by their location within the blockchain itself. Rather than use the 64 character '''TxID''', an encoding of the position coordinates can be made friendly for occasional human transcription. In this document, we propose a standard for doing this.
=== Examples ===
{| class="wikitable"
|-
! Block # !! Transaction # !! Outpoint # !! TxRef !! TxID
|-
| 0 || 0 || 0 || tx1:rqqq‑qqqq‑qwtv‑vjr || 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
|-
| 170 || 1 || 0 || tx1:r52q‑qqpq‑qpty‑cfg || f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16
|-
| 456789 || 1234 || 1 || tx1:y29u‑mqjx‑ppqq‑sfp2‑tt || 6fb8960f70667dc9666329728a19917937896fc476dfc54a3e802e887ecb4e82
|}
== Specification ==
A '''confirmed transaction position reference''', or '''TxRef''', is a reference to a particular location within the blockchain, specified by the block height and a transaction index within the block, and optionally, an outpoint index within the transaction.
''Please Note: All values in this specification are encoded in little-endian format.''
=== TxRef Considerations ===
It is possible for a '''TxRef''' to reference a transaction that doesn't really exist because:
* The specified block hasn't yet been mined.
* The transaction index is greater than the total number of transactions included within the specified block.
* The optional outpoint index is greater than the total outpoints contained within the transaction.
Therefore, implementers must be careful not to display '''TxRef'''s to users prematurely:
* Applications MUST NOT display '''TxRef'''s for transactions with less than 6 confirmations.
* Application MUST show a warning for '''TxRef'''s for transactions with less than 100 confirmations.
** This warning SHOULD state that in the case of a large reorganisation, the '''TxRef'''s displayed may point to a different transaction, or to no transaction at all.
=== TxRef Format ===
'''TxRef''' MUST use the '''Bech32m''''''Why use Bech32 Encoding for Confirmed Transaction References?''' The error detection and correction properties of this encoding format make it very attractive. We expect that it will be reasonable for software to correct a maximum of two characters; however, we haven’t specified this yet. encoding as defined in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP-0173] and later refined in [https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki BIP-0350]. The Bech32m encoding consists of:
==== Human-Readable Part ====
The '''HRP''' can be thought of as a label. We have chosen labels to distinguish between Main, Test, and Regtest networks:
* Mainnet: '''"tx"'''.
* Testnet: '''"txtest"'''.
* Regtest: '''"txrt"'''.
==== Separator ====
The separator is the character '''"1"'''.
==== Data Part ====
The data part for a '''TxRef''' consists of the transaction's block height, transaction index within the block, and optionally, an outpoint index. Specific encoding details for the data are given below.
''Please note: other specifications, such as [https://w3c-ccg.github.io/did-spec/ the Decentralized Identifiers spec], have implicitly encoded the information contained within the HRP elsewhere. In this case they may choose to not include the HRP as specified here.''
==== Readability ====
To increase portability and readability, additional separator characters SHOULD be added to the '''TxRef''':
* A Colon'''Why add a colon here?''' This allows it to conform better with W3C URN/URL standards. '''":"''' added after the separator character '1'.
* Hyphens'''Why hyphens within the TxRef?''' As '''TxRef'''s are short, we expect that they will be quoted via voice or written by hand. The inclusion of hyphens every 4 characters breaks up the string and means people don't lose their place so easily. '''"-"''' added after every 4 characters beyond the colon.
=== Encoding ===
Encoding a '''TxRef''' requires 4 or 5 pieces of data: a magic code denoting which network is being used; a version number (currently always 0); the block height of the block containing the transaction; the index of the transaction within the block; and optionally, the index of the outpoint within the transaction. Only a certain number of bits are supported for each of these values, see the following table for details.
{| class="wikitable"
!
!Description
!Possible Data Type
!'''# of Bits used'''
!Values
|-
| style="background: #99DDFF; color: black; text-align : center;" | Magic Code
|Chain Namespacing Code
|uint8
| style="background: #99DDFF; color: black; text-align : center;" | 5
|'''3''': Mainnet '''4''': Mainnet with Outpoint '''6''': Testnet '''7''': Testnet with Outpoint '''0''': Regtest '''1''': Regtest with Outpoint
|-
| style="background: #DDDDDD; color: black; text-align : center;" | Version
|For Future Use
|uint8
| style="background: #DDDDDD; color: black; text-align : center;" | 1
|Must be '''0'''
|-
| style="background: #EEDD88; color: black; text-align : center;" | Block Height
|The Block Height of the Tx
|uint32
| style="background: #EEDD88; color: black; text-align : center;" | 24
|Block 0 to Block 16777215
|-
| style="background: #FFAABB; color: black; text-align : center;" | Transaction Index
|The index of the Tx inside the block
|uint16, uint32
| style="background: #FFAABB; color: black; text-align : center;" | 15
|Tx 0 to Tx 32767
|-
| style="background: #BBCC33; color: black; text-align : center;" | Outpoint Index
|The index of the Outpoint inside the Tx
|uint16, uint32
| style="background: #BBCC33; color: black; text-align : center;" | 15
|Outpoint 0 to Outpoint 32767
|}
==== Magic Notes ====
The magic code provides namespacing between chains:
* For Mainnet the magic code is: '''0x3''', leading to an '''"r"''' character when encoded.
* For Mainnet with Outpoint Encoded the magic code is: '''0x4''', leading to a '''"y"''' character when encoded.
* For Testnet the magic code is: '''0x6''', leading to an '''"x"''' character when encoded.
* For Testnet with Outpoint Encoded the magic code is: '''0x7''', leading to an '''"8"''' character when encoded.
* For Regtest the magic code is: '''0x0''', leading to a '''"q"''' character when encoded.
* For Regtest with Outpoint Encoded the magic code is: '''0x1''', leading to a '''"p"''' character when encoded.
==== Encoding Example ====
We want to encode a '''TxRef''' that refers to Transaction #1234 of Block #456789 on the Mainnet chain. We use this data in preparation for the Bech32 encoding algorithm:
{| class="wikitable"
!
!Decimal Value
!Binary Value
!'''# of Bits used'''
!Bit Indexes and Values
|-
| style="background: #99DDFF; color: black; text-align : center;" | Magic Code
| style="background: #99DDFF; color: black; text-align : center;" | 3
|00000011
| style="background: #99DDFF; color: black; text-align : center;" | 5
|(mc04, mc03, mc02, mc01, mc00) = (0, 0, 0, 1, 1)
|-
| style="background: #DDDDDD; color: black; text-align : center;" | Version
| style="background: #DDDDDD; color: black; text-align : center;" | 0
|00000000
| style="background: #DDDDDD; color: black; text-align : center;" | 1
|(v0) = (0)
|-
| style="background: #EEDD88; color: black; text-align : center;" | Block Height
| style="background: #EEDD88; color: black; text-align : center;" | 456789
|00000110 11111000 01010101
| style="background: #EEDD88; color: black; text-align : center;" | 24
|(bh23, bh22, bh21, bh20, bh19, bh18, bh17, bh16) = (0, 0, 0, 0, 0, 1, 1, 0) (bh15, bh14, bh13, bh12, bh11, bh10, bh09, bh08) = (1, 1, 1, 1, 1, 0, 0, 0) (bh07, bh06, bh05, bh04, bh03, bh02, bh01, bh00) = (0, 1, 0, 1, 0, 1, 0, 1)
|-
| style="background: #FFAABB; color: black; text-align : center;" | Transaction Index
| style="background: #FFAABB; color: black; text-align : center;" | 1234
|00000100 11010010
| style="background: #FFAABB; color: black; text-align : center;" | 15
|(ti14, ti13, ti12, ti11, ti10, ti09, ti08) = (0, 0, 0, 0, 1, 0, 0) (ti07, ti06, ti05, ti04, ti03, ti02, ti01, ti00) = (1, 1, 0, 1, 0, 0, 1, 0)
|}
As shown in the last column, we take the necessary bits of each binary value and copy them into nine unsigned chars illustrated in the next table. We only set the lower five bits of each unsigned char as the bech32 algorithm only uses those bits.
{| class="wikitable" style="text-align: center"
!
!
!style="width:2em"|7
!style="width:2em"|6
!style="width:2em"|5
!style="width:2em"|4
!style="width:2em"|3
!style="width:2em"|2
!style="width:2em"|1
!style="width:2em"|0
!
!Decimal Value
!Bech32 Character
|-
| || || || || || || || || || || || ||
|-
| rowspan="2" | data[0] || Index
|na
|na
|na
| style="background: #99DDFF; color: black; text-align : center;" | mc04
| style="background: #99DDFF; color: black; text-align : center;" | mc03
| style="background: #99DDFF; color: black; text-align : center;" | mc02
| style="background: #99DDFF; color: black; text-align : center;" | mc01
| style="background: #99DDFF; color: black; text-align : center;" | mc00
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|0
|1
|1
|
|3
|r
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[1] || Index
|na
|na
|na
| style="background: #EEDD88; color: black; text-align : center;" | bh03
| style="background: #EEDD88; color: black; text-align : center;" | bh02
| style="background: #EEDD88; color: black; text-align : center;" | bh01
| style="background: #EEDD88; color: black; text-align : center;" | bh00
| style="background: #DDDDDD; color: black; text-align : center;" | v0
|
|
|
|-
|Value
|0
|0
|0
|0
|1
|0
|1
|0
|
|10
|2
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[2] || Index
|na
|na
|na
| style="background: #EEDD88; color: black; text-align : center;" | bh08
| style="background: #EEDD88; color: black; text-align : center;" | bh07
| style="background: #EEDD88; color: black; text-align : center;" | bh06
| style="background: #EEDD88; color: black; text-align : center;" | bh05
| style="background: #EEDD88; color: black; text-align : center;" | bh04
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|1
|0
|1
|
|5
|9
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[3] || Index
|na
|na
|na
| style="background: #EEDD88; color: black; text-align : center;" | bh13
| style="background: #EEDD88; color: black; text-align : center;" | bh12
| style="background: #EEDD88; color: black; text-align : center;" | bh11
| style="background: #EEDD88; color: black; text-align : center;" | bh10
| style="background: #EEDD88; color: black; text-align : center;" | bh09
|
|
|
|-
|Value
|0
|0
|0
|1
|1
|1
|0
|0
|
|28
|u
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[4] || Index
|na
|na
|na
| style="background: #EEDD88; color: black; text-align : center;" | bh18
| style="background: #EEDD88; color: black; text-align : center;" | bh17
| style="background: #EEDD88; color: black; text-align : center;" | bh16
| style="background: #EEDD88; color: black; text-align : center;" | bh15
| style="background: #EEDD88; color: black; text-align : center;" | bh14
|
|
|
|-
|Value
|0
|0
|0
|1
|1
|0
|1
|1
|
|27
|m
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[5] || Index
|na
|na
|na
| style="background: #EEDD88; color: black; text-align : center;" | bh23
| style="background: #EEDD88; color: black; text-align : center;" | bh22
| style="background: #EEDD88; color: black; text-align : center;" | bh21
| style="background: #EEDD88; color: black; text-align : center;" | bh20
| style="background: #EEDD88; color: black; text-align : center;" | bh19
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|0
|0
|0
|
|0
|q
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[6] || Index
|na
|na
|na
| style="background: #FFAABB; color: black; text-align : center;" | ti04
| style="background: #FFAABB; color: black; text-align : center;" | ti03
| style="background: #FFAABB; color: black; text-align : center;" | ti02
| style="background: #FFAABB; color: black; text-align : center;" | ti01
| style="background: #FFAABB; color: black; text-align : center;" | ti00
|
|
|
|-
|Value
|0
|0
|0
|1
|0
|0
|1
|0
|
|18
|j
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[7] || Index
|na
|na
|na
| style="background: #FFAABB; color: black; text-align : center;" | ti09
| style="background: #FFAABB; color: black; text-align : center;" | ti08
| style="background: #FFAABB; color: black; text-align : center;" | ti07
| style="background: #FFAABB; color: black; text-align : center;" | ti06
| style="background: #FFAABB; color: black; text-align : center;" | ti05
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|1
|1
|0
|
|6
|x
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[8] || Index
|na
|na
|na
| style="background: #FFAABB; color: black; text-align : center;" | ti14
| style="background: #FFAABB; color: black; text-align : center;" | ti13
| style="background: #FFAABB; color: black; text-align : center;" | ti12
| style="background: #FFAABB; color: black; text-align : center;" | ti11
| style="background: #FFAABB; color: black; text-align : center;" | ti10
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|0
|0
|1
|
|1
|p
|}
The Bech32 algorithm encodes the nine unsigned chars above and computes a checksum of those chars and encodes that as well--this gives a six character checksum (in this case, '''utt3p0''') which is appended to the final '''TxRef'''. The final '''TxRef''' given is: '''tx1:r29u-mqjx-putt-3p0''' and is illustrated in the following table:
TxRef character indexes and descriptions
{| class="wikitable" style="text-align: top"
!style="width:2em"|Index
!style="width:2em"|0
!style="width:2em"|1
!style="width:2em"|2
!style="width:2em"|3
!style="width:2em"|4
!style="width:2em"|5
!style="width:2em"|6
!style="width:2em"|7
!style="width:2em"|8
!style="width:2em"|9
!style="width:2em"|10
!style="width:2em"|11
!style="width:2em"|12
!style="width:2em"|13
!style="width:2em"|14
!style="width:2em"|15
!style="width:2em"|16
!style="width:2em"|17
!style="width:2em"|18
!style="width:2em"|19
!style="width:2em"|20
!style="width:2em"|21
|-
|Char:
| style="background: #BBCCEE; color: black; text-align : center;" | t
| style="background: #BBCCEE; color: black; text-align : center;" | x
| style="background: #FFCCCC; color: black; text-align : center;" | 1
| style="background: #CCDDAA; color: black; text-align : center;" | :
| style="background: #EEEEBB; color: black; text-align : center;" | r
| style="background: #EEEEBB; color: black; text-align : center;" | 2
| style="background: #EEEEBB; color: black; text-align : center;" | 9
| style="background: #EEEEBB; color: black; text-align : center;" | u
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | m
| style="background: #EEEEBB; color: black; text-align : center;" | q
| style="background: #EEEEBB; color: black; text-align : center;" | j
| style="background: #EEEEBB; color: black; text-align : center;" | x
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | p
| style="background: #EEEEBB; color: black; text-align : center;" | u
| style="background: #EEEEBB; color: black; text-align : center;" | t
| style="background: #EEEEBB; color: black; text-align : center;" | t
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | 3
| style="background: #EEEEBB; color: black; text-align : center;" | p
| style="background: #EEEEBB; color: black; text-align : center;" | 0
|}
==== Outpoint Index ====
Some uses of '''TxRef''' may want to refer to a specific outpoint of the transaction. In the previous example, since we did not specify the outpoint index, the '''TxRef''' '''tx1:r29u-mqjx-putt-3p0''' implicitly references the first (index 0) outpoint of the 1234th transaction in the 456789th block in the blockchain.
If instead, for example, we want to reference the second (index 1) outpoint, we need to change the magic code from '''3''' to '''4''' and would include the following in the data to be encoded:
{| class="wikitable"
!
!Decimal Value
!Binary Value
!'''# of Bits used'''
!Bit Indexes and Values
|-
| style="background: #99DDFF; color: black; text-align : center;" | Magic Code
| style="background: #99DDFF; color: black; text-align : center;" | 4
|00000100
| style="background: #99DDFF; color: black; text-align : center;" | 5
|(mc04, mc03, mc02, mc01, mc00) = (0, 0, 1, 0, 0)
|-
| style="background: #BBCC33; color: black; text-align : center;" | Outpoint Index
| style="background: #BBCC33; color: black; text-align : center;" | 1
|00000000 00000001
| style="background: #BBCC33; color: black; text-align : center;" | 15
|(op14, op13, op12, op11, op10, op09, op08) = (0, 0, 0, 0, 0, 0, 0) (op07, op06, op05, op04, op03, op02, op01, op00) = (0, 0, 0, 0, 0, 0, 0, 1)
|}
{| class="wikitable" style="text-align: center"
!
!
!style="width:2em"|7
!style="width:2em"|6
!style="width:2em"|5
!style="width:2em"|4
!style="width:2em"|3
!style="width:2em"|2
!style="width:2em"|1
!style="width:2em"|0
!
!Decimal Value
!Bech32 Character
|-
| || || || || || || || || || || || ||
|-
| rowspan="2" | data[0] || Index
|na
|na
|na
| style="background: #99DDFF; color: black; text-align : center;" | mc04
| style="background: #99DDFF; color: black; text-align : center;" | mc03
| style="background: #99DDFF; color: black; text-align : center;" | mc02
| style="background: #99DDFF; color: black; text-align : center;" | mc01
| style="background: #99DDFF; color: black; text-align : center;" | mc00
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|1
|0
|0
|
|4
|y
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[9] || Index
|na
|na
|na
| style="background: #BBCC33; color: black; text-align : center;" | op04
| style="background: #BBCC33; color: black; text-align : center;" | op03
| style="background: #BBCC33; color: black; text-align : center;" | op02
| style="background: #BBCC33; color: black; text-align : center;" | op01
| style="background: #BBCC33; color: black; text-align : center;" | op00
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|0
|0
|1
|
|1
|p
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[10] || Index
|na
|na
|na
| style="background: #BBCC33; color: black; text-align : center;" | op09
| style="background: #BBCC33; color: black; text-align : center;" | op08
| style="background: #BBCC33; color: black; text-align : center;" | op07
| style="background: #BBCC33; color: black; text-align : center;" | op06
| style="background: #BBCC33; color: black; text-align : center;" | op05
|
|
|
|-
|Value
|0
|0
|0
|0
|0
|0
|0
|0
|
|0
|q
|-
| || || || || || || || || || || ||
|-
| rowspan="2" | data[11] || Index
|na
|na
|na
| style="background: #BBCC33; color: black; text-align : center;" | op14
| style="background: #BBCC33; color: black; text-align : center;" | op13
| style="background: #BBCC33; color: black; text-align : center;" | op12
| style="background: #BBCC33; color: black; text-align : center;" | op11
| style="background: #BBCC33; color: black; text-align : center;" | op10
|
|
|
|-
| Value
|0
|0
|0
|0
|0
|0
|0
|0
|
|0
|q
|}
After Bech32 encoding all twelve unsigned chars above, we get the checksum: '''sfp2tt'''. The final '''TxRef''' given is: '''tx1:y29u-mqjx-ppqq-sfp2-tt''' and is illustrated in the following table:
TxRef character indexes and descriptions
{| class="wikitable" style="text-align: top"
!style="width:2em"|Index
!style="width:2em"|0
!style="width:2em"|1
!style="width:2em"|2
!style="width:2em"|3
!style="width:2em"|4
!style="width:2em"|5
!style="width:2em"|6
!style="width:2em"|7
!style="width:2em"|8
!style="width:2em"|9
!style="width:2em"|10
!style="width:2em"|11
!style="width:2em"|12
!style="width:2em"|13
!style="width:2em"|14
!style="width:2em"|15
!style="width:2em"|16
!style="width:2em"|17
!style="width:2em"|18
!style="width:2em"|19
!style="width:2em"|20
!style="width:2em"|21
!style="width:2em"|22
!style="width:2em"|23
!style="width:2em"|24
!style="width:2em"|25
|-
|Char:
| style="background: #BBCCEE; color: black; text-align : center;" | t
| style="background: #BBCCEE; color: black; text-align : center;" | x
| style="background: #FFCCCC; color: black; text-align : center;" | 1
| style="background: #CCDDAA; color: black; text-align : center;" | :
| style="background: #EEEEBB; color: black; text-align : center;" | y
| style="background: #EEEEBB; color: black; text-align : center;" | 2
| style="background: #EEEEBB; color: black; text-align : center;" | 9
| style="background: #EEEEBB; color: black; text-align : center;" | u
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | m
| style="background: #EEEEBB; color: black; text-align : center;" | q
| style="background: #EEEEBB; color: black; text-align : center;" | j
| style="background: #EEEEBB; color: black; text-align : center;" | x
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | p
| style="background: #EEEEBB; color: black; text-align : center;" | p
| style="background: #EEEEBB; color: black; text-align : center;" | q
| style="background: #EEEEBB; color: black; text-align : center;" | q
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | s
| style="background: #EEEEBB; color: black; text-align : center;" | f
| style="background: #EEEEBB; color: black; text-align : center;" | p
| style="background: #EEEEBB; color: black; text-align : center;" | 2
| style="background: #CCDDAA; color: black; text-align : center;" | -
| style="background: #EEEEBB; color: black; text-align : center;" | t
| style="background: #EEEEBB; color: black; text-align : center;" | t
|}
=== Decoding ===
The Bech32 spec defines 32 valid characters as its "alphabet". All non-Bech32-alphabet characters present in a '''TxRef''' after the Bech32 separator character MUST be ignored/removed when parsing (except for terminating characters). We do not wish to expect the users to keep their '''TxRef'''s in good form and '''TxRef'''s may contains hyphens, colons, invisible spaces, uppercase or random characters. We expect users to copy, paste, write by-hand, write in a mix of character sets, etc. Parsers SHOULD attempt to correct for these and other common errors, reporting to the user any '''TxRef'''s that violate a proper Bech32 encoding.
As of early 2021, '''TxRef''' has been in limited use for a couple of years and it is possible that there are some '''TxRef'''s in use which were created with the original specification of Bech32 before the Bech32m refinement was codified. Due to this possibility, a '''TxRef''' parser SHOULD be able to decode both Bech32m and Bech32 encoded '''TxRef'''s. In such a case, a '''TxRef''' parser SHOULD display or somehow notify the user that they are using an obsolete '''TxRef''' and that they should upgrade it to the Bech32m version. Additionally, the parser MAY also display the Bech32m version.
== Rationale ==
== Reference implementations ==
C Reference Implementation (supports magic codes 0x3 and 0x6): https://github.com/jonasschnelli/bitcoin_txref_code
Go Reference Implementation (supports magic codes 0x3 and 0x6): https://github.com/kulpreet/txref
C++ Reference Implementation (supports magic codes 0x3, 0x4, 0x6, 0x7, 0x0 and 0x1): https://github.com/dcdpr/libtxref/
Java Reference Implementation (supports magic codes 0x3, 0x4, 0x6, 0x7, 0x0 and 0x1): https://github.com/dcdpr/libtxref-java/
== Appendices ==
=== Test Examples ===
The following examples show values for various combinations on mainnet and testnet; encoding block height, transaction index, and an optional output index.
==== TxRef ====
The following list gives properly encoded mainnet '''TxRef'''s and the decoded hex values (block height, transaction index)
* tx1:rqqq-qqqq-qwtv-vjr: (0x0, 0x0)
* tx1:rqqq-qqll-lj68-7n2: (0x0, 0x7FFF)
* tx1:r7ll-llqq-qats-vx9: (0xFFFFFF, 0x0)
* tx1:r7ll-llll-lp6m-78v: (0xFFFFFF, 0x7FFF)
The following list gives properly encoded testnet '''TxRef'''s and the decoded hex values (block height, transaction index)
* txtest1:xqqq-qqqq-qrrd-ksa: (0x0, 0x0)
* txtest1:xqqq-qqll-lljx-y35: (0x0, 0x7FFF)
* txtest1:x7ll-llqq-qsr3-kym: (0xFFFFFF, 0x0)
* txtest1:x7ll-llll-lvj6-y9j: (0xFFFFFF, 0x7FFF)
The following list gives valid (sometimes strangely formatted) '''TxRef'''s and the decoded values (block height, transaction index)*
* tx1:r29u-mqjx-putt-3p0: (456789, 1234)
* TX1R29UMQJXPUTT3P0: (456789, 1234)
* tx1 r29u mqjx putt 3p0: (456789, 1234)
* tx1!r29u/mqj*x-putt^^3p0: (456789, 1234)
The following list gives invalid '''TxRef'''s and the reason for their invalidity.
* tx1:t7ll-llll-lcq3-aj4: Magic 0xB instead of 0x3.
* tx1:rlll-llll-lu9m-00x: Version 1 instead of 0.
* tx1:r7ll-llll-lqfu-gss2: Valid Bech32, but ten 5 bit unsigned chars instead of nine.
* tx1:r7ll-llll-rt5h-wz: Valid Bech32, but eight 5 bit unsigned chars instead of nine.
* tx1:r7ll-LLLL-lp6m-78v: Invalid Bech32 due to mixed case. Would decode correctly otherwise.
==== TxRef with Outpoints ====
The following list gives properly encoded mainnet '''TxRef'''s with Outpoints and the decoded values (block height, transaction index, outpoint index)
* tx1:yqqq-qqqq-qqqq-rvum-0c: (0x0, 0x0, 0x0)
* tx1:yqqq-qqll-lqqq-en8x-05: (0x0, 0x7FFF, 0x0)
* tx1:y7ll-llqq-qqqq-ggjg-w6: (0xFFFFFF, 0x0, 0x0)
* tx1:y7ll-llll-lqqq-jhf4-wk: (0xFFFFFF, 0x7FFF, 0x0)
* tx1:yqqq-qqqq-qpqq-pw4v-kq: (0x0, 0x0, 0x1)
* tx1:yqqq-qqll-lpqq-m3w3-kv: (0x0, 0x7FFF, 0x1)
* tx1:y7ll-llqq-qpqq-22ml-hz: (0xFFFFFF, 0x0, 0x1)
* tx1:y7ll-llll-lpqq-s4qz-hw: (0xFFFFFF, 0x7FFF, 0x1)
* tx1:y29u-mqjx-ppqq-sfp2-tt: (456789, 1234, 1)
The following list gives properly encoded testnet '''TxRef'''s with Outpoints and the decoded values (block height, transaction index, outpoint index)
* txtest1:8qqq-qqqq-qqqq-d5ns-vl: (0x0, 0x0, 0x0)
* txtest1:8qqq-qqll-lqqq-htgd-vn: (0x0, 0x7FFF, 0x0)
* txtest1:87ll-llqq-qqqq-xsar-da: (0xFFFFFF, 0x0, 0x0)
* txtest1:87ll-llll-lqqq-u0x7-d3: (0xFFFFFF, 0x7FFF, 0x0)
* txtest1:8qqq-qqqq-qpqq-0k68-48: (0x0, 0x0, 0x1)
* txtest1:8qqq-qqll-lpqq-4fp6-4t: (0x0, 0x7FFF, 0x1)
* txtest1:87ll-llqq-qpqq-yj55-59: (0xFFFFFF, 0x0, 0x1)
* txtest1:87ll-llll-lpqq-7d0f-5f: (0xFFFFFF, 0x7FFF, 0x1)
* txtest1:829u-mqjx-ppqq-73wp-gv: (456789, 1234, 1)
=== TxRef Payload Value Choices: ===
Some calculations showing why we chose these particular bit-length of the block height and transaction index.
==== Block Height Value: ====
24 bits: value can be between 0, and 0xFFFFFF (16777216 blocks).
* In early April, 2021, there have been 677700 blocks
* There are roughly (365 days * 24 hours * 6 blocks / hour) = 52560 blocks every year, implying about (16777216 - 677700) / 52560 = 306 more years of addressable blocks.
* Some time before year 2327 this specification should be extended.
==== Tx Position Value: ====
15 bits: value can be between 0x0, and 0x7FFF (32768 transactions).
*The ''realistic'' smallest Tx is 83 Bytes for maximum 12047 tx in a block.
**4B version + 1B tx_in count + 36B previous_output + 1B script length + 0B signature script + 4B sequence + 1B tx_out count + 8B amount + 1B script length + 23B pubkey script + 4B lock_time = 83B
*The ''extreme'' smallest Tx is 60 Bytes for maximum 16665 tx in a block.
**4B version + 1B tx_in count + 36B previous_output + 1B script length + 0B signature script + 4B sequence + 1B tx_out count + 8B amount + 1B script length + 0B pubkey script + 4B lock_time = 60B
== Acknowledgements ==
Special Thanks to Pieter Wuille and Greg Maxwell for Bech32, a wonderful user-facing data encoding.
================================================
FILE: bip-0137.mediawiki
================================================
BIP: 137
Layer: Applications
Title: Signatures of Messages using Private Keys
Authors: Christopher Gilliard
Status: Deployed
Type: Specification
Assigned: 2019-02-16
License: BSD-2-Clause
==Abstract==
This document describes a signature format for signing messages with Bitcoin private keys.
The specification is intended to describe the standard for signatures of messages that can be signed and verified between different clients that exist in the field today. Note: that a new signature format has been defined which has a number of advantages over this BIP, but to be backwards compatible with existing implementations this BIP will be useful. See BIP 322 [1] for full details on the new signature scheme.
One of the key problems in this area is that there are several different types of Bitcoin addresses and without introducing specific standards it is unclear which type of address format is being used. See [2]. This BIP will attempt to address these issues and define a clear and concise format for Bitcoin signatures.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
==Motivation==
Since Bitcoin private keys can not only be used to sign Bitcoin transactions, but also any other message, it has become customary to use them to sign various messages for differing purposes. Some applications of signing messages with a Bitcoin private key are as follows: proof of funds for collateral, credit worthiness, entrance to events, airdrops, audits as well as other applications. While there was no BIP written for how to digitally sign messages with Bitcoin private keys with P2PKH addresses it is a fairly well understood process, however with the introduction of Segwit (both in the form of P2SH and bech32) addresses, it is unclear how to distinguish a P2PKH, P2SH, or bech32 address from one another. This BIP proposes a standard signature format that will allow clients to distinguish between the different address formats.
==Specification==
===Background on ECDSA Signatures===
(For readers who already understand how ECDSA signatures work, you can skip this section as this is only intended as background information.)
Elliptic Curve Digital Signature Algorithm or ECDSA is a cryptographic algorithm used by Bitcoin to ensure that funds can only be spent by their rightful owners.
A few concepts related to ECDSA:
private key: A secret number, known only to the person that generated it. A private key is essentially a randomly generated number. In Bitcoin, someone with the private key that corresponds to funds on the block chain can spend the funds. In Bitcoin, a private key is a single unsigned 256 bit integer (32 bytes).
public key: A number that corresponds to a private key, but does not need to be kept secret. A public key can be calculated from a private key, but not vice versa. A public key can be used to determine if a signature is genuine (in other words, produced with the proper key) without requiring the private key to be divulged. In Bitcoin, public keys are either compressed or uncompressed. Compressed public keys are 33 bytes, consisting of a prefix either 0x02 or 0x03, and a 256-bit integer called x. The older uncompressed keys are 65 bytes, consisting of constant prefix (0x04), followed by two 256-bit integers called x and y (2 * 32 bytes). The prefix of a compressed key allows for the y value to be derived from the x value.
signature: A number that proves that a signing operation took place. A signature is mathematically generated from a hash of something to be signed, plus a private key. The signature itself is two numbers known as r and s. With the public key, a mathematical algorithm can be used on the signature to determine that it was originally produced from the hash and the private key, without needing to know the private key. Signatures are either 73, 72, or 71 bytes long, with probabilities approximately 25%, 50% and 25% respectively, although sizes even smaller than that are possible with exponentially decreasing probability. Source [3].
===Conventions with signatures used in Bitcoin===
Bitcoin signatures have the r and s values mentioned above, and a header. The header is a single byte and the r and s are each 32 bytes so a signature's size is 65 bytes. The header is used to specify information about the signature. It can be thought of as a bitmask with each bit in this byte having a meaning. The serialization format of a Bitcoin signature is as follows:
[1 byte of header data][32 bytes for r value][32 bytes for s value]
The header byte has a few components to it. First, it stores something known as the recId. This value is stored in the least significant 2 bits of the header. If the header is between a value of 31 and 34, this indicates that it is a compressed address. If the header value is between 35 and 38 inclusive, it is a p2sh segwit address. If the header value is between 39 and 42, it is a bech32 address.
===Procedure for signing/verifying a signature===
As noted above the signature is composed of three components, the header, r and s values. r/s can be computed with standard ECDSA library functions. Part of the header includes something called a recId. This is part of every ECDSA signature and should be generated by the ECDSA library. The recId is a number between 0 and 3 inclusive. The header is the recId plus a constant which indicates what type of Bitcoin address this is. For P2PKH address using an uncompressed public key this value is 27. For P2PKH address using compressed public key this value is 31. For P2SH-P2WPKH this value is 35 and for P2WPKH (version 0 witness) address this value is 39. So, you have the following ranges:
* 27-30: P2PKH uncompressed
* 31-34: P2PKH compressed
* 35-38: Segwit P2SH
* 39-42: Segwit Bech32
To verify a signature, the recId is obtained by subtracting this constant from the header value.
===Sample Code for processing a signature===
Note: this code is a modification of the BitcoinJ code which is written in java.
public static ECKey signedMessageToKey(String message, String signatureBase64) throws SignatureException {
byte[] signatureEncoded;
try {
signatureEncoded = Base64.decode(signatureBase64);
} catch (RuntimeException e) {
// This is what you get back from Bouncy Castle if base64 doesn't decode :(
throw new SignatureException("Could not decode base64", e);
}
// Parse the signature bytes into r/s and the selector value.
if (signatureEncoded.length < 65)
throw new SignatureException("Signature truncated, expected 65 bytes and got " + signatureEncoded.length);
int header = signatureEncoded[0] & 0xFF;
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
// 0x1D = second key with even y, 0x1E = second key with odd y
if (header < 27 || header > 42)
throw new SignatureException("Header byte out of range: " + header);
BigInteger r = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 1, 33));
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signatureEncoded, 33, 65));
ECDSASignature sig = new ECDSASignature(r, s);
byte[] messageBytes = formatMessageForSigning(message);
// Note that the C++ code doesn't actually seem to specify any character encoding. Presumably it's whatever
// JSON-SPIRIT hands back. Assume UTF-8 for now.
Sha256Hash messageHash = Sha256Hash.twiceOf(messageBytes);
boolean compressed = false;
// this section is added to support new signature types
if(header>= 39) // this is a bech32 signature
{
header -= 12;
compressed = true;
} // this is a segwit p2sh signature
else if(header >= 35)
{
header -= 8;
compressed = true;
} // this is a compressed key signature
else if (header >= 31) {
compressed = true;
header -= 4;
}
int recId = header - 27;
ECKey key = ECKey.recoverFromSignature(recId, sig, messageHash, compressed);
if (key == null)
throw new SignatureException("Could not recover public key from signature");
return key;
}
==Backwards Compatibility==
Since this format includes P2PKH keys, it is backwards compatible, but keep in mind some software has checks for ranges of headers and will report the newer segwit header types as errors.
==Implications==
Message signing is an important use case and potentially underused due to the fact that, up until now, there has not been a formal specification for how wallets can sign messages using Bitcoin private keys. Bitcoin wallets should be interoperable and use the same conventions for determining a signature's validity. This BIP can also be updated as new signature formats emerge.
==Acknowledgements==
* Konstantin Bay - review
* Holly Casaletto - review
* James Bryrer - review
Note that the background on ECDSA signatures was taken from en.bitcoin.it and code sample modified from BitcoinJ.
==References==
[1] - https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki
[2] - https://github.com/bitcoin/bitcoin/issues/10542
[3] - https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
================================================
FILE: bip-0140.mediawiki
================================================
== Abstract ==
This BIP describes the use of normalized transaction IDs (NTXIDs) in order to eliminate transaction malleability, both in the third-party modification scenario as well as the participant modification scenario. The transaction ID is normalized by removing the signature scripts from transactions before computing its hash. The normalized transaction hashes are then used during the signature creation and signature verification of dependent transactions.
== Motivation ==
Transaction malleability refers to the fact that transactions can be modified, either by one of the signers by re-signing the transaction or a third-party by modifying the signature representation. This is a problem since any modification to the serialized representation also changes the hash of the transaction, which is used by spending transaction to reference the funds that are being transferred. If a transaction is modified and later confirmed by ending up in the blockchain all transactions that depended on the original transaction are no longer valid, and thus orphaned.
BIPs 62[[https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki|BIP 62 - Dealing with malleability]] and 66[[https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki|BIP 66 - Strict DER signatures]] alleviate the problem of third-party modification by defining a canonical representation of the signatures. However, checking the canonical representation is complex and may not eliminate all sources of third-party malleability. Furthermore, these BIPs do not address modifications by one of the signers, i.e., re-signing the transaction, because signers can produce any number of signatures due to the random parameter in ECDSA.
This proposal eliminates malleability by removing the malleable signatures from the hash used to reference the outputs spent by a transaction. The new hash used to reference an output is called the ''normalized transaction ID''. The integrity of all data that is used to reference the output is guaranteed by the signature itself, and any modification that would change the normalized transaction ID would also invalidate the signature itself.
Besides eliminating transaction malleability as a source of problems it also allows the use of transaction templates. Transaction templates simplify higher level protocols and allows new uses. They allow an unsigned template transaction to be used as a basis for a sequence of transaction and only once the sequence matches the signers' expectations they provide the necessary signatures for the template to become valid, thus opting in to the sequence.
== Specification ==
The use of normalized transaction IDs is introduced as a softfork. The specification is divided into three parts:
* Computation of the normalized transaction ID
* Introduction of a new extensible signature verification opcode to enable softfork deployment
* Changes to the UTXO tracking to enable normalized transaction ID lookup
=== Normalized Transaction ID computation ===
In order to calculate the normalized transaction ID, the signature script is stripped from each input of the transaction of non-coinbase transactions and each input is normalized. Stripping the signature script is achieved by setting the script's length to 0 and removing the uchar[] array from the TxIn.[[https://en.bitcoin.it/wiki/Protocol_Specification#tx|Protocol Specification: TX]]
Inputs are then normalized by replacing the hash of each previous transaction with its normalized version if available, i.e., the normalized hash of the previous transaction that created the output being spent in the current transaction. Version 1 transactions do not have a normalized transaction ID hence the non-normalized transaction ID is used for input normalization.
The normalized transaction ID is then computed as the double SHA 256 hash of the normalized transaction matching the existing transaction ID computation. The normalized transaction ID remains unchanged even if the signatures of the transaction are replaced/malleated and describe a class of semantically identical transactions. In the following we use ''transaction instance ID'' to refer to the transaction ID computed on the transaction including signatures. Normalized transaction IDs for coinbase transactions are computed with the signature script in the coinbase input, in order to avoid hash collisions.
=== OP_CHECKSIGEX ===
This BIP introduces a new opcode OP_CHECKSIGEX which replaces OP_NOP4. OP_CHECKSIGEX subsumes OP_CHECKSIGVERIFY and OP_CHECKMULTISIGVERIFY, and extends them by accepting a new VERSION parameter. The version parameter is a single integer pushed onto the stack before invoking OP_CHECKSIGEX and is used to group and evolve future versions of signature checking opcodes.
When executed OP_CHECKSIGEX pops the version from the stack and then performs the signature check according to the specified version. If the verifying client does not support the specified version, i.e., the version was defined after the release of the client, the client must treat the OP_CHECKSIGEX as an OP_NOP.
==== Version 1 ====
The first version of OP_CHECKSIGEX (VERSION=1) implements normalized transaction IDs and uses Schnorr signatures instead of the current ECDSA signatures.
Version 1 introduces the following new standard script format:
m {pubkey}...{pubkey} n v OP_CHECKSIGEX
with matching scriptSig format:
{signature}...{signature}
This is the standard ''m-of-n'' script defined in [https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki BIP 11] with an additional version parameter v and the new opcode. Singlesig transactions are encoded as ''1-of-1'' transactions.
The existing OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY have a bug[[https://bitcoin.org/en/developer-guide#multisig|Developer Documentation - Multisig]] that pops one argument too many from the stack. This bug is not reproduced in the implementation of OP_CHECKSIGEX, so the canonical solution of pushing a dummy value onto the stack is not necessary.
The normalization is achieved by normalizing the transaction before computing the signaturehash, i.e., the hash that is signed.
The transaction must be normalized by replacing all transaction IDs in the inputs by their normalized variants and stripping the signature scripts. The normalized transaction IDs are computed as described in the previous section. This normalization step is performed both when creating the signatures as well as when checking the signatures.
=== Tracking Normalized Transaction IDs ===
The transaction version is bumped to 2. The new version signals to clients receiving the transaction that they should track the normalized transaction ID along with the transaction instance ID in the unspent transaction output (UTXO) set. Upon receiving a version 2 transaction the client computes the normalized transaction ID, annotates the outputs with it, and adds them into the UTXO set indexed by the transaction instance ID as before. Transactions continue using the transaction instance ID to reference the outputs, but while checking the signature they may get normalized. All network messages continue to use the transaction instance ID to reference the transaction, specifically inv, getdata, tx and block messages still use transaction instance IDs, not the normalized transaction IDs.
Outputs created by version 1 transactions are not annotated with the normalized transaction ID, and when normalizing the hashes in transaction inputs referencing version 1 outputs are not modified.
== Rationale ==
=== Normalization ===
Normalized transaction IDs are provably non-malleable since no data is included in the signaturehash whose integrity is not also proven in the signature, thus any modification causing the hash to change will also invalidate the signature.
Normalized transactions are secure as they still use cryptographic hashes over all the semantic information of the transaction, i.e., the inputs, outputs and metadata, thus it is still computationally infeasible to cause a hash collision between transactions.
There are a number of advantages to using normalized transaction IDs:
* Like BIP 62 and BIP 66 it solves the problem of third-parties picking transactions out of the network, modifying them and reinjecting them.
* ''m-of-n'' multisig outputs are often used in higher level protocols[[http://www.tik.ee.ethz.ch/file/716b955c130e6c703fac336ea17b1670/duplex-micropayment-channels.pdf|A Fast and Scalable Payment Network with Bitcoin Duplex Micropayment Channels ]][[http://lightning.network/lightning-network-paper.pdf|The Bitcoin Lightning Network:
Scalable Off-Chain Instant Payments]] in which several parties sign a transaction. Without normalized transaction IDs it is trivial for one party to re-sign a transaction, hence changing the transaction hash and invalidating any transaction built on top of its outputs. Normalized transaction IDs force the ID not to change, even if a party replaces its signature.
* Many higher level protocols build structures of transactions on top of multisig outputs that are not completely signed. This is currently not possible without one party holding a fully signed transaction and then calculating the ID. It is desirable to be able to build successive transactions without one party collecting all signatures, and thus possibly lock in funds unilaterally. Normalized transaction IDs allow the use of transaction templates, i.e., completely unsigned transactions upon which further transactions can be built, and only once every party is assured the structure matches its expectations it signs the template, thus validating the template.
The only occurrence in which transactions can still be modified unilaterally is in the case SIGHASH_NONE, SIGHASH_SINGLE or SIGHASH_ANYONECANPAY is used. This however is not problematic since in these cases the creator of the transaction explicitly allows modification.
In case of a transaction becoming invalid due to one of the inputs being malleated it is necessary to modify the spending transaction to reference the modified transaction ID. However, the signatures, which only use the normalized IDs, remain valid as long as the semantics of the funding transaction remain unchanged. An observer in the network may fix the transaction and reinject a corrected version.
Using version 2 for transactions is an explicit opt-in to the normalized ID tracking and a simple upgrade for existing clients. It avoids having to reprocess the entire blockchain and computing the normalized transaction IDs for existing outputs in the UTXO. This would be further complicated by having to recursively compute normalized transaction IDs down to the coinbase transactions which created the coins.
Tracking the normalized transaction IDs in the UTXO requires the storage of an additional hash per transaction whose outputs are not completely spent, which at 7,000,000 transactions with unspent outputs amounts to 224MB additional storage on disk.
The coinbase transactions have been checked for hash-collisions and no collisions were found except for the coinbase transactions in blocks at heights 91842 and 91880, which are known to be identical[[https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki|BIP 30 - Duplicate transactions]], and motivated the introduction of BIP 34.[[https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki|Block v2, Height in Coinbase]] Since coinbase transactions are invalid if transmitted outside of a block it is not possible to modify them on the fly and since they only mature after being included for a long time in the blockchain they are considered safe.
=== OP_CHECKSIGEX ===
The new opcode OP_CHECKSIGEX was introduced in order to allow the use of normalized transaction IDs as a softfork and in order to keep the number of OP_NOPs needed to a bare minimum, while enabling future soft-fork updates to the signing algorithms.
The additional argument containing the version can be pushed on the stack using a single byte up to version 16 (OP_1 - OP_16), resulting in one byte overhead for this script type. Using the standard multisig format also for 1-of-1 transactions add an additional 2 bytes, however it also removes the bug requiring a dummy push, resulting in a single byte overhead.
Furthermore, using Schnorr signatures instead of ECDSA brings a number of improvements that reduce the size of transactions (''m-of-m'' is the same size as ''1-of-1'') and increase verification speed (batch signature validation by summing up keys and signatures). The code is already in bitcoin/secp256k1 and can be merged in. We limited the description of this BIP to re-using BIP 11 style ''m-of-n'' scripts to keep it short, however Schnorr also allows a number of more complex applications which we defer to future BIPs.
Version 0 was intentionally skipped in order to guarantee that the top-most element before OP_CHECKSIGEX is non-zero. This is necessary to guarantee that non-upgraded clients, which interpret OP_CHECKSIGEX as OP_NOP4, do not end up with a zero value on top of the stack after execution, which would be interpreted as script failure.
=== Impact ===
This is a softfork which replaces OP_NOP4 with the new implementation of OP_CHECKSIGEX, as such the impact on the network is minimal. Wallets that do not implement this opcode will not be able to verify the validity of the scripts, however if transactions using OP_CHECKSIGEX are included in blocks they will accept them and track the inputs correctly. This is guaranteed since the transaction inputs still use the non-normalized transaction ID to reference the outputs to be claimed, hence non-upgraded wallets can still lookup the outputs and mark them as spent. Furthermore, clients that do not implement this BIP are unable to identify outputs using this script as their own, however upgrading and rescanning the blockchain will make them available.
== See also ==
* [[bip-0062.mediawiki|BIP 62: Dealing with malleability]]
* [[bip-0066.mediawiki|BIP 66: Strict DER Signatures]]
== References ==
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0141.mediawiki
================================================
BIP: 141
Layer: Consensus (soft fork)
Title: Segregated Witness (Consensus layer)
Authors: Eric Lombrozo
Johnson Lau
Pieter Wuille
Status: Deployed
Type: Specification
Assigned: 2015-12-21
License: PD
==Abstract==
This BIP defines a new structure called a "witness" that is committed to blocks separately from the transaction merkle tree. This structure contains data required to check transaction validity but not required to determine transaction effects. In particular, scripts and signatures are moved into this new structure.
The witness is committed in a tree that is nested into the block's existing merkle root via the coinbase transaction for the purpose of making this BIP soft fork compatible. A future hard fork can place this tree in its own branch.
==Motivation==
The entirety of the transaction's effects are determined by output consumption (spends) and new output creation. Other transaction data, and signatures in particular, are only required to validate the blockchain state, not to determine it.
By removing this data from the transaction structure committed to the transaction merkle tree, several problems are fixed:
# '''Nonintentional malleability becomes impossible'''. Since signature data is no longer part of the transaction hash, changes to how the transaction was signed are no longer relevant to transaction identification. As a solution of transaction malleability, this is superior to the canonical signature approach ([https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki BIP62]):
#* It prevents involuntary transaction malleability for any type of scripts, as long as all inputs are signed (with at least one CHECKSIG or CHECKMULTISIG operation)
#* In the case of an m-of-n CHECKMULTISIG script, a transaction is malleable only with agreement of m private key holders (as opposed to only 1 private key holder with BIP62)
#* It prevents involuntary transaction malleability due to unknown ECDSA signature malleability
#* It allows creation of unconfirmed transaction dependency chains without counterparty risk, an important feature for offchain protocols such as the Lightning Network
# '''Transmission of signature data becomes optional'''. It is needed only if a peer is trying to validate a transaction instead of just checking its existence. This reduces the size of SPV proofs and potentially improves the privacy of SPV clients as they can download more transactions using the same bandwidth.
# '''Some constraints could be bypassed with a soft fork''' by moving part of the transaction data to a structure unknown to current protocol, for example:
#* Size of witness could be ignored / discounted when calculating the block size, effectively increasing the block size to some extent
#* Hard coded constants, such as maximum data push size (520 bytes) or sigops limit could be reevaluated or removed
#* New script system could be introduced without any limitation from the existing script semantic. For example, a new transaction digest algorithm for transaction signature verification is described in [https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143]
==Specification==
=== Transaction ID ===
A new data structure, witness, is defined. Each transaction will have 2 IDs.
Definition of txid remains unchanged: the double SHA256 of the traditional serialization format:
[nVersion][txins][txouts][nLockTime]
A new wtxid is defined: the double SHA256 of the new serialization with witness data:
[nVersion][marker][flag][txins][txouts][witness][nLockTime]
Format of nVersion, txins, txouts, and nLockTime are same as traditional serialization.
The marker MUST be a 1-byte zero value: 0x00.
The flag MUST be a 1-byte non-zero value. Currently, 0x01 MUST be used.
The witness is a serialization of all witness fields of the transaction. Each txin is associated with a witness field. A witness field starts with a var_int to indicate the number of stack items for the txin. It is followed by stack items, with each item starts with a var_int to indicate the length. Witness data is NOT script.
A non-witness program (defined hereinafter) txin MUST be associated with an empty witness field, represented by a 0x00. If all txins are not witness program, a transaction's wtxid is equal to its txid.
=== Commitment structure ===
A new block rule is added which requires a commitment to the wtxid. The wtxid of coinbase transaction is assumed to be 0x0000....0000.
A witness root hash is calculated with all those wtxid as leaves, in a way similar to the hashMerkleRoot in the block header.
The commitment is recorded in a scriptPubKey of the coinbase transaction. It must be at least 38 bytes, with the first 6-byte of 0x6a24aa21a9ed, that is:
1-byte - OP_RETURN (0x6a)
1-byte - Push the following 36 bytes (0x24)
4-byte - Commitment header (0xaa21a9ed)
32-byte - Commitment hash: Double-SHA256(witness root hash|witness reserved value)
39th byte onwards: Optional data with no consensus meaning
and the coinbase's input's witness must consist of a single 32-byte array for the witness reserved value.
If there are more than one scriptPubKey matching the pattern, the one with highest output index is assumed to be the commitment.
If all transactions in a block do not have witness data, the commitment is optional.
=== Witness program ===
A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of a 1-byte push opcode (one of OP_0,OP_1,OP_2,...,OP_16) followed by a direct data push between 2 and 40 bytes gets a new special meaning. The value of the first push is called the "version byte". The following byte vector pushed is called the "witness program".
In more detail, this means a scriptPubKey or redeemScript which consists of (in order):
* First, byte 0x00 (OP_0) or any byte between 0x51 (OP_1) and 0x60 (OP_16) inclusive (the version byte).
* Then, a byte ''L'' between 0x02 (push of 2 bytes) and 0x28 (push of 40 bytes) inclusive.
* Finally, ''L'' arbitrary bytes (the witness program).
There are two cases in which witness validation logic are triggered. Each case determines the location of the witness version byte and program, as well as the form of the scriptSig:
# Triggered by a scriptPubKey that is exactly a push of a version byte, plus a push of a witness program. The scriptSig must be exactly empty or validation fails. (''"native witness program"'')
# Triggered when a scriptPubKey is a P2SH script, and the BIP16 redeemScript pushed in the scriptSig is exactly a push of a version byte plus a push of a witness program. The scriptSig must be exactly a push of the BIP16 redeemScript or validation fails. (''"P2SH witness program"'')
If the version byte is 0, and the witness program is 20 bytes (''L = 20''):
* It is interpreted as a pay-to-witness-public-key-hash (P2WPKH) program.
* The witness must consist of exactly 2 items (≤ 520 bytes each). The first one a signature, and the second one a public key.
* The HASH160 of the public key must match the 20-byte witness program.
* After normal script evaluation, the signature is verified against the public key with CHECKSIG operation. The verification must result in a single TRUE on the stack.
If the version byte is 0, and the witness program is 32 bytes (''L = 32''):
* It is interpreted as a pay-to-witness-script-hash (P2WSH) program.
* The witness must consist of an input stack to feed to the script, followed by a serialized script (witnessScript).
* The witnessScript (≤ 10,000 bytes) is popped off the initial witness stack. SHA256 of the witnessScript must match the 32-byte witness program.
* The witnessScript is deserialized, and executed after normal script evaluation with the remaining witness stack (≤ 520 bytes for each stack item).
* The script must not fail, and result in exactly a single TRUE on the stack.
If the version byte is 0, but the witness program is neither 20 nor 32 bytes, the script must fail.For example, a scriptPubKey with OP_0 followed by a 40-byte non-zero data push will fail due to incorrect program size. However, a scriptPubKey with OP_0 followed by a 41-byte non-zero data push will pass, since it is not considered to be a witness program
If the version byte is 1 to 16, no further interpretation of the witness program or witness stack happens, and there is no size restriction for the witness stack. These versions are reserved for future extensions.For backward compatibility, for any version byte from 0 to 16, the script must fail if the witness program has a CastToBool value of zero. However, having a hash like this is a successful preimage attack against the hash function, and the risk is negligible.
=== Other consensus critical limits ===
==== Block size ====
Blocks are currently limited to 1,000,000 bytes (1MB) total size. We change this restriction as follows:
''Block weight'' is defined as ''Base size'' * 3 + ''Total size''. (rationaleRationale of using a single composite constraint, instead of two separate limits such as 1MB base data and 3MB witness data: Using two separate limits would make mining and fee estimation nearly impossible. Miners would need to solve a complex non-linear optimization problem to find the set of transactions that maximize fees given both constraints, and wallets would not be able to know what to pay as it depends on which of the two conditions is most constrained by the time miners try to produce blocks with their transactions in. Another problem with such an approach is freeloading. Once a set of transactions hit the base data 1MB constraint, up to 3MB extra data could be added to the witness by just minimally increasing the fee. The marginal cost for extra witness space effectively becomes zero in that case.)
''Base size'' is the block size in bytes with the original transaction serialization without any witness-related data, as seen by a non-upgraded node.
''Total size'' is the block size in bytes with transactions serialized as described in [[bip-0144.mediawiki|BIP144]], including base data and witness data.
The new rule is ''block weight'' ≤ 4,000,000.
==== Sigops ====
Sigops per block is currently limited to 20,000. We change this restriction as follows:
Sigops in the current pubkey script, signature script, and P2SH check script are counted at 4 times their previous value.
The sigop limit is likewise quadrupled to ≤ 80,000.
Each P2WPKH input is counted as 1 sigop. In addition, opcodes within a P2WSH witnessScript are counted identically as previously within the P2SH redeemScript. That is, CHECKSIG is counted as only 1 sigop. When preceded by OP_1 to OP_16 CHECKMULTISIG is counted as 1 to 16 sigops respectively, otherwise it is counted as 20 sigops. This rule applies to both native witness program and P2SH witness program.
=== Additional definitions ===
The following definitions are not used for consensus limits, but are suggested to provide language consistent with the terminology introduced above.
==== Transaction size calculations ====
''Transaction weight'' is defined as ''Base transaction size'' * 3 + ''Total transaction size'' (ie. the same method as calculating ''Block weight'' from ''Base size'' and ''Total size'').
''Virtual transaction size'' is defined as ''Transaction weight'' / 4 (rounded up to the next integer).
''Base transaction size'' is the size of the transaction serialised with the witness data stripped.
''Total transaction size'' is the transaction size in bytes serialized as described in [[bip-0144.mediawiki|BIP144]], including base data and witness data.
=== New script semantics ===
Despite that the script language for P2WPKH and P2WSH looks very similar to pre-segregated witness script, there are several notable differences. Users MUST NOT assume that a script spendable in pre-segregated witness system would also be spendable as a P2WPKH or P2WSH script. Before large-scale deployment in the production network, developers should test the scripts on testnet with the default relay policy turned on, and with a small amount of money after BIP141 is activated on mainnet.
A major difference at consensus level is described in [https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143], as a new transaction digest algorithm for signature verification in version 0 witness program.
Three relay and mining policies are also included in the first release of segregated witness at reference implementation version 0.13.1. Softforks based on these policies are likely to be proposed in the near future. To avoid indefinite delay in transaction confirmation and permanent fund loss in a potential softfork, users MUST observe the new semantics carefully:
# Only compressed public keys are accepted in P2WPKH and P2WSH (See [https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#Restrictions_on_public_key_type BIP143])
# The argument of OP_IF/NOTIF in P2WSH must be minimalhttps://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html
# Signature(s) must be null vector(s) if an OP_CHECKSIG or OP_CHECKMULTISIG is failed (for both pre-segregated witness script and P2WSH. See [https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki BIP146])
== Examples ==
=== P2WPKH ===
The following example is a version 0 pay-to-witness-public-key-hash (P2WPKH):
witness:
scriptSig: (empty)
scriptPubKey: 0 <20-byte-key-hash>
(0x0014{20-byte-key-hash})
The '0' in scriptPubKey indicates the following push is a version 0 witness program. The length of the witness program indicates that it is a P2WPKH type. The witness must consist of exactly 2 items. The HASH160 of the pubkey in witness must match the witness program.
The signature is verified as
CHECKSIG
Comparing with a traditional P2PKH output, the P2WPKH equivalent occupies 3 less bytes in the scriptPubKey, and moves the signature and public key from scriptSig to witness.
=== P2WPKH nested in BIP16 P2SH ===
The following example is the same P2WPKH, but nested in a BIP16 P2SH output.
witness:
scriptSig: <0 <20-byte-key-hash>>
(0x160014{20-byte-key-hash})
scriptPubKey: HASH160 <20-byte-script-hash> EQUAL
(0xA914{20-byte-script-hash}87)
The only item in scriptSig is hashed with HASH160, compared against the 20-byte-script-hash in scriptPubKey, and interpreted as:
0 <20-byte-key-hash>
The public key and signature are then verified as described in the previous example.
Comparing with the previous example, the scriptPubKey is 1 byte bigger and the scriptSig is 23 bytes bigger. Although a nested witness program is less efficient, its payment address is fully transparent and backward compatible for all Bitcoin reference client since version 0.6.0.
=== P2WSH ===
The following example is an 1-of-2 multi-signature version 0 pay-to-witness-script-hash (P2WSH).
witness: 0 <1 2 CHECKMULTISIG>
scriptSig: (empty)
scriptPubKey: 0 <32-byte-hash>
(0x0020{32-byte-hash})
The '0' in scriptPubKey indicates the following push is a version 0 witness program. The length of the witness program indicates that it is a P2WSH type. The last item in the witness (the "witnessScript") is popped off, hashed with SHA256, compared against the 32-byte-hash in scriptPubKey, and deserialized:
1 2 CHECKMULTISIG
The script is executed with the remaining data from witness:
0 1 2 CHECKMULTISIG
P2WSH allows maximum script size of 10,000 bytes, as the 520-byte push limit is bypassed.
The scriptPubKey occupies 34 bytes, as opposed to 23 bytes of BIP16 P2SH. The increased size improves security against possible collision attacks, as 280 work is not infeasible anymore (By the end of 2015, 284 hashes have been calculated in Bitcoin mining since the creation of Bitcoin). The spending script is same as the one for an equivalent BIP16 P2SH output but is moved to witness.
=== P2WSH nested in BIP16 P2SH ===
The following example is the same 1-of-2 multi-signature P2WSH script, but nested in a BIP16 P2SH output.
witness: 0 <1 2 CHECKMULTISIG>
scriptSig: <0 <32-byte-hash>>
(0x220020{32-byte-hash})
scriptPubKey: HASH160 <20-byte-hash> EQUAL
(0xA914{20-byte-hash}87)
The only item in scriptSig is hashed with HASH160, compared against the 20-byte-hash in scriptPubKey, and interpreted as:
0 <32-byte-hash>
The P2WSH witnessScript is then executed as described in the previous example.
Comparing with the previous example, the scriptPubKey is 11 bytes smaller (with reduced security) while witness is the same. However, it also requires 35 bytes in scriptSig.
=== Extensible commitment structure ===
The new commitment in coinbase transaction is a hash of the witness root hash and a witness reserved value. The witness reserved value currently has no consensus meaning, but in the future allows new commitment values for future softforks. For example, if a new consensus-critical commitment is required in the future, the commitment in coinbase becomes:
Double-SHA256(Witness root hash|Hash(new commitment|witness reserved value))
For backward compatibility, the Hash(new commitment|witness reserved value) will go to the coinbase witness, and the witness reserved value will be recorded in another location specified by the future softfork. Any number of new commitment could be added in this way.
Any commitments that are not consensus-critical to Bitcoin, such as merge-mining, MUST NOT use the witness reserved value to preserve the ability to do upgrades of the Bitcoin consensus protocol.
The optional data space following the commitment also leaves room for metadata of future softforks, and MUST NOT be used for other purpose.
=== Trust-free unconfirmed transaction dependency chain ===
Segregated witness fixes the problem of transaction malleability fundamentally, which enables the building of unconfirmed transaction dependency chains in a trust-free manner.
Two parties, Alice and Bob, may agree to send certain amount of Bitcoin to a 2-of-2 multisig output (the "funding transaction"). Without signing the funding transaction, they may create another transaction, time-locked in the future, spending the 2-of-2 multisig output to third account(s) (the "spending transaction"). Alice and Bob will sign the spending transaction and exchange the signatures. After examining the signatures, they will sign and commit the funding transaction to the blockchain. Without further action, the spending transaction will be confirmed after the lock-time and release the funding according to the original contract. It also retains the flexibility of revoking the original contract before the lock-time, by another spending transaction with shorter lock-time, but only with mutual-agreement of both parties.
Such setups are not possible with BIP62 as the malleability fix, since the spending transaction could not be created without both parties first signing the funding transaction. If Alice reveals the funding transaction signature before Bob does, Bob is able to lock up the funding indefinitely without ever signing the spending transaction.
Unconfirmed transaction dependency chain is a fundamental building block of more sophisticated payment networks, such as duplex micropayment channel and the Lightning Network, which have the potential to greatly improve the scalability and efficiency of the Bitcoin system.
== Future extensions ==
=== Compact fraud proof for SPV nodes ===
Bitcoin right now only has two real security models. A user either runs a full-node which validates every block with all rules in the system, or a SPV (Simple Payment Verification) client which only validates the headers as a proof of publication of some transactions. The Bitcoin whitepaper suggested that SPV nodes may accept alerts from full nodes when they detect an invalid block, prompting the SPV node to download the questioned blocks and transactions for validation. This approach, however, could become a DoS attack vector as there is virtually no cost to generate a false alarm. An alarm must come with a compact, yet deterministic fraud proof.
In the current Bitcoin protocol, it is possible to generate compact fraud proof for almost all rules except a few:
# It is not possible to prove a miner has introduced too many Bitcoins in the coinbase transaction outputs without showing the whole block itself and all input transactions.
# It is not possible to prove the violation of any block specific constraints, such as size and sigop limits, without showing the whole block (and all input transactions in the case of sigop limit)
# It is not possible to prove the spending of a non-existing input without showing all transaction IDs in the blockchain way back to the genesis block.
Extra witness data can be committed that allows short proofs of block invalidity that SPV nodes can quickly verify:
# Sum trees for transaction fee can be committed making it possible to construct short proofs that the miner does not add excessive fees to the coinbase transaction. Similar for the block size and sigop count limit.
# Backlinks for the outputs spent by the transaction's inputs can be provided. These backlinks consist of a block hash and an offset that thin clients can easily query and check to verify that the outputs exist.
These commitments could be included in the extensible commitment structure through a soft fork and will be transparent to nodes that do not understand such new rules.
=== New script system ===
Since a version byte is pushed before a witness program, and programs with unknown versions are always considered as anyone-can-spend script, it is possible to introduce any new script system with a soft fork. The witness as a structure is not restricted by any existing script semantics and constraints, the 520-byte push limit in particular, and therefore allows arbitrarily large scripts and signatures.
Examples of new script systems include Schnorr signatures, which reduce the size of multisig transactions dramatically; Lamport signatures, which are quantum computing resistant; and Merklized abstract syntax trees, which allow very compact witnesses for conditional scripts with extreme complexity.
=== Per-input lock-time and relative-lock-time ===
Currently there is only one nLockTime field in a transaction and all inputs must share the same value. [https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP68] enables per-input relative-lock-time using the nSequence field, however, with a limited lock-time period and resolution.
With a soft fork, it is possible to introduce a separate witness structure to allow per-input lock-time and relative-lock-time, and a new script system that could sign and manipulate the new data (like [https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP65] and [https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112]).
== Backward compatibility ==
As a soft fork, older software will continue to operate without modification. Non-upgraded nodes, however, will not see nor validate the witness data and will consider all witness programs as anyone-can-spend scripts (except a few edge cases where the witness programs are equal to 0, which the script must fail). Wallets should always be wary of anyone-can-spend scripts and treat them with suspicion. Non-upgraded nodes are strongly encouraged to upgrade in order to take advantage of the new features.
'''What a non-upgraded wallet can do'''
* Receiving bitcoin from non-upgraded and upgraded wallets
* Sending bitcoin to non-upgraded and upgraded wallets with traditional P2PKH address (without any benefit of segregated witness)
* Sending bitcoin to upgraded wallets using a P2SH address
* Sending bitcoin to upgraded wallets using a native witness program through [https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki BIP70] payment protocol
'''What a non-upgraded wallet cannot do'''
* Validating segregated witness transaction. It assumes such a transaction is always valid
== Deployment ==
This BIP will be deployed by "version bits" BIP9 with the name "segwit" and using bit 1.
For Bitcoin mainnet, the BIP9 starttime will be midnight 15 November 2016 UTC (Epoch timestamp 1479168000) and BIP9 timeout will be midnight 15 November 2017 UTC (Epoch timestamp 1510704000).
For Bitcoin testnet, the BIP9 starttime will be midnight 1 May 2016 UTC (Epoch timestamp 1462060800) and BIP9 timeout will be midnight 1 May 2017 UTC (Epoch timestamp 1493596800).
== Credits ==
Special thanks to Gregory Maxwell for originating many of the ideas in this BIP and Luke-Jr for figuring out how to deploy this as a soft fork.
== Footnotes ==
== Reference Implementation ==
https://github.com/bitcoin/bitcoin/pull/8149
== References ==
*[[bip-0016.mediawiki|BIP16 Pay to Script Hash]]
*[[bip-0143.mediawiki|BIP143 Transaction Signature Verification for Version 0 Witness Program]]
*[[bip-0144.mediawiki|BIP144 Segregated Witness (Peer Services)]]
*[[bip-0173.mediawiki|BIP173 Base32 address format for native v0-16 witness outputs]]
== Copyright ==
This document is placed in the public domain.
================================================
FILE: bip-0142.mediawiki
================================================
BIP: 142
Layer: Applications
Title: Address Format for Segregated Witness
Authors: Johnson Lau
Status: Closed
Type: Specification
Assigned: 2015-12-24
License: PD
== Abstract ==
This BIP describes new types of Bitcoin address to support native segregated witness transactions with 20-byte and 32-byte program.
== Motivation ==
To define standard payment address for native segregated witness (segwit) transactions to promote early adoption of the more efficient transaction method.
== Specification ==
The new Bitcoin address format defined is for the Pay-to-Witness-Public-Key-Hash (P2WPKH) and Pay-to-Witness-Script-Hash (P2WSH) transaction described in segregated witness soft fork (BIP141). The scriptPubKey is an OP_0 followed by a push of 20-byte-hash (P2WPKH) or 32-byte hash (P2WSH).
The new address is encoded in a way similar to existing address formats:
base58-encode:
[1-byte address version]
[1-byte witness program version]
[0x00]
[20/32-byte-hash]
[4-byte checksum]
For P2WPKH address, the address version is 6 (0x06) for a main-network address or 3 (0x03) for a testnet address.
For P2WSH address, the address version is 10 (0x0A) for a main-network address or 40 (0x28) for a testnet address.
The witness program version is a 1-byte value between 0 (0x00) and 16 (0x10). Only version 0 is defined in BIP141. Versions 1 to 16 are reserved for future extensions.
Following the witness program version is a 0x00 padding to make sure that each witness program version will have a unique prefix.
Following the padding is the program hash, 20 byte for a P2WPKH address and 32 byte for a P2WSH address.
The 4-byte checksum is the first four bytes of the double SHA256 hash of the serialization of the previous items.
All addresses generated with this scheme will have a constant length, with 36 digits for 20-byte and 53 digits for 32-byte. Different witness program versions will have a unique prefix, as shown in the following table:
{|class="wikitable" style="text-align: center;"
|-
!rowspan=3 style=""|Witness program version
!colspan=4 style=""|Hash size
|-
!colspan=2 style=""|20-byte (36 characters)
!colspan=2 style=""|32-byte (53 characters)
|-
!Mainnet
!Testnet
!Mainnet
!Testnet
|-
|0||p2||QW||7Xh||T7n
|-
|1||p4||QY||7Xq||T7w
|-
|2||p6||Qa||7Xz||T85
|-
|3||p7||Qc||7Y9||T8E
|-
|4||pA||Qe||7YH||T8N
|-
|5||pB||Qf||7YS||T8X
|-
|6||pD||Qh||7Ya||T8g
|-
|7||pF||Qj||7Yj||T8p
|-
|8||pG||Qm||7Yt||T8y
|-
|9||pJ||Qn||7Z2||T97
|-
|10||pL||Qp||7ZB||T9G
|-
|11||pN||Qr||7ZK||T9Q
|-
|12||pQ||Qt||7ZU||T9Z
|-
|13||pS||Qv||7Zc||T9i
|-
|14||pT||Qw||7Zm||T9r
|-
|15||pV||Qy||7Zv||TA1
|-
|16||pX||R1||7a4||TA9
|-
|}
== Rationale ==
BIP141 defines 2 ways of encoding a "witness program", a data push of 2 to 32 bytes:
* A native witness program output is a scriptPubKey with a push of version byte followed by a push of witness program, and nothing else;
* Segwit-in-P2SH is a BIP16 P2SH redeemScript with a push of version byte followed by a push of witness program, while the scriptPubKey looks like a normal P2SH output.
Considering the BIP13 P2SH address has been defined in 2012, using segwit-in-P2SH allows most existing wallets to pay a segwit-compatible wallet without any upgrade. However, this method requires more block space and is only a short-term solution to make the transition smoother. Eventually, all users are expected to use the more efficient native witness program as the primary method of payment.
The drawbacks of Bitcoin addresses have been extensively discussed in BIP13. Since then, better payment methods have been proposed or deployed, for example:
*BIP47 Reusable Payment Codes for Hierarchical Deterministic Wallets
*BIP63 Stealth Addresses
*BIP70 Payment protocol
However, none of these are as widely adopted as the suboptimal base-58 scriptPubKey template addresses, which is still a standard for the whole eco-system, from wallets, block explorers, merchants, exchanges, to end users. It is believed that the proposed P2WPKH and P2WSH address format is the easiest way for wallets and services to adopt native witness program, which is particularly important in the context of scaling the capacity of the blockchain.
While P2WPKH address is specific for simple payment to a single public key, P2WSH address allows arbitrarily complex segwit transactions, similar to the BIP13 P2SH address.
== Compatibility ==
This proposal is not backward-compatible. However, an older implementation will report the new address type as invalid, and refuse to create a transaction.
This proposal is forward-compatible with future versions of witness programs of 20 and 32 bytes.
== Example ==
The following public key,
0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
when encoded as a P2PKH template, would become:
DUP HASH160 <010966776006953D5567439E5E39F86A0D273BEE> EQUALVERIFY CHECKSIG
With the corresponding version 1 Bitcoin address being:
16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
When the same public key is encoded as P2WPKH, the scriptPubKey becomes:
OP_0 <010966776006953D5567439E5E39F86A0D273BEE>
Using 0x06 as address version, followed by 0x00 as witness program version, and a 0x00 padding, the equivalent P2WPKH address is:
p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm
== Reference implementation ==
https://github.com/theuni/bitcoin/commit/ede1b57058ac8efdefe61f67395affb48f2c0d80
== References ==
* [[bip-0013.mediawiki|BIP 13: Address Format for pay-to-script-hash]]
* [[bip-0016.mediawiki|BIP 16: Pay to Script Hash]]
* [[bip-0070.mediawiki|BIP 70: Payment Protocol]]
* [[bip-0141.mediawiki|BIP 141: Segregated Witness]]
== Copyright ==
This work is placed in the public domain.
================================================
FILE: bip-0143.mediawiki
================================================
BIP: 143
Layer: Consensus (soft fork)
Title: Transaction Signature Verification for Version 0 Witness Program
Authors: Johnson Lau
Pieter Wuille
Status: Deployed
Type: Specification
Assigned: 2016-01-03
License: PD
== Abstract ==
This proposal defines a new transaction digest algorithm for signature verification in version 0 witness program, in order to minimize redundant data hashing in verification, and to cover the input value by the signature.
== Motivation ==
There are 4 ECDSA signature verification codes in the original Bitcoin script system: CHECKSIG, CHECKSIGVERIFY, CHECKMULTISIG, CHECKMULTISIGVERIFY (“sigops”). According to the sighash type (ALL, NONE, SINGLE, ANYONECANPAY), a transaction digest is generated with a double SHA256 of a serialized subset of the transaction, and the signature is verified against this digest with a given public key. The detailed procedure is described in a Bitcoin Wiki article. [https://en.bitcoin.it/wiki/OP_CHECKSIG]
Unfortunately, there are at least 2 weaknesses in the original SignatureHash transaction digest algorithm:
* For the verification of each signature, the amount of data hashing is proportional to the size of the transaction. Therefore, data hashing grows in O(n2) as the number of sigops in a transaction increases. While a 1 MB block would normally take 2 seconds to verify with an average computer in 2015, a 1MB transaction with 5569 sigops may take 25 seconds to verify. This could be fixed by optimizing the digest algorithm by introducing some reusable “midstate”, so the time complexity becomes O(n). [https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-2292 CVE-2013-2292][https://bitcointalk.org/?topic=140078 New Bitcoin vulnerability: A transaction that takes at least 3 minutes to verify][http://rusty.ozlabs.org/?p=522 The Megatransaction: Why Does It Take 25 Seconds?]
* The algorithm does not involve the amount of Bitcoin being spent by the input. This is usually not a problem for online network nodes as they could request for the specified transaction to acquire the output value. For an offline transaction signing device ("cold wallet"), however, the unknowing of input amount makes it impossible to calculate the exact amount being spent and the transaction fee. To cope with this problem a cold wallet must also acquire the full transaction being spent, which could be a big obstacle in the implementation of lightweight, air-gapped wallet. By including the input value of part of the transaction digest, a cold wallet may safely sign a transaction by learning the value from an untrusted source. In the case that a wrong value is provided and signed, the signature would be invalid and no funding might be lost. [https://bitcointalk.org/index.php?topic=181734.0 SIGHASH_WITHINPUTVALUE: Super-lightweight HW wallets and offline data]
Deploying the aforementioned fixes in the original script system is not a simple task. That would be either a hardfork, or a softfork for new sigops without the ability to remove or insert stack items. However, the introduction of segregated witness softfork offers an opportunity to define a different set of script semantics without disrupting the original system, as the unupgraded nodes would always consider such a transaction output is spendable by arbitrary signature or no signature at all. [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141: Segregated Witness (Consensus layer)]
== Specification ==
A new transaction digest algorithm is defined, but only applicable to sigops in version 0 witness program:
Double SHA256 of the serialization of:
1. nVersion of the transaction (4-byte little endian)
2. hashPrevouts (32-byte hash)
3. hashSequence (32-byte hash)
4. outpoint (32-byte hash + 4-byte little endian)
5. scriptCode of the input (serialized as scripts inside CTxOuts)
6. value of the output spent by this input (8-byte little endian)
7. nSequence of the input (4-byte little endian)
8. hashOutputs (32-byte hash)
9. nLocktime of the transaction (4-byte little endian)
10. sighash type of the signature (4-byte little endian)
Semantics of the original sighash types remain unchanged, except the following:
# The way of serialization is changed;
# All sighash types commit to the amount being spent by the signed input;
# FindAndDelete of the signature is not applied to the scriptCode;
# OP_CODESEPARATOR(s) after the last executed OP_CODESEPARATOR are not removed from the scriptCode (the last executed OP_CODESEPARATOR and any script before it are always removed);
# SINGLE does not commit to the input index. When ANYONECANPAY is not set, the semantics are unchanged since hashPrevouts and outpoint together implicitly commit to the input index. When SINGLE is used with ANYONECANPAY, omission of the index commitment allows permutation of the input-output pairs, as long as each pair is located at an equivalent index.
The items 1, 4, 7, 9, 10 have the same meaning as the original algorithm.
The item 5:
*For P2WPKH witness program, the scriptCode is 0x1976a914{20-byte-pubkey-hash}88ac.
*For P2WSH witness program,
**if the witnessScript does not contain any OP_CODESEPARATOR, the scriptCode is the witnessScript serialized as scripts inside CTxOut.
**if the witnessScript contains any OP_CODESEPARATOR, the scriptCode is the witnessScript but removing everything up to and including the last executed OP_CODESEPARATOR before the signature checking opcode being executed, serialized as scripts inside CTxOut. (The exact semantics is demonstrated in the examples below)
The item 6 is a 8-byte value of the amount of bitcoin spent in this input.
hashPrevouts:
*If the ANYONECANPAY flag is not set, hashPrevouts is the double SHA256 of the serialization of all input outpoints;
*Otherwise, hashPrevouts is a uint256 of 0x0000......0000.
hashSequence:
*If none of the ANYONECANPAY, SINGLE, NONE sighash type is set, hashSequence is the double SHA256 of the serialization of nSequence of all inputs;
*Otherwise, hashSequence is a uint256 of 0x0000......0000.
hashOutputs:
*If the sighash type is neither SINGLE nor NONE, hashOutputs is the double SHA256 of the serialization of all output amount (8-byte little endian) with scriptPubKey (serialized as scripts inside CTxOuts);
*If sighash type is SINGLE and the input index is smaller than the number of outputs, hashOutputs is the double SHA256 of the output amount with scriptPubKey of the same index as the input;
*Otherwise, hashOutputs is a uint256 of 0x0000......0000.In the original algorithm, a uint256 of 0x0000......0001 is committed if the input index for a SINGLE signature is greater than or equal to the number of outputs. In this BIP a 0x0000......0000 is committed, without changing the semantics.
The hashPrevouts, hashSequence, and hashOutputs calculated in an earlier verification may be reused in other inputs of the same transaction, so that the time complexity of the whole hashing process reduces from O(n2) to O(n).
Refer to the reference implementation, reproduced below, for the precise algorithm:
uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
CHashWriter ss(SER_GETHASH, 0);
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
ss << txTo.vin[n].prevout;
}
hashPrevouts = ss.GetHash();
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
CHashWriter ss(SER_GETHASH, 0);
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
ss << txTo.vin[n].nSequence;
}
hashSequence = ss.GetHash();
}
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
CHashWriter ss(SER_GETHASH, 0);
for (unsigned int n = 0; n < txTo.vout.size(); n++) {
ss << txTo.vout[n];
}
hashOutputs = ss.GetHash();
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}
CHashWriter ss(SER_GETHASH, 0);
// Version
ss << txTo.nVersion;
// Input prevouts/nSequence (none/all, depending on flags)
ss << hashPrevouts;
ss << hashSequence;
// The input being signed (replacing the scriptSig with scriptCode + amount)
// The prevout may already be contained in hashPrevout, and the nSequence
// may already be contained in hashSequence.
ss << txTo.vin[nIn].prevout;
ss << static_cast(scriptCode);
ss << amount;
ss << txTo.vin[nIn].nSequence;
// Outputs (none/one/all, depending on flags)
ss << hashOutputs;
// Locktime
ss << txTo.nLockTime;
// Sighash type
ss << nHashType;
return ss.GetHash();
== Restrictions on public key type ==
As a default policy, only compressed public keys are accepted in P2WPKH and P2WSH. Each public key passed to a sigop inside version 0 witness program must be a compressed key: the first byte MUST be either 0x02 or 0x03, and the size MUST be 33 bytes. Transactions that break this rule will not be relayed or mined by default.
Since this policy is preparation for a future softfork proposal, to avoid potential future funds loss, users MUST NOT use uncompressed keys in version 0 witness programs.
== Example ==
To ensure consistency in consensus-critical behaviour, developers should test their implementations against all the tests below. More tests related to this proposal could be found under https://github.com/bitcoin/bitcoin/tree/master/src/test/data .
=== Native P2WPKH ===
The following is an unsigned transaction:
0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000
nVersion: 01000000
txin: 02 fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f 00000000 00 eeffffff
ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a 01000000 00 ffffffff
txout: 02 202cb20600000000 1976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac
9093510d00000000 1976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac
nLockTime: 11000000
The first input comes from an ordinary P2PK:
scriptPubKey : 2103c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432ac value: 6.25
private key : bbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866
The second input comes from a P2WPKH witness program:
scriptPubKey : 00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1, value: 6
private key : 619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9
public key : 025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357
To sign it with a nHashType of 1 (SIGHASH_ALL):
hashPrevouts:
dSHA256(fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a01000000)
= 96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37
hashSequence:
dSHA256(eeffffffffffffff)
= 52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b
hashOutputs:
dSHA256(202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac)
= 863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5
hash preimage: 0100000096b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd3752b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3bef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a010000001976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac0046c32300000000ffffffff863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e51100000001000000
nVersion: 01000000
hashPrevouts: 96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37
hashSequence: 52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b
outpoint: ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a01000000
scriptCode: 1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac
amount: 0046c32300000000
nSequence: ffffffff
hashOutputs: 863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5
nLockTime: 11000000
nHashType: 01000000
sigHash: c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670
signature: 304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01
The serialized signed transaction is: 01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000
nVersion: 01000000
marker: 00
flag: 01
txin: 02 fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f 00000000 494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01 eeffffff
ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a 01000000 00 ffffffff
txout: 02 202cb20600000000 1976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac
9093510d00000000 1976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac
witness 00
02 47304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee01 21025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357
nLockTime: 11000000
=== P2SH-P2WPKH ===
The following is an unsigned transaction: 0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000
nVersion: 01000000
txin: 01 db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477 01000000 00 feffffff
txout: 02 b8b4eb0b00000000 1976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac
0008af2f00000000 1976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac
nLockTime: 92040000
The input comes from a P2SH-P2WPKH witness program:
scriptPubKey : a9144733f37cf4db86fbc2efed2500b4f4e49f31202387, value: 10
redeemScript : 001479091972186c449eb1ded22b78e40d009bdf0089
private key : eb696a065ef48a2192da5b28b694f87544b30fae8327c4510137a922f32c6dcf
public key : 03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873
To sign it with a nHashType of 1 (SIGHASH_ALL):
hashPrevouts:
dSHA256(db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a547701000000)
= b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a
hashSequence:
dSHA256(feffffff)
= 18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198
hashOutputs:
dSHA256(b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac)
= de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83
hash preimage: 01000000b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001976a91479091972186c449eb1ded22b78e40d009bdf008988ac00ca9a3b00000000feffffffde984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c839204000001000000
nVersion: 01000000
hashPrevouts: b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a
hashSequence: 18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198
outpoint: db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a547701000000
scriptCode: 1976a91479091972186c449eb1ded22b78e40d009bdf008988ac
amount: 00ca9a3b00000000
nSequence: feffffff
hashOutputs: de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83
nLockTime: 92040000
nHashType: 01000000
sigHash: 64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6
signature: 3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb01
The serialized signed transaction is: 01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000
nVersion: 01000000
marker: 00
flag: 01
txin: 01 db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477 01000000 1716001479091972186c449eb1ded22b78e40d009bdf0089 feffffff
txout: 02 b8b4eb0b00000000 1976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac
0008af2f00000000 1976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac
witness 02 473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb01 2103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873
nLockTime: 92040000
=== Native P2WSH ===
This example shows how OP_CODESEPARATOR and out-of-range SIGHASH_SINGLE are processed:
The following is an unsigned transaction:
0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000
nVersion: 01000000
txin: 02 fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e 00000000 00 ffffffff
0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f8 00000000 00 ffffffff
txout: 01 00f2052a01000000 1976a914a30741f8145e5acadf23f751864167f32e0963f788ac
nLockTime: 00000000
The first input comes from an ordinary P2PK:
scriptPubKey: 21036d5c20fa14fb2f635474c1dc4ef5909d4568e5569b79fc94d3448486e14685f8ac value: 1.5625
private key: b8f28a772fccbf9b4f58a4f027e07dc2e35e7cd80529975e292ea34f84c4580c
signature: 304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201 (SIGHASH_ALL)
The second input comes from a native P2WSH witness program:
scriptPubKey : 00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0, value: 49
witnessScript: 21026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac
<026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880ae> CHECKSIGVERIFY CODESEPARATOR <0255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465> CHECKSIG
To sign it with a nHashType of 3 (SIGHASH_SINGLE):
hashPrevouts:
dSHA256(fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000000815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f800000000)
= ef546acf4a020de3898d1b8956176bb507e6211b5ed3619cd08b6ea7e2a09d41
nVersion: 01000000
hashPrevouts: ef546acf4a020de3898d1b8956176bb507e6211b5ed3619cd08b6ea7e2a09d41
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: 0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f800000000
scriptCode: (see below)
amount: 0011102401000000
nSequence: ffffffff
hashOutputs: 0000000000000000000000000000000000000000000000000000000000000000 (this is the second input but there is only one output)
nLockTime: 00000000
nHashType: 03000000
scriptCode: 4721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac
^^
(please note that the not-yet-executed OP_CODESEPARATOR is not removed from the scriptCode)
preimage: 01000000ef546acf4a020de3898d1b8956176bb507e6211b5ed3619cd08b6ea7e2a09d4100000000000000000000000000000000000000000000000000000000000000000815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f8000000004721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac0011102401000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000003000000
sigHash: 82dde6e4f1e94d02c2b7ad03d2115d691f48d064e9d52f58194a6637e4194391
public key: 026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880ae
private key: 8e02b539b1500aa7c81cf3fed177448a546f19d2be416c0c61ff28e577d8d0cd
signature: 3044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e2703
scriptCode: 23210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac
(everything up to the last executed OP_CODESEPARATOR, including that OP_CODESEPARATOR, are removed)
preimage: 01000000ef546acf4a020de3898d1b8956176bb507e6211b5ed3619cd08b6ea7e2a09d4100000000000000000000000000000000000000000000000000000000000000000815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000023210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac0011102401000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000003000000
sigHash: fef7bd749cce710c5c052bd796df1af0d935e59cea63736268bcbe2d2134fc47
public key: 0255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465
private key: 86bf2ed75935a0cbef03b89d72034bb4c189d381037a5ac121a70016db8896ec
signature: 304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503
The serialized signed transaction is: 01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000
This example shows how unexecuted OP_CODESEPARATOR is processed, and SINGLE|ANYONECANPAY does not commit to the input index:
The following is an unsigned transaction:
0100000002e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac00000000
nVersion: 01000000
txin: 02 e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc001 00000000 00 ffffffff
80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b 00000000 00 ffffffff
txout: 02 8096980000000000 1976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac
8096980000000000 1976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac
nLockTime: 00000000
The first input comes from a native P2WSH witness program:
scriptPubKey: 0020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d value: 0.16777215
witnessScript:0063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
0 IF CODESEPARATOR ENDIF <0392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98> CHECKSIG
The second input comes from a native P2WSH witness program:
scriptPubKey: 0020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537 value: 0.16777215
witnessScript:5163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
1 IF CODESEPARATOR ENDIF <0392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98> CHECKSIG
To sign it with a nHashType of 0x83 (SINGLE|ANYONECANPAY):
nVersion: 01000000
hashPrevouts: 0000000000000000000000000000000000000000000000000000000000000000
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: (see below)
scriptCode: (see below)
amount: ffffff0000000000
nSequence: ffffffff
hashOutputs: (see below)
nLockTime: 00000000
nHashType: 83000000
outpoint: e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc00100000000
scriptCode: 270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
(since the OP_CODESEPARATOR is not executed, nothing is removed from the scriptCode)
hashOutputs: b258eaf08c39fbe9fbac97c15c7e7adeb8df142b0df6f83e017f349c2b6fe3d2
preimage: 0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc00100000000270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98acffffff0000000000ffffffffb258eaf08c39fbe9fbac97c15c7e7adeb8df142b0df6f83e017f349c2b6fe3d20000000083000000
sigHash: e9071e75e25b8a1e298a72f0d2e9f4f95a0f5cdf86a533cda597eb402ed13b3a
public key: 0392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98
private key: f52b3484edd96598e02a9c89c4492e9c1e2031f471c49fd721fe68b3ce37780d
signature: 3045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683
outpoint: 80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b00000000
scriptCode: 2468210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
(everything up to the last executed OP_CODESEPARATOR, including that OP_CODESEPARATOR, are removed)
hashOutputs: 91ea93dd77f702b738ebdbf3048940a98310e869a7bb8fa2c6cb3312916947ca
preimage: 010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b000000002468210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98acffffff0000000000ffffffff91ea93dd77f702b738ebdbf3048940a98310e869a7bb8fa2c6cb3312916947ca0000000083000000
sigHash: cd72f1f1a433ee9df816857fad88d8ebd97e09a75cd481583eb841c330275e54
public key: 0392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98
private key: f52b3484edd96598e02a9c89c4492e9c1e2031f471c49fd721fe68b3ce37780d
signature: 30440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83
The serialized signed transaction is:
01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000
nVersion: 01000000
marker: 00
flag: 01
txin: 02 e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc001 00000000 00 ffffffff
80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b 00000000 00 ffffffff
txout: 02 8096980000000000 1976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac
8096980000000000 1976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac
witness 02 483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683 270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
02 4730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83 275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
nLockTime: 00000000
Since SINGLE|ANYONECANPAY does not commit to the input index, the signatures are still valid when the input-output pairs are swapped:
0100000000010280e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffffe9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff0280969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac80969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000
nVersion: 01000000
marker: 00
flag: 01
txin: 02 80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b 00000000 00 ffffffff
e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc001 00000000 00 ffffffff
txout: 02 8096980000000000 1976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac
8096980000000000 1976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac
witness 02 4730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83 275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
02 483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683 270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac
nLockTime: 00000000
=== P2SH-P2WSH ===
This example is a P2SH-P2WSH 6-of-6 multisig witness program signed with 6 different SIGHASH types.
The following is an unsigned transaction: 010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000
nVersion: 01000000
txin: 01 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e 01000000 00 ffffffff
txout: 02 00e9a43500000000 1976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688ac
c0832f0500000000 1976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac
nLockTime: 00000000
The input comes from a P2SH-P2WSH 6-of-6 multisig witness program:
scriptPubKey : a9149993a429037b5d912407a71c252019287b8d27a587, value: 9.87654321
redeemScript : 0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54
witnessScript: 56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
hashPrevouts:
dSHA256(36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000)
= 74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0
hashSequence:
dSHA256(ffffffff)
= 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044
hashOutputs for ALL:
dSHA256(00e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac)
= bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc
hashOutputs for SINGLE:
dSHA256(00e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688ac)
= 9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f708
hash preimage for ALL: 0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa03bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504436641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000001000000
nVersion: 01000000
hashPrevouts: 74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0
hashSequence: 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044
outpoint: 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000
scriptCode: cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
amount: b168de3a00000000
nSequence: ffffffff
hashOutputs: bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc
nLockTime: 00000000
nHashType: 01000000
sigHash: 185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c
public key: 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3
private key: 730fff80e1413068a05b57d6a58261f07551163369787f349438ea38ca80fac6
signature: 304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01
hash preimage for NONE: 0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000002000000
nVersion: 01000000
hashPrevouts: 74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000
scriptCode: cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
amount: b168de3a00000000
nSequence: ffffffff
hashOutputs: 0000000000000000000000000000000000000000000000000000000000000000
nLockTime: 00000000
nHashType: 02000000
sigHash: e9733bc60ea13c95c6527066bb975a2ff29a925e80aa14c213f686cbae5d2f36
public key: 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b
private key: 11fa3d25a17cbc22b29c44a484ba552b5a53149d106d3d853e22fdd05a2d8bb3
signature: 3044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502
hash preimage for SINGLE: 0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000003000000
nVersion: 01000000
hashPrevouts: 74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000
scriptCode: cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
amount: b168de3a00000000
nSequence: ffffffff
hashOutputs: 9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f708
nLockTime: 00000000
nHashType: 03000000
sigHash: 1e1f1c303dc025bd664acb72e583e933fae4cff9148bf78c157d1e8f78530aea
public key: 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a
private key: 77bf4141a87d55bdd7f3cd0bdccf6e9e642935fec45f2f30047be7b799120661
signature: 3044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403
hash preimage for ALL|ANYONECANPAY: 010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffffbc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc0000000081000000
nVersion: 01000000
hashPrevouts: 0000000000000000000000000000000000000000000000000000000000000000
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000
scriptCode: cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
amount: b168de3a00000000
nSequence: ffffffff
hashOutputs: bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc
nLockTime: 00000000
nHashType: 81000000
sigHash: 2a67f03e63a6a422125878b40b82da593be8d4efaafe88ee528af6e5a9955c6e
public key: 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4
private key: 14af36970f5025ea3e8b5542c0f8ebe7763e674838d08808896b63c3351ffe49
signature: 3045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381
hash preimage for NONE|ANYONECANPAY: 010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000082000000
nVersion: 01000000
hashPrevouts: 0000000000000000000000000000000000000000000000000000000000000000
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000
scriptCode: cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
amount: b168de3a00000000
nSequence: ffffffff
hashOutputs: 0000000000000000000000000000000000000000000000000000000000000000
nLockTime: 00000000
nHashType: 82000000
sigHash: 781ba15f3779d5542ce8ecb5c18716733a5ee42a6f51488ec96154934e2c890a
public key: 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16
private key: fe9a95c19eef81dde2b95c1284ef39be497d128e2aa46916fb02d552485e0323
signature: 3045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a0882
hash preimage for SINGLE|ANYONECANPAY: 010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000083000000
nVersion: 01000000
hashPrevouts: 0000000000000000000000000000000000000000000000000000000000000000
hashSequence: 0000000000000000000000000000000000000000000000000000000000000000
outpoint: 36641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000
scriptCode: cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae
amount: b168de3a00000000
nSequence: ffffffff
hashOutputs: 9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f708
nLockTime: 00000000
nHashType: 83000000
sigHash: 511e8e52ed574121fc1b654970395502128263f62662e076dc6baf05c2e6a99b
public key: 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b
private key: 428a7aee9f0c2af0cd19af3cf1c78149951ea528726989b2e83e4778d2c3f890
signature: 30440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783
The serialized signed transaction is: 0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000
=== No FindAndDelete ===
These examples show that FindAndDelete for the signature is not applied. The transactions are generated in an unconventional way. Instead of signing using a private key, the signatures are pre-determined as part of witnessScript. The public keys are generated with key recovery, using the fixed signatures and the sighash defined in this proposal. Therefore, the private keys are unknown.
The following is an unsigned transaction: 010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff0101000000000000000000000000
nVersion: 01000000
txin: 01 69c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1 4c1d0000 00 ffffffff
txout: 01 0100000000000000 00
nLockTime: 00000000
The input comes from a P2WSH witness program:
scriptPubKey : 00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19, value: 0.00200000
redeemScript : OP_CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>
ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01
To sign it with a nHashType of 1 (SIGHASH_ALL):
hashPrevouts:
dSHA256(69c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d0000)
= b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f
hashSequence:
dSHA256(ffffffff)
= 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044
hashOutputs:
dSHA256(010000000000000000)
= e5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b934228
hash preimage: 01000000b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504469c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d00004aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01400d030000000000ffffffffe5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b9342280000000001000000
nVersion: 01000000
hashPrevouts: b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f
hashSequence: 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044
outpoint: 69c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d0000
scriptCode: 4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01
amount: 400d030000000000
nSequence: ffffffff
hashOutputs: e5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b934228
nLockTime: 00000000
nHashType: 01000000
sigHash: 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23
signature: 30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e 01
pubkey: 02a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c
The serialized signed transaction is: 0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000
nVersion: 01000000
marker: 00
flag: 01
txin: 01 69c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1 4c1d0000 00 ffffffff
txout: 01 0100000000000000 00
witness: 03 4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01
2102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c
4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01
nLockTime: 00000000
The following transaction is a OP_CHECKMULTISIGVERIFY version of the FindAndDelete examples: 010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000
redeemScript: OP_2 OP_CHECKMULTISIGVERIFY <30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601>
hash preimage: 0100000039283953eb1e26994dde57b7f9362a79a8c523e2f8deba943c27e826a005f1e63bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e706650449275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d00009552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175400d030000000000ffffffffe5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b9342280000000001000000
sighash: c1628a1e7c67f14ca0c27c06e4fdeec2e6d1a73c7a91d7c046ff83e835aebb72
witness: 07 00
4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01
48304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601
0102
2102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c0
21034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e
9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175
The new serialization format is described in BIP144 [[bip-0144.mediawiki|BIP144: Segregated Witness (Peer Services)]]
== Deployment ==
This proposal is deployed with Segregated Witness softfork (BIP 141)
== Backward compatibility ==
As a soft fork, older software will continue to operate without modification. Non-upgraded nodes, however, will not see nor validate the witness data and will consider all witness programs, including the redefined sigops, as anyone-can-spend scripts.
== Reference Implementation ==
https://github.com/bitcoin/bitcoin/pull/8149
== References ==
== Copyright ==
This document is placed in the public domain.
================================================
FILE: bip-0144.mediawiki
================================================
==Abstract==
This BIP defines new messages and serialization formats for propagation of transactions and blocks committing to segregated witness structures.
==Motivation==
In addition to defining witness structures and requiring commitments in future blocks ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141] - Consensus segwit BIP), new mechanisms must be defined to allow peers to advertise support for segregated witness and to relay the witness structures and request them from other peers without breaking compatibility with older nodes.
==Specification==
=== Serialization ===
A new serialization format for tx messages is added to the peer-to-peer protocol.
The serialization has the following structure:
{| class="wikitable" style="width: auto; text-align: center; font-size: smaller; table-layout: fixed;"
!Field Size
!Name
!Type
!Description
|-
| 4
| version
| int32_t
| Transaction data format version
|-
| 1
| marker
| char
| Must be zero
|-
| 1
| flag
| char
| Must be nonzero
|-
| 1+
| txin_count
| var_int
| Number of transaction inputs
|-
| 41+
| txins
| txin[]
| A list of one or more transaction inputs
|-
| 1+
| txout_count
| var_int
| Number of transaction outputs
|-
| 9+
| txouts
| txouts[]
| A list of one or more transaction outputs
|-
| 1+
| script_witnesses
| script_witnesses[]
| The witness structure as a serialized byte array
|-
| 4
| lock_time
| uint32_t
| The block number or timestamp until which the transaction is locked
|}
Parsers supporting this BIP will be able to distinguish between the old serialization format (without the witness) and this one. The marker byte is set to zero so that this structure will never parse as a valid transaction in a parser that does not support this BIP. If parsing were to succeed, such a transaction would contain no inputs and a single output.
If the witness is empty, the old serialization format must be used.
Currently, the only witness objects type supported are script witnesses which consist of a stack of byte arrays. It is encoded as a var_int item count followed by each item encoded as a var_int length followed by a string of bytes. Each txin has its own script witness. The number of script witnesses is not explicitly encoded as it is implied by txin_count. Empty script witnesses are encoded as a zero byte. The order of the script witnesses follows the same order as the associated txins.
* '''Rationale for not having an independent message type with its own serialization''': this would require separate "tx" and "block" messages, and all RPC calls operating on raw transactions would need to be duplicated, or need inefficient or nondeterministic guesswork to know which type is to be used.
* '''Rationale for not using just a single 0x00 byte as marker''': that would lead to empty transactions (no inputs, no outputs, which are used in some tests) to be interpreted as new serialized data.
* '''Rationale for the 0x01 flag byte in between''': this will allow us to easily add more extra non-committed data to transactions (like txouts being spent, ...). It can be interpreted as a bitvector.
=== Handshake ===
A node will signal that it can provide witnesses using the following service bit
NODE_WITNESS = (1 << 3)
=== Hashes ===
Transaction hashes used in the transaction merkle tree and txin outpoints are always computed using the old non-witness
serialization.
Support for a new hash including the witness data is added that is
computed from the new witness serialization. (Note that transactions
with an empty witness always use the old serialization,
and therefore, they have witness hash equal to normal hash.)
=== Relay ===
New inv types MSG_WITNESS_TX (0x40000001, or (1<<30)+MSG_TX) and MSG_WITNESS_BLOCK (0x40000002, or (1<<30)+MSG_BLOCK) are added, only
for use in getdata. Inventory messages themselves still use just MSG_TX and MSG_BLOCK,
similar to MSG_FILTERED_BLOCK. A further inv type MSG_FILTERED_WITNESS_BLOCK (0x40000003, or (1<<30)+MSG_FILTERED_BLOCK) is reserved for future use.
* '''Rationale for not advertizing witnessness in invs''': we don't always use invs anymore (with 'sendheaders' BIP 130), plus it's not useful: implicitly, every transaction and block have a witness, old ones just have empty ones.
MSG_WITNESS_TX getdata requests should use the non-witness serialized hash. The peer shall respond with a tx message, and if the witness structure is nonempty, the witness serialization shall be used.
MSG_WITNESS_BLOCK requests will return a block message with transactions that have a witness using witness serialization.
== Credits ==
Special thanks to Gregory Maxwell for originating many of the ideas in this BIP and Luke-Jr for figuring out how to deploy this as a soft fork.
== Reference Implementation ==
https://github.com/bitcoin/bitcoin/pull/8149
== Copyright ==
This document is placed in the public domain.
================================================
FILE: bip-0145.mediawiki
================================================
BIP: 145
Layer: API/RPC
Title: getblocktemplate Updates for Segregated Witness
Authors: Luke Dashjr
Status: Deployed
Type: Specification
Assigned: 2016-01-30
License: BSD-2-Clause OR OPUBL-1.0
==Abstract==
This BIP describes modifications to the getblocktemplate JSON-RPC call ([[bip-0022.mediawiki|BIP 22]]) to support segregated witness as defined by [[bip-0141.mediawiki|BIP 141]].
==Specification==
===Block Template===
The template Object is revised to include a new key:
{| class="wikitable"
!colspan=4| template
|-
! Key !! Required !! Type !! Description
|-
| weightlimit || No || Number || total weight allowed in blocks
|}
The '!' rule prefix MUST be enabled on the "segwit" rule for templates including transactions with witness data.
In particular, note that even if the client's "rules" list lacks "segwit", server MAY support old miners by producing a witness-free template and omitting the '!' rule prefix for "segwit" in the template's "rules" list.
If the GBT server does not support producing witness-free templates after its activation, it must also use the '!' rule prefix in the "vbavailable" list prior to activation.
====Transactions Object Format====
The Objects listed in the response's "transactions" key is revised to include these keys:
{| class="wikitable"
!colspan=3|template "transactions" element
|-
! Key !! Type !! Description
|-
| txid || String || transaction id encoded in hexadecimal; required for transactions with witness data
|-
| weight || Number || numeric weight of the transaction, as counted for purposes of the block's weightlimit; if key is not present, weight is unknown and clients MUST NOT assume it is zero, although they MAY choose to calculate it themselves
|-
| hash || String || reversed hash of complete transaction (with witness data included) encoded in hexadecimal
|}
Transactions with witness data may only be included if the template's "rules" list (see [[bip-0009.mediawiki#getblocktemplate_changes|BIP 9]]) includes "segwit".
===Sigops===
For templates with "segwit" enabled as a rule, the "sigoplimit" and "sigops" keys must use the new values as calculated in [[bip-0141.mediawiki#Sigops|BIP 141]].
===Block Assembly with Witness Transactions===
When block assembly is done without witness transactions, no changes are made by this BIP, and it should be assembled as previously.
When witness transactions are included in the block, the primary merkle root MUST be calculated with those transactions' "txid" field instead of "hash". A secondary merkle root MUST be calculated as per [[bip-0141.mediawiki#Commitment_structure|BIP 141's commitment structure specification]] to be inserted into the generation (coinbase) transaction.
Servers MUST NOT include a commitment in the "coinbasetxn" key on the template. Clients MUST insert the commitment as an additional output at the end of the final generation (coinbase) transaction. Only if the template includes a "mutable" key (see [[bip-0023.mediawiki#Mutations|BIP 23 Mutations]]) including "generation", the client MAY in that case place the commitment output in any position it chooses, provided that no later output matches the commitment pattern.
==Motivation==
Segregated witness substantially changes the structure of blocks, so the previous getblocktemplate specification is no longer sufficient.
It additionally also adds a new way of counting resource limits, and so GBT must be extended to convey this information correctly as well.
==Rationale==
Why doesn't "weightlimit" simply redefine the existing "sizelimit"?
* "sizelimit" is already enforced by clients by counting the sum of bytes in transactions' "data" keys.
* Servers may wish to limit the overall size of a block, independently from the "weight" of the block.
Why is "sigoplimit" redefined instead of a new "sigopweightlimit" being added?
* The old limit was already arbitrarily defined, and could not be counted by clients on their own anyway. The concept of "sigop weight" is merely a change in the arbitrary formula used.
Why is "sigoplimit" divided by 4?
* To resemble the previous values. (FIXME: is this a good reason? maybe we shouldn't divide it?)
Why is the witness commitment required to be added to the end of the generation transaction rather than anywhere else?
* Servers which do not allow modification of the generation outputs ought to be checking this as part of the validity of submissions. By requiring a specific placement, they can simply strip the commitment and do a byte-for-byte comparison of the outputs. Placing it at the end avoids the possibility of a later output matching the pattern and overriding it.
Why shouldn't the server simply add the commitment upfront in the "coinbasetxn", and simply send the client stripped transaction data?
* It would become impossible for servers to specify only "coinbasevalue", since clients would no longer have the information required to construct the commitment.
* getblocktemplate is intended to be a *decentralised* mining protocol, and allowing clients to be blinded to the content of the block works contrary to that purpose.
* BIP 23's "transactions" mutations allow the client to modify the transaction-set on their own, which is impossible without the complete transaction data.
==Reference Implementation==
* [https://github.com/bitcoin/libblkmaker/tree/segwit libblkmaker]
* [https://github.com/luke-jr/eloipool/tree/segwit Eloipool]
* [https://github.com/bitcoin/bitcoin/pull/7404/files Bitcoin Core]
==See Also==
* [[bip-0009.mediawiki|BIP 9: Version bits with timeout and delay]]
* [[bip-0022.mediawiki|BIP 22: getblocktemplate - Fundamentals]]
* [[bip-0023.mediawiki|BIP 23: getblocktemplate - Pooled Mining]]
* [[bip-0141.mediawiki|BIP 141: Segregated Witness (Consensus layer)]]
==Copyright==
This BIP is dual-licensed under the Open Publication License and BSD 2-clause license.
================================================
FILE: bip-0146.mediawiki
================================================
BIP: 146
Layer: Consensus (soft fork)
Title: Dealing with signature encoding malleability
Authors: Johnson Lau
Pieter Wuille
Status: Closed
Type: Specification
Assigned: 2016-08-16
License: PD
==Abstract==
This document specifies proposed changes to the Bitcoin transaction validity rules to fix signature malleability related to ECDSA signature encoding.
==Motivation==
Signature malleability refers to the ability of any relay node on the network to transform the signature in transactions, with no access to the relevant private keys required. For non-segregated witness transactions, signature malleability will change the txid and invalidate any unconfirmed child transactions. Although the txid of segregated witness ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) transactions is not third party malleable, this malleability vector will change the wtxid and may reduce the efficiency of compact block relay ([https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki BIP152]).
Since the enforcement of Strict DER signatures ([https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66]), there are 2 remaining known sources of malleability in ECDSA signatures:
# '''Inherent ECDSA signature malleability''': ECDSA signatures are inherently malleable as taking the negative of the number S inside (modulo the curve order) does not invalidate it.
# '''Malleability of failing signature''': If a signature failed to validate in OP_CHECKSIG or OP_CHECKMULTISIG, a FALSE would be returned to the stack and the script evaluation would continue. The failing signature may take any value, as long as it follows all the rules described in BIP66.
This document specifies new rules to fix the aforesaid signature malleability.
==Specification==
To fix signature encoding malleability, the following new rules are applied to pre-segregated witness and segregated witness scripts:
===LOW_S===
We require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially restricting this value to its lower half range). Every signature passed to OP_CHECKSIGIncluding pay-to-witness-public-key-hash (P2WPKH) described in BIP141, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, or OP_CHECKMULTISIGVERIFY, to which ECDSA verification is applied, MUST use a S value between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive) with strict DER encoding (see [https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66]).
If a signature passing to ECDSA verification does not pass the Low S value check and is not an empty byte array, the entire script evaluates to false immediately.
A high S value in signature could be trivially replaced by S' = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S.
===NULLFAIL===
If an OP_CHECKSIG is trying to return a FALSE value to the stack, we require that the relevant signature must be an empty byte array.
If an OP_CHECKMULTISIG is trying to return a FALSE value to the stack, we require that all signatures passing to this OP_CHECKMULTISIG must be empty byte arrays, even the processing of some signatures might have been skipped due to early termination of the signature verification.
Otherwise, the entire script evaluates to false immediately.
==Examples==
The following examples are the combined results of the LOW_S and NULLFAIL rules.Please note that due to implementation details in reference client v0.13.1, some signatures with S value higher than the half curve order might pass the LOW_S test. However, such signatures are certainly invalid, and will fail later due to NULLFAIL test.
Notation:
CO : curve order = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141
HCO : half curve order = CO / 2 = 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0
P1, P2 : valid, serialized, public keys
S1L, S2L : valid low S value signatures using respective keys P1 and P2 (1 ≤ S ≤ HCO)
S1H, S2H : signatures with high S value (otherwise valid) using respective keys P1 and P2 (HCO < S < CO)
F : any BIP66-compliant non-empty byte array but not a valid signature
These scripts will return a TRUE to the stack as before:
S1L P1 CHECKSIG
0 S1L S2L 2 P1 P2 2 CHECKMULTISIG
These scripts will return a FALSE to the stack as before:
0 P1 CHECKSIG
0 0 0 2 P1 P2 2 CHECKMULTISIG
These previously TRUE scripts will fail immediately under the new rules:
S1H P1 CHECKSIG
0 S1H S2L 2 P1 P2 2 CHECKMULTISIG
0 S1L S2H 2 P1 P2 2 CHECKMULTISIG
0 S1H S2H 2 P1 P2 2 CHECKMULTISIG
These previously FALSE scripts will fail immediately under the new rules:
F P1 CHECKSIG
0 S2L S1L 2 P1 P2 2 CHECKMULTISIG
0 S1L F 2 P1 P2 2 CHECKMULTISIG
0 F S2L 2 P1 P2 2 CHECKMULTISIG
0 S1L 0 2 P1 P2 2 CHECKMULTISIG
0 0 S2L 2 P1 P2 2 CHECKMULTISIG
0 F 0 2 P1 P2 2 CHECKMULTISIG
0 0 F 2 P1 P2 2 CHECKMULTISIG
==Deployment==
This BIP will be deployed by "version bits" [https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP9]. Details TBD.
For Bitcoin mainnet, the BIP9 starttime will be midnight TBD UTC (Epoch timestamp TBD) and BIP9 timeout will be midnight TBD UTC (Epoch timestamp TBD).
For Bitcoin testnet, the BIP9 starttime will be midnight TBD UTC (Epoch timestamp TBD) and BIP9 timeout will be midnight TBD UTC (Epoch timestamp TBD).
==Compatibility==
The reference client has produced LOW_S compatible signatures since v0.9.0, and the LOW_S rule has been enforced as relay policy by the reference client since v0.11.1. As of August 2016, very few transactions violating the requirement are being added to the chain. For all scriptPubKey types in actual use, non-compliant signatures can trivially be converted into compliant ones, so there is no loss of functionality by these requirements.
Scripts with failing OP_CHECKSIG or OP_CHECKMULTISIG rarely happen on the chain. The NULLFAIL rule has been enforced as relay policy by the reference client since v0.13.1.
Users MUST pay extra attention to these new rules when designing exotic scripts.
==Implementation==
Implementations for the reference client is available at:
https://github.com/bitcoin/bitcoin/blob/35fe0393f216aa6020fc929272118eade5628636/src/script/interpreter.cpp#L185
and
https://github.com/bitcoin/bitcoin/pull/8634
==Footnotes==
==Acknowledgements==
This document is extracted from the previous [https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki BIP62] proposal which had input from various people.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0147.mediawiki
================================================
BIP: 147
Layer: Consensus (soft fork)
Title: Dealing with dummy stack element malleability
Authors: Johnson Lau
Status: Deployed
Type: Specification
Assigned: 2016-09-02
License: PD
==Abstract==
This document specifies proposed changes to the Bitcoin transaction validity rules to fix a malleability vector in the extra stack element consumed by OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY.
==Motivation==
Signature malleability refers to the ability of any relay node on the network to transform the signature in transactions, with no access to the relevant private keys required. For non-segregated witness transactions, signature malleability will change the txid and invalidate any unconfirmed child transactions. Although the txid of segregated witness ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) transactions is not third party malleable, this malleability vector will change the wtxid and may reduce the efficiency of compact block relay ([https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki BIP152]).
A design flaw in OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY causes them to consume an extra stack element ("dummy element") after signature validation. The dummy element is not inspected in any manner, and could be replaced by any value without invalidating the script. This document specifies a new rule to fix this signature malleability.
==Specification==
To fix the dummy element malleability, a new consensus rule ("NULLDUMMY") is deployed to require that the dummy element MUST be the empty byte array. Anything else makes the script evaluate to false immediately. The NULLDUMMY rule applies to OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY in pre-segregated scripts, and also pay-to-witness-script-hash scripts described in BIP141.
==Deployment==
This BIP will be deployed by "version bits" [https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP9] using the same parameters for BIP141 and BIP143, with the name "segwit" and using bit 1.
For Bitcoin mainnet, the BIP9 starttime is midnight 15 November 2016 UTC (Epoch timestamp 1479168000) and BIP9 timeout is midnight 15 November 2017 UTC (Epoch timestamp 1510704000).
For Bitcoin testnet, the BIP9 starttime is midnight 1 May 2016 UTC (Epoch timestamp 1462060800) and BIP9 timeout is midnight 1 May 2017 UTC (Epoch timestamp 1493596800).
==Compatibility==
The reference client has produced compatible signatures from the beginning, and the NULLDUMMY rule has been enforced as relay policy by the reference client since v0.10.0. There has been no transactions violating the requirement being added to the chain since at least August 2015.
For all scriptPubKey types in actual use, non-compliant signatures can trivially be converted into compliant ones, so there is no loss of functionality by this requirement. Users MUST pay extra attention to this new rule when designing exotic scripts.
==Implementation==
An implementation for the reference client is available at https://github.com/bitcoin/bitcoin/pull/8636
==Acknowledgements==
Peter Todd is the original author of NULLDUMMY. This document is extracted from the previous [https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki BIP62] proposal, which was composed by Pieter Wuille and had input from various people.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0148.mediawiki
================================================
==Abstract==
This document specifies a BIP16 like soft fork flag day activation of the segregated witness BIP9 deployment known as "segwit".
==Definitions==
"existing segwit deployment" refer to the BIP9 "segwit" deployment using bit 1, between November 15th 2016 and November 15th 2017 to activate BIP141, BIP143 and BIP147.
==Motivation==
Segwit increases the blocksize, fixes transaction malleability, and makes scripting easier to upgrade as well as bringing many other [https://bitcoincore.org/en/2016/01/26/segwit-benefits/ benefits].
It is hoped that miners will respond to this BIP by activating segwit early, before this BIP takes effect. Otherwise this BIP will cause the mandatory activation of the existing segwit deployment before the end of midnight November 15th 2017.
==Specification==
All times are specified according to median past time.
This BIP will be active between midnight August 1st 2017 (epoch time 1501545600) and midnight November 15th 2017 (epoch time 1510704000) if the existing segwit deployment is not locked-in or activated before epoch time 1501545600. This BIP will cease to be active when segwit is locked-in.
While this BIP is active, all blocks must set the nVersion header top 3 bits to 001 together with bit field (1<<1) (according to the existing segwit deployment). Blocks that do not signal as required will be rejected.
=== Reference implementation ===
// Check if Segregated Witness is Locked In
bool IsWitnessLockedIn(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{
LOCK(cs_main);
return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_LOCKED_IN);
}
// BIP148 mandatory segwit signalling.
int64_t nMedianTimePast = pindex->GetMedianTimePast();
if ( (nMedianTimePast >= 1501545600) && // Tue 01 Aug 2017 00:00:00 UTC
(nMedianTimePast <= 1510704000) && // Wed 15 Nov 2017 00:00:00 UTC
(!IsWitnessLockedIn(pindex->pprev, chainparams.GetConsensus()) && // Segwit is not locked in
!IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus())) ) // and is not active.
{
bool fVersionBits = (pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS;
bool fSegbit = (pindex->nVersion & VersionBitsMask(chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) != 0;
if (!(fVersionBits && fSegbit)) {
return state.DoS(0, error("ConnectBlock(): relayed block must signal for segwit, please upgrade"), REJECT_INVALID, "bad-no-segwit");
}
}
https://github.com/bitcoin/bitcoin/compare/master...shaolinfry:bip-segwit-flagday
==Backwards Compatibility==
This deployment is compatible with the existing "segwit" bit 1 deployment scheduled between midnight November 15th, 2016 and midnight November 15th, 2017.
==Rationale==
Historically, the P2SH soft fork (BIP16) was activated using a predetermined flag day where nodes began enforcing the new rules. P2SH was successfully activated with relatively few issues
By orphaning non-signalling blocks during the last month of the BIP9 bit 1 "segwit" deployment, this BIP can cause the existing "segwit" deployment to activate without needing to release a new deployment.
==References==
*[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-March/013714.html Mailing list discussion]
*[https://github.com/bitcoin/bitcoin/blob/v0.6.0/src/main.cpp#L1281-L1283 P2SH flag day activation]
*[[bip-0009.mediawiki|BIP9 Version bits with timeout and delay]]
*[[bip-0016.mediawiki|BIP16 Pay to Script Hash]]
*[[bip-0141.mediawiki|BIP141 Segregated Witness (Consensus layer)]]
*[[bip-0143.mediawiki|BIP143 Transaction Signature Verification for Version 0 Witness Program]]
*[[bip-0147.mediawiki|BIP147 Dealing with dummy stack element malleability]]
*[https://bitcoincore.org/en/2016/01/26/segwit-benefits/ Segwit benefits]
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0149.mediawiki
================================================
==Abstract==
This document specifies a user activated soft fork for [[bip-0141.mediawiki|BIP141]], [[bip-0143.mediawiki|BIP143]] and [[bip-0147.mediawiki|BIP147]] using versionbits with guaranteed lock-in.
==Motivation==
Miners have been reluctant to signal the BIP9 segwit deployment despite a large portion of the Bitcoin ecosystem who want the soft fork activated. This BIP specifies a user activated soft fork (UASF) that deploys segwit again using versionbits with guaranteed lock-in on timeout if the BIP is not already locked-in or activated by the timeout. This ensures users have sufficient time to prepare and no longer require a miner supermajority, while still allowing for an earlier miner activated soft fork (MASF).
==Reference implementation==
The reference implementation will refuse to run on Bitcoin mainnet before 7 November 2017, and can only be run on testnet and regtest until then.
https://github.com/bitcoin/bitcoin/compare/master...shaolinfry:uasegwit-flagday
==Specification==
This deployment will set service bit (1<<5) as NODE_UAWITNESS.
==Deployment==
This BIP should only be deployed if BIP9-segwit fails to lock-in or activate before timeout on 15 November 2017. This BIP cannot be deployed before 15 November 2017.
This BIP will be deployed by BIP8 with the name "segwit" and using bit 1.
For Bitcoin mainnet, the BIP8 starttime will be midnight 16 November 2017 UTC (Epoch timestamp 1510790400) and BIP8 timeout will be 4 July 2018 UTC (Epoch timestamp 1530662400).
For Bitcoin testnet, segwit is already activated so no deployment is specified.
==Backwards Compatibility==
This deployment reuses the GBT deployment name "segwit" to maintain compatibility with existing mining software.
This deployment is incompatible with the BIP9-segwit deployment and should not be run concurrently with it.
==Rationale==
The '''starttime''' of this BIP is after the BIP9-segwit timeout to remove compatibility issues with old nodes.
==References==
[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-April/014234.html Mailing list discussion]
[[bip-0008.mediawiki|BIP8]]
[[bip-0009.mediawiki|BIP9]]
[[bip-0141.mediawiki|BIP141]]
[[bip-0143.mediawiki|BIP143]]
[[bip-0147.mediawiki|BIP147]]
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0150.mediawiki
================================================
== Abstract ==
This BIP describes a way for peers to authenticate to other peers to guarantee node ownership and/or allow peers to access additional or limited node services, without the possibility of fingerprinting.
== Motivation ==
We assume peer operators want to limit the access of different node services or increase datastream priorities to a selective subset of peers. Also we assume that peers want to connect to specific peers to broadcast or filter transactions (or similar actions that reveal sensitive information) and therefore operators want to authenticate the remote peer and ensure that they have not connected to a MITM (man-in-the-middle) attacker.
Benefits of peer authentication:
* Peers can detect MITM attacks when connecting to known peers
* Peers can allow resource hungry transaction filtering only to specific peers
* Peers can allow access to sensitive information that can lead to node fingerprinting (fee estimation)
* Peers can allow custom message types (private extensions) to authenticated peers
A simple authentication scheme based on elliptic cryptography will allow peers to identify each other and selectively allow access to restricted services or reject the connection if the peer identity cannot be verified.
== Specification ==
The authentication scheme proposed in this BIP uses ECDSA, '''secrets will never be transmitted'''.
'''Authentication initialization must only happen if encrypted channels have been established (according to BIP-151 [1]).'''
The '''encryption-session-ID''' is available once channels are encrypted (according to BIP-151 [1]).
The identity-public-keys used for the authentication must be pre-shared over a different channel (mail/PGP, physical paper exchange, etc.). This BIP does not cover a "trust on first use" (TOFU) concept.
The authentication state must be kept until the encryption/connection terminates.
Only one authentication process is allowed per connection. Re-authentication require re-establishing the connection.
=== Known-peers and authorized-peers database ===
Each peer that supports p2p authentication must provide two user-editable "databases".
# '''known-peers''' contains known identity-public-keys together with a network identifier (IP & port), similar to the "known-host" file supported by openssh.
# '''authorized-peers''' contains authorized identity-public-keys
=== Local identity key management ===
Each peer can configure multiple identity-keys (ECC, 32 bytes). Peers should make sure that each network interface (IPv4, IPv6, tor) has its own identity-key (otherwise it would be possible to link a tor address to a IPvX address).
The identity-public-key(s) can be shared over a different channel with other node-operators (or non-validating clients) to grant authorized access.
=== Authentication procedure ===
Authentication based on this BIP will require both sides to authenticate. Signatures/public-keys will only be revealed if the remote peer can prove that they already know the remote identity-public-key.
# -> Requesting peer sends AUTHCHALLENGE (hash)
# <- Responding peer sends AUTHREPLY (signature)
# -> Requesting peer sends AUTHPROPOSE (hash)
# <- Responding peer sends AUTHCHALLENGE (hash)
# -> Requesting peer sends AUTHREPLY (signature)
For privacy reasons, dropping the connection or aborting during the authentication process must not be allowed.
=== AUTHCHALLENGE message ===
A peer can send an authentication challenge to see if the responding peer can produce a valid signature with the expected responding peer's identity-public-key by sending an AUTHCHALLENGE-message to the remote peer.
The responding peer needs to check if the hash matches the hash calculated with his own local identity-public-key. Fingerprinting the requesting peer is not possible.
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 32bytes || challenge-hash || hash || hash(encryption-session-ID || challenge_type || remote-peers-expected-identity-public-key)
|}
challenge_type is a single character. i if the AUTHCHALLENGE-message is the first, requesting challenge or r if it's the second, remote peers challenge message.
=== AUTHREPLY message ===
A peer must reply an AUTHCHALLENGE-message with an AUTHREPLY-message.
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 64bytes || signature || normalized comp.-signature || A signature of the encryption-session-ID done with the identity-key
|}
If the challenge-hash from the AUTHCHALLENGE-message did not match the local authentication public-key, the signature must contain 64 bytes of zeros.
The requesting peer can check the responding peer's identity by checking the validity of the sent signature against with the pre-shared remote peers identity-public-key.
If the signature was invalid, the requesting peer must still proceed with the authentication by sending an AUTHPROPOSE-message with 32 random bytes.
=== AUTHPROPOSE message ===
A peer can propose authentication of the channel by sending an AUTHPROPOSE-message to the remote peer.
If the signature sent in AUTHREPLY was invalid, the peer must still send an AUTHPROPOSE-message containing 32 random bytes.
The AUTHPROPOSE message must be answered with an AUTHCHALLENGE-message - even if the proposed requesting-peers identity-public-key has not been found in the authorized-peers database. In case of no match, the responding AUTHCHALLENGE-message must contains 32 bytes of zeros.
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 32bytes || auth-propose-hash || hash || hash(encryption-session-ID || "p" || identity-public-key)
|}
== Post-Authentication Re-Keying ==
After the second AUTHREPLY message (requesting peer's signature -> responding peer), both clients must re-key the symmetric encryption according to BIP151 while using '''a slightly different re-key key derivation hash'''.
Both peers re-key with hash(encryption-session-ID || old_symmetric_cipher_key || requesting-peer-identity-public-key || responding-peer-identity-public-key)
== Identity-Addresses ==
The peers should display/log the identity-public-key as an identity-address to the users, which is a base58-check encoded ripemd160(sha256) hash. The purpose of this is for better visual comparison (logs, accept-dialogs).
The base58check identity byte is 0x0F followed by an identity-address version number (=0xFF01).
An identity address would look like TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA and can be interpreted as a remote peer's fingerprint.
== Compatibility ==
This proposal is backward compatible. Non-supporting peers will ignore the new AUTH* messages.
== Example of an auth interaction ==
Before authentication (once during peer setup or upgrade)
# Requesting peer and responding peer create each an identity-keypair (standard ECC priv/pubkey)
# Requesting and responding peer share the identity-public-key over a different channel (mail/PGP, physical paper exchange, etc.)
# Responding peer stores requesting peers identity-public-key in its authorized-peers database (A)
# Requesting peer stores responding peers identity-public-key in its known-peers database together with its IP and port (B)
Encryption
# Encrypted channels must be established (according to BIP-151 [1])
Authentication
# Requesting peer sends an AUTHCHALLENGE message
AUTHCHALLENGE:
[32 bytes, hash(encryption-session-ID || "i" || )]
# Responding peer does create the same hash (encryption-session-ID || "i" || ) with its local identity-public-key
# If the hash does not match, response with an AUTHREPLY message containing 64bytes of zeros.
# In case of a match, response with an AUTHREPLY message
AUTHREPLY:
[64 bytes normalized compact ECDSA signature (H)] (sig of the encryption-session-ID done with the identity-key)
# Requesting peer does verify the signature with the remote-peers-identity-public-key
# If the signature is invalid, requesting peer answers with an AUTHREPLY message containing 32 random bytes
# In case of a valid signature, requesting peer sends an AUTHPROPOSE message
AUTHPROPOSE:
[32 bytes, hash(encryption-session-ID || "p" || )]
# Responding peer iterates over authorized-peers database (A), hashes the identical data and looks for a match.
# If the hash does not match, responding peer answer with an AUTHCHALLENGE message containing 32 bytes of zeros.
# In case of a match, responding peer sends an AUTHCHALLENGE message with the hashed client public-key
AUTHCHALLENGE:
[32 bytes, hash(encryption-session-ID || "r" || )]
# Requesting peer sends an AUTHREPLY message containing 64 bytes of zeros if server failed to authenticate
# Otherwise, response with signature in the AUTHREPLY message
AUTHREPLY:
[64 bytes normalized compact ECDSA signature (H)] (sig of the encryption-session-ID done with the identity-key)
# Responding peer must verify the signature and can grant access to restricted services.
# Both peers re-key the encryption after BIP151 including the requesting-peer-identity-public-key and responding-peer-identity-public-key
== Disadvantages ==
The protocol may be slow if a peer has a large authorized-peers database due to the requirement of iterating and hashing over all available authorized peer identity-public-keys.
== Reference implementation ==
== References ==
* [1] [[bip-0151.mediawiki|BIP 151: Peer-to-Peer Communication Encryption]]
== Acknowledgements ==
* Gregory Maxwell and Pieter Wuille for most of the ideas in this BIP.
* Bryan Bishop for editing.
== Copyright ==
This work is placed in the public domain.
================================================
FILE: bip-0151.mediawiki
================================================
BIP: 151
Layer: Peer Services
Title: Peer-to-Peer Communication Encryption
Authors: Jonas Schnelli
Comments-Summary: Controversial; some recommendation, and some discouragement
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0151
Status: Closed
Type: Specification
Assigned: 2016-03-23
License: PD
Proposed-Replacement: 324
== Abstract ==
This BIP describes an alternative way that a peer can encrypt their communication between a selective subset of remote peers.
== Motivation ==
The Bitcoin network does not encrypt communication between peers today. This opens up security issues (eg: traffic manipulation by others) and allows for mass surveillance / analysis of bitcoin users. Mostly this is negligible because of the nature of Bitcoin's trust model, however, for SPV nodes this can have significant privacy impacts [1] and could reduce the censorship-resistance of a peer.
Encrypting peer traffic will make analysis and specific user targeting much more difficult than it currently is. Today it's trivial for a network provider or any other men-in-the-middle to identify a Bitcoin user and its controlled addresses/keys (and link with his Google profile, etc.). Just created and broadcasted transactions will reveal the amount and the payee to the network provider.
This BIP also describes a way that data manipulation (blocking commands by a intercepting TCP/IP node) would be identifiable by the communicating peers.
Analyzing the type of p2p communication would still be possible because of the characteristics (size, sending-interval, etc.) of the encrypted messages.
Encrypting traffic between peers is already possible with VPN, tor, stunnel, curveCP or any other encryption mechanism on a deeper OSI level, however, most mechanisms are not practical for SPV or other DHCP/NAT environment and will require significant knowhow in how to setup such a secure channel.
== Specification ==
A peer that supports encryption must accept encryption requests from all peers.
An independent ECDH negotiation for both communication directions is required and therefore a bidirectional communication will use two symmetric cipher keys (one per direction).
Both peers must only send encrypted messages after a successful ECDH negotiation in ''both directions''.
Encryption initialization must happen before sending any other messages to the responding peer (encinit message after a version message must be ignored).
=== Symmetric Encryption Cipher Keys ===
The symmetric encryption cipher keys will be calculated with ECDH/HKDF by sharing the pubkeys of an ephemeral key. Once the ECDH secret is calculated on each side, the symmetric encryption cipher keys must be derived with HKDF [2] after the following specification:
1. HKDF extraction
PRK = HKDF_EXTRACT(hash=SHA256, salt="bitcoinecdh", ikm=ecdh_secret|cipher-type).
2. Derive Key1
K_1 = HKDF_EXPAND(prk=PRK, hash=SHA256, info="BitcoinK1", L=32)
3. Derive Key2
K_2 = HKDF_EXPAND(prk=PRK, hash=SHA256, info="BitcoinK2", L=32)
It is important to include the cipher-type into the symmetric cipher key derivation to avoid weak-cipher-attacks.
=== Session ID ===
Both sides must also calculate the 256bit session-id using SID = HKDF_EXPAND(prk=PRK, hash=SHA256, info="BitcoinSessionID", L=32). The session-id can be used for linking the encryption-session to an identity check.
=== The encinit message type ===
To request encrypted communication, the requesting peer generates an EC ephemeral-session-keypair and sends an encinit message to the responding peer and waits for an encack message. The responding node must do the same encinit/encack interaction for the opposite communication direction.
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 33bytes || ephemeral-pubkey || comp.-pubkey || The session pubkey from the requesting peer
|-
| 1bytes || symmetric key cipher type || int8 || symmetric key cipher type to use
|}
Possible symmetric key ciphers types
{|class="wikitable"
! Number !! symmetric key ciphers type
|-
| 0 || chacha20-poly1305@openssh.com
|}
=== ChaCha20-Poly1305 Cipher Suite ===
ChaCha20 is a stream cipher designed by Daniel Bernstein [3]. It operates by permuting 128 fixed bits, 128 or 256 bits of key,
a 64 bit nonce and a 64 bit counter into 64 bytes of output. This output is used as a keystream, with any unused bytes simply discarded.
Poly1305, also by Daniel Bernstein [4], is a one-time Carter-Wegman MAC that computes a 128 bit integrity tag given a message and a single-use
256 bit secret key.
The chacha20-poly1305@openssh.com specified and defined by openssh [5] combines these two primitives into an authenticated encryption mode. The construction used is based on that proposed for TLS by Adam Langley [6], but differs in the layout of data passed to the MAC and in the addition of encryption of the packet lengths.
K_1 must be used to only encrypt the payload size of the encrypted message to avoid leaking information by revealing the message size.
K_2 must be used in conjunction with poly1305 to build an AEAD.
Optimized implementations of ChaCha20-Poly1305 are very fast in general, therefore it is very likely that encrypted messages require less CPU cycles per byte than the current unencrypted p2p message format. A quick analysis by Pieter Wuille of the current ''standard implementations'' has shown that SHA256 requires more CPU cycles per byte than ChaCha20 & Poly1304.
=== The encack message type ===
The responding peer accepts the encryption request by sending an encack message.
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 33bytes || ephemeral-pubkey || comp.-pubkey || The session pubkey from the responding peer
|}
At this point, the shared secret key for the symmetric key cipher must be calculated by using ECDH (own privkey x remote pub key).
Private keys will never be transmitted. The shared secret can only be calculated if an attacker knows at least one private key and the remote peer's public key.
* '''The encinit/encack interaction must be done from both sides.'''
* Each communication direction uses its own secret key for the symmetric cipher.
* The second encinit request (from the responding peer) must use the same symmetric cipher type.
* All unencrypted messages before the second encack response (from the responding peer) must be ignored.
* After a successful encinit/encack interaction, the "encrypted messages structure" must be used. Non-encrypted messages from the requesting peer must lead to a connection termination.
After a successful encinit/encack interaction from both sides, the messages format must use the "encrypted messages structure". Non-encrypted messages from the requesting peer must lead to a connection termination (can be detected by the 4 byte network magic in the unencrypted message structure).
=== Encrypted Messages Structure ===
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| 4 || length || uint32_t || Length of ciphertext payload in number of bytes
|-
| ? || ciphertext payload || ? || One or many ciphertext command & message data
|-
| 16 || MAC tag || ? || 128bit MAC-tag
|}
Encrypted messages do not have the 4byte network magic.
The maximum message length needs to be chosen carefully. The 4 byte length field can lead to a required message buffer of 4 GiB.
Processing the message before the authentication succeeds must not be done.
The 4byte sha256 checksum is no longer required because the AEAD.
Both peers need to track the message sequence number (uint32) of sent messages to the remote peer for building a 64 bit symmetric cipher IV. Sequence numbers are allowed to overflow to zero after 4294967295 (2^32-1).
The encrypted payload will result decrypted in one or many unencrypted messages:
{|class="wikitable"
! Field Size !! Description !! Data type !! Comments
|-
| ? || command || varlen || ASCII string identifying the packet content, we are using varlen in the encrypted messages.
|-
| 4 || length || uint32_t || Length of plaintext payload
|-
| ? || payload || ? || The actual data
|}
If more data is present, another message must be deserialized. There is no explicit amount-of-messages integer.
=== Re-Keying ===
A responding peer can inform the requesting peer over a re-keying with an encack message containing 33byte of zeros to indicate that all encrypted message following after this encack message will be encrypted with ''the next symmetric cipher key''.
The new symmetric cipher key will be calculated by SHA256(SHA256(session_id || old_symmetric_cipher_key)).
Re-Keying interval is a peer policy with a minimum timespan of 10 seconds.
The Re-Keying must be done after every 1GB of data sent or received (recommended by RFC4253 SSH Transport).
=== Risks ===
The encryption does not include an identity authentication scheme. This BIP does not cover a proposal to avoid MITM attacks during the encryption initialization.
Identity authentication will be covered in another BIP and will presume communication encryption after this BIP.
== Compatibility ==
This proposal is backward compatible. Non-supporting peers will ignore the encinit messages.
== Reference implementation ==
== References ==
* [1] https://e-collection.library.ethz.ch/eserv/eth:48205/eth-48205-01.pdf
* [2] HKDF (RFC 5869) https://tools.ietf.org/html/rfc5869
* [3] ChaCha20 https://cr.yp.to/chacha/chacha-20080128.pdf
* [4] Poly1305 https://cr.yp.to/mac/poly1305-20050329.pdf
* [5] https://github.com/openssh/openssh-portable/blob/05855bf2ce7d5cd0a6db18bc0b4214ed5ef7516d/PROTOCOL.chacha20poly1305
* [6] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03
== Acknowledgements ==
* Pieter Wuille and Gregory Maxwell for most of the ideas in this BIP.
== Copyright ==
This work is placed in the public domain.
================================================
FILE: bip-0152.mediawiki
================================================
==Abstract==
Compact blocks on the wire as a way to save bandwidth for nodes on the P2P network.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
==Motivation==
Historically, the Bitcoin P2P protocol has not been very bandwidth efficient for block relay. Every transaction in a block is included when relayed, even though a large number of the transactions in a given block are already available to nodes before the block is relayed. This causes moderate inbound bandwidth spikes for nodes when receiving blocks, but can cause very significant outbound bandwidth spikes for some nodes which receive a block before their peers. When such spikes occur, buffer bloat can make consumer-grade internet connections temporarily unusable, and can delay the relay of blocks to remote peers who may choose to wait instead of redundantly requesting the same block from other, less congested, peers.
Thus, decreasing the bandwidth used during block relay is very useful for many individuals running nodes.
While the goal of this work is explicitly not to reduce block transfer latency, it does, as a side effect reduce block transfer latencies in some rather significant ways. Additionally, this work forms a foundation for future work explicitly targeting low-latency block transfer.
==Specification for version 1==
===Intended Protocol Flow===
The protocol is intended to be used in two ways, depending on the peers and bandwidth available, as discussed [[#Implementation_Notes|later]]. The "high-bandwidth" mode, which nodes may only enable for a few of their peers, is enabled by setting the first boolean to 1 in a sendcmpct message. In this mode, peers send new block announcements with the short transaction IDs already (via a cmpctblock message), possibly even before fully validating the block (as indicated by the grey box in the image above). In some cases no further round-trip is needed, and the receiver can reconstruct the block and process it as usual immediately. When some transactions were not available from local sources (ie mempool), a getblocktxn/blocktxn roundtrip is necessary, bringing the best-case latency to the same 1.5*RTT minimum time that nodes take today, though with significantly less bandwidth usage.
The "low-bandwidth" mode is enabled by setting the first boolean to 0 in a sendcmpct message. In this mode, peers send new block announcements with the usual inv/headers announcements (as per BIP130, and after fully validating the block). The receiving peer may then request the block using a MSG_CMPCT_BLOCK getdata request, which will receive a response of the header and short transaction IDs. In some cases no further round-trip is needed, and the receiver can reconstruct the block and process it as usual, taking the same 1.5*RTT minimum time that nodes take today, though with significantly less bandwidth usage. When some transactions were not available from local sources (ie mempool), a getblocktxn/blocktxn roundtrip is necessary, bringing the latency to at least 2.5*RTT in this case, again with significantly less bandwidth usage than today. Because TCP often exhibits worse transfer latency for larger data sizes (as a multiple of RTT), total latency is expected to be reduced even when the full 2.5*RTT transfer mechanism is used.
===New data structures===
Several new data structures are added to the P2P network to relay compact blocks: PrefilledTransaction, HeaderAndShortIDs, BlockTransactionsRequest, and BlockTransactions.
For the purposes of this section, CompactSize refers to the variable-length integer encoding used across the existing P2P protocol to encode array lengths, among other things, in 1, 3, 5 or 9 bytes. Only CompactSize encodings which are minimally-encoded (ie the shortest length possible) are used by this spec. Any other CompactSize encodings are left with undefined behavior.
Several uses of CompactSize below are "differentially encoded". For these, instead of using raw indexes, the number encoded is the difference between the current index and the previous index, minus one. For example, a first index of 0 implies a real index of 0, a second index of 0 thereafter refers to a real index of 1, etc.
====PrefilledTransaction====
A PrefilledTransaction structure is used in HeaderAndShortIDs to provide a list of a few transactions explicitly.
{|
|Field Name||Type||Size||Encoding||Purpose
|-
|index||CompactSize||1, 3 bytes||Compact Size, differentially encoded since the last PrefilledTransaction in a list||The index into the block at which this transaction is
|-
|tx||Transaction||variable||As encoded in "tx" messages sent in response to getdata MSG_TX||The transaction which is in the block at index index.
|}
====HeaderAndShortIDs====
A HeaderAndShortIDs structure is used to relay a block header, the short transactions IDs used for matching already-available transactions, and a select few transactions which we expect a peer may be missing.
{|
|Field Name||Type||Size||Encoding||Purpose
|-
|header||Block header||80 bytes||First 80 bytes of the block as defined by the encoding used by "block" messages||The header of the block being provided
|-
|nonce||uint64_t||8 bytes||Little Endian||A nonce for use in short transaction ID calculations
|-
|shortids_length||CompactSize||1 or 3 bytes||As used to encode array lengths elsewhere||||The number of short transaction IDs in shortids (ie block tx count - prefilledtxn_length)
|-
|shortids||List of 6-byte integers||6*shortids_length bytes||Little Endian||The short transaction IDs calculated from the transactions which were not provided explicitly in prefilledtxn
|-
|prefilledtxn_length||CompactSize||1 or 3 bytes||As used to encode array lengths elsewhere||||The number of prefilled transactions in prefilledtxn (ie block tx count - shortids_length)
|-
|prefilledtxn||List of PrefilledTransactions||variable size*prefilledtxn_length||As defined by PrefilledTransaction definition, above||Used to provide the coinbase transaction and a select few which we expect a peer may be missing
|}
====BlockTransactionsRequest====
A BlockTransactionsRequest structure is used to list transaction indexes in a block being requested.
{|
|Field Name||Type||Size||Encoding||Purpose
|-
|blockhash||Binary blob||32 bytes||The output from a double-SHA256 of the block header, as used elsewhere||The blockhash of the block which the transactions being requested are in
|-
|indexes_length||CompactSize||1 or 3 bytes||As used to encode array lengths elsewhere||||The number of transactions being requested
|-
|indexes||List of CompactSizes||1 or 3 bytes*indexes_length||Differentially encoded||The indexes of the transactions being requested in the block
|}
====BlockTransactions====
A BlockTransactions structure is used to provide some of the transactions in a block, as requested.
{|
|Field Name||Type||Size||Encoding||Purpose
|-
|blockhash||Binary blob||32 bytes||The output from a double-SHA256 of the block header, as used elsewhere||The blockhash of the block which the transactions being provided are in
|-
|transactions_length||CompactSize||1 or 3 bytes||As used to encode array lengths elsewhere||||The number of transactions provided
|-
|transactions||List of Transactions||variable||As encoded in "tx" messages in response to getdata MSG_TX||The transactions provided
|}
====Short transaction IDs====
Short transaction IDs are used to represent a transaction without sending a full 256-bit hash. They are calculated by:
# single-SHA256 hashing the block header with the nonce appended (in little-endian)
# Running SipHash-2-4 with the input being the transaction ID and the keys (k0/k1) set to the first two little-endian 64-bit integers from the above hash, respectively.
# Dropping the 2 most significant bytes from the SipHash output to make it 6 bytes.
===New messages===
A new inv type (MSG_CMPCT_BLOCK == 4) and several new protocol messages are added: sendcmpct, cmpctblock, getblocktxn, and blocktxn.
====sendcmpct====
# The sendcmpct message is defined as a message containing a 1-byte integer followed by a 8-byte integer where pchCommand == "sendcmpct".
# The first integer SHALL be interpreted as a boolean (and MUST have a value of either 1 or 0)
# The second integer SHALL be interpreted as a little-endian version number. Nodes sending a sendcmpct message MUST currently set this value to 1.
# Upon receipt of a "sendcmpct" message with the first and second integers set to 1, the node SHOULD announce new blocks by sending a cmpctblock message.
# Upon receipt of a "sendcmpct" message with the first integer set to 0, the node SHOULD NOT announce new blocks by sending a cmpctblock message, but SHOULD announce new blocks by sending invs or headers, as defined by BIP130.
# Upon receipt of a "sendcmpct" message with the second integer set to something other than 1, nodes MUST treat the peer as if they had not received the message (as it indicates the peer will provide an unexpected encoding in cmpctblock, and/or other, messages). This allows future versions to send duplicate sendcmpct messages with different versions as a part of a version handshake for future versions. See Protocol Versioning section, below, for more info on the specifics of the version-negotiation mechanics.
# Nodes SHOULD check for a protocol version of >= 70014 before sending sendcmpct messages.
# Nodes MUST NOT send a request for a MSG_CMPCT_BLOCK object to a peer before having received a sendcmpct message from that peer.
# Nodes MUST NOT request a MSG_CMPCT_BLOCK object before having sent all sendcmpct messages to that peer which they intend to send, as the peer cannot know what version protocol to use in the response.
====MSG_CMPCT_BLOCK====
# getdata messages may now contain requests for MSG_CMPCT_BLOCK objects.
# Upon receipt of a getdata containing a request for a MSG_CMPCT_BLOCK object with the hash of a block which was recently announced and is close to the tip of the best chain of the receiver and after having sent the requesting peer a sendcmpct message, nodes MUST respond with a cmpctblock message containing appropriate data representing the block being requested.
# Upon receipt of a getdata containing a request for a MSG_CMPCT_BLOCK object for which a cmpctblock message is not sent in response, a block message containing the requested block in non-compact form MUST be sent.
# MSG_CMPCT_BLOCK inv objects MUST NOT appear anywhere except for in getdata messages.
====cmpctblock====
# The cmpctblock message is defined as a message containing a serialized HeaderAndShortIDs message and pchCommand == "cmpctblock".
# Upon receipt of a cmpctblock message after sending a sendcmpct message, nodes SHOULD calculate the short transaction ID for each unconfirmed transaction they have available (ie in their mempool) and compare each to each short transaction ID in the cmpctblock message.
# After finding already-available transactions, nodes which do not have all transactions available to reconstruct the full block SHOULD request the missing transactions using a getblocktxn message.
# A node MUST NOT send a cmpctblock message unless they are able to respond to a getblocktxn message which requests every transaction in the block.
# A node MUST NOT send a cmpctblock message without having validated that the header properly commits to each transaction in the block, and properly builds on top of the existing, fully-validated chain with a valid proof-of-work either as a part of the current most-work valid chain, or building directly on top of it. A node MAY send a cmpctblock before validating that each transaction in the block validly spends existing UTXO set entries.
====getblocktxn====
# The getblocktxn message is defined as a message containing a serialized BlockTransactionsRequest message and pchCommand == "getblocktxn".
# Upon receipt of a properly-formatted getblocktxn message, nodes which recently provided the sender of such a message a cmpctblock for the block hash identified in this message MUST respond with either an appropriate blocktxn message, or a full block message. A blocktxn response MUST contain exactly and only each transaction which is present in the appropriate block at the index specified in the getblocktxn indexes list, in the order requested.
====blocktxn====
# The blocktxn message is defined as a message containing a serialized BlockTransactions message and pchCommand == "blocktxn".
# Upon receipt of a properly-formatted requested blocktxn message, nodes SHOULD attempt to reconstruct the full block by:
## Taking the prefilledtxn transactions from the original cmpctblock and placing them in the marked positions.
## For each short transaction ID from the original cmpctblock, in order, find the corresponding transaction either from the blocktxn message or from other sources and place it in the first available position in the block.
# Once the block has been reconstructed, it shall be processed as normal, keeping in mind that short transaction IDs are expected to occasionally collide, and that nodes MUST NOT be penalized for such collisions, wherever they appear.
==Protocol Versioning==
# The protocol version negotiation allows two nodes to agree on the versions of compact blocks which they will exchange. As it is only in a single field, it does not allow a node to support a specific version in only one direction (sending or receiving).
# Upon connection establishment, a node SHOULD send a burst of sendcmpct messages containing every version of compact block encodings for which they are willing to support sending cmpctblock and blocktxn messages, and receiving getblocktxn messages. These messages SHOULD be ordered in the order of the priority which the node wishes to receive cmpctblock/blocktxn messages, with the highest-priority version sendcmpct message sent first.
# The encoding version used to send a cmpctblock or blocktxn message or to receive a getblocktxn message MUST be the second integer (version number) in the first sendcmpct message received for which a sendcmpct message with the same version number was sent.
# Nodes MUST NOT send a sendcmpct message which contains a version number other than the version number which has been negotiated for receiving cmpctblock/blocktxn messages after sending a request for a MSG_CMPCT_BLOCK object, sending a cmpctblock, getblocktxn, blocktxn, or pong message.
# As a node must send all sendcmpct messages which contain a novel version announcement before any other compact block-related messages, it is possible to determine which version of compact blocks will be used for each object received. It is, however, not possible to know which version will be used to encode the response to a request for a compact block object before any MSG_CMPCT_BLOCK-containing getdata, cmpctblock, getblocktxn, blocktxn, or ping/pong messages have been exchanged.
# Thus, if a node wishes to determine exactly which version of compact blocks will be used before requesting a compact block object, it must send all of its sendcmpct version announcements, followed by a ping, and wait for the pong response to ensure it has received all sendcmpctblock version announcement messages from the remote peer. Nodes can, obviously, however, determine that the version used will be at least a certain version (in their priority order) after having received a sendcmpct message from the remote peer containing that version as the second integer.
===Sample Version Implementation===
# By way of example, an implementation of the above protocol might look like the following.
# Upon exchanging version/verack messages, a node immediately sends its list of sendcmpct announcements to the other side, with the version which it wants to receive sent first.
# Upon receiving the first sendcmpct announcement with a protocol version which is understood from the remote peer, a node will "lock in" the compact block encoding version which will be used to encode compact blocks to that peer.
# The node then sets the current receive-protocol-version in use on the connection to that version, and uses it to decode new compact block messages.
# Upon receiving subsequent sendcmpct announcements with a protocol version which is understood from the remote peer (ie a version which has been announced using a sendcmpct in the other direction), a node will check if that protocol version is higher-receive-priority than the current receive-protocol-version in use on the connection, and switch to that version for decoding new compact block messages received.
# A node might wish to keep a flag for each peer which indicates compact block version negotiation is complete, which can be set upon receiving any compact block-related, or pong message.
# The above implementation requires only a compile-time list of supported versions in some static priority order, two version fields per peer, and an optional negotiation-complete boolean per-peer.
==Specification for version 2==
Compact blocks version 2 is almost identical to version 1, but supports segregated witness transactions (BIP 141 and BIP 144). The changes are:
# The second integer (version number) inside sendcmpct is 2 instead of 1 (see Protocol Versioning section, above).
# Transactions inside cmpctblock messages (both those used as direct announcement and those in response to getdata) and in blocktxn should include witness data, using the same format as responses to getdata MSG_WITNESS_TX, specified in BIP144.
# Short transaction IDs sent to us in cmpctblock messages, and sent by us in getblocktxn messages, are computed using the same process as in version 1, but using the wtxid as defined in BIP 141 instead of the txid. Note that, though a node normally SHOULD, if a node does not include (ie must then include the short ID for) the coinbase transaction, it must be computed by encoding the transaction in witness format as defined by BIP 141.
# Upon receipt of a getdata containing a request for a MSG_CMPCT_BLOCK object for which a cmpctblock message is not sent in response, the block message containing the requested block in non-compact form MUST be encoded with witnesses (as is sent in reply to a MSG_WITNESS_BLOCK getdata) if the protocol version used to encode the cmpctblock message would have been 2, and encoded without witnesses (as is sent in response to a MSG_BLOCK getdata) if the protocol version used to encode the cmpctblock message would have been 1.
==Implementation Notes==
# For nodes which have sufficient inbound bandwidth, sending a sendcmpct message with the first integer set to 1 to up to 3 peers is RECOMMENDED. If possible, it is RECOMMENDED that those peers be selected based on their past performance in providing blocks quickly (eg the three peers which provided the highest number of the recent N blocks the quickest), allowing nodes to receive blocks which come from those peers in only 0.5*RTT.
# Nodes MUST NOT send such sendcmpct messages to more than three peers, as it encourages wasting outbound bandwidth across the network.
# All nodes SHOULD send a sendcmpct message to all appropriate peers. This will reduce their outbound bandwidth usage by allowing their peers to request compact blocks instead of full blocks.
# Nodes with limited inbound bandwidth SHOULD request blocks using MSG_CMPCT_BLOCK/getblocktxn requests, when possible. While this increases worst-case message round-trips, it is expected to reduce overall transfer latency as TCP is more likely to exhibit poor throughput on low-bandwidth nodes.
# Nodes sending cmpctblock messages SHOULD limit prefilledtxn to 10KB of transactions. When in doubt, nodes SHOULD only include the coinbase transaction in prefilledtxn.
# Nodes MAY pick one nonce per block they wish to send, and only build a cmpctblock message once for all peers which they wish to send a given block to. Nodes SHOULD NOT use the same nonce across multiple different blocks.
# Nodes MAY impose additional requirements on when they announce new blocks by sending cmpctblock messages. For example, nodes with limited outbound bandwidth MAY choose to announce new blocks using inv/header messages (as per BIP130) to conserve outbound bandwidth.
# Note that the MSG_CMPCT_BLOCK section does not require that nodes respond to MSG_CMPCT_BLOCK getdata requests for blocks which they did not recently announce. This allows nodes to calculate cmpctblock messages at announce-time instead of at request-time. Blocks which are requested with a MSG_CMPCT_BLOCK getdata, but which are not responded to with a cmpctblock message MUST be responded to with a block message, allowing nodes to request all blocks using MSG_CMPCT_BLOCK getdatas and rely on their peer to pick an appropriate response.
# While the current version sends transactions with the same encodings as are used in tx messages and elsewhere in the protocol, the version field in sendcmpct is intended to allow this to change in the future. For this reason, it is recommended that the code used to decode PrefilledTransaction and BlockTransactions messages be prepared to take a different transaction encoding, if and when the version field in sendcmpct changes in a future BIP.
# Any undefined behavior in this spec may cause failure to transfer block to, peer disconnection by, or self-destruction by the receiving node. A node receiving non-minimally-encoded CompactSize encodings should make a best-effort to eat the sender's cat.
===Pre-Validation Relay and Consistency Considerations===
# As high-bandwidth mode permits relaying of CMPCTBLOCK messages prior to full validation (requiring only that the block header is valid before relay), nodes SHOULD NOT ban a peer for announcing a new block with a CMPCTBLOCK message that is invalid, but has a valid header. For avoidance of doubt, nodes SHOULD bump their peer-to-peer protocol version to 70015 or higher to signal that they will not ban or punish a peer for announcing compact blocks prior to full validation, and nodes SHOULD NOT announce a CMPCTBLOCK to a peer with a version number below 70015 before fully validating the block.
# SPV nodes which implement this spec must consider the implications of accepting blocks which were not validated by the node which provided them. Especially SPV nodes which allow users to select a "trusted full node" to sync from may wish to avoid implementing this spec in high-bandwidth mode.
# Note that this spec does not change the requirement that nodes only relay information about blocks which they have fully validated in response to GETDATA/GETHEADERS/GETBLOCKS/etc requests. Nodes which announce using CMPCTBLOCK message and then receive a request for associated block data SHOULD ensure that messages do not go unresponded to, and that the appropriate data is provided after the block has been validated, subject to standard message-response ordering requirements. Note that no requirement is added that the node respond to the request with the new block included in eg GETHEADERS or GETBLOCKS messages, but the node SHOULD re-announce the block using the associated announcement methods after validation has completed if it is not included in the original response. On the other hand, nodes SHOULD delay responding to GETDATA requests for the block until validation has completed, stalling all message processing for the associated peer. REJECT messages are not considered "responses" for the purpose of this section.
# As a result of the above requirements, implementers may wish to consider the potential for the introduction of delays in responses while remote peers validate blocks, avoiding delay-causing requests where possible.
==Justification==
====Protocol design====
There have been many proposals to save wire bytes when relaying blocks. Many of them have a two-fold goal of reducing block relay time and thus rely on the use of significant processing power in order to avoid introducing additional worst-case RTTs. Because this work is not focused primarily on reducing block relay time, its design is much simpler (ie does not rely on set reconciliation protocols). Still, in testing at the time of writing, nodes are able to relay blocks without the extra getblocktxn/blocktxn RTT around 90% of the time. With a smart compact-block-announcement policy, it is thus expected that this work might allow blocks to be relayed between nodes in 0.5*RTT instead of 1.5*RTT at least 75% of the time.
====Short transaction ID calculation====
There are several design goals for the Short ID calculation:
* '''Performance''' The sender needs to compute short IDs for all block transactions, and the receiver for all mempool transactions they are being compared to. As we're easily talking about several thousand transactions, sub-microsecond processing per-transactions is needed.
* '''Space''' cmpctblock messages are never optional in this protocol, and contain a short ID for each non-prefilled transaction in the block. Thus, the size of short IDs is directly proportional to the maximum bandwidth savings possible.
* '''Collision resistance''' It should be hard for network participants to create transactions that cause collisions. If an attacker were able to cause such collisions, filling mempools (and, thus, blocks) with them would cause poor network propagation of new (or non-attacker, in the case of a miner) blocks.
SipHash is a secure, fast, and simple 64-bit MAC designed for network traffic authentication and collision-resistant hash tables. We truncate the output from SipHash-2-4 to 48 bits (see next section) in order to minimize space. The resulting 48-bit hash is certainly not large enough to avoid intentionally created individual collisions, but by using the block hash as a key to SipHash, an attacker cannot predict what keys will be used once their transactions are actually included in a relayed block. We mix in a per-connection 64-bit nonce to obtain independent short IDs on every connection, so that even block creators cannot control where collisions occur, and random collisions only ever affect a small number of connections at any given time. The mixing is done using SHA256(block_header || nonce), which is slow compared to SipHash, but only done once per block. It also adds the ability for nodes to choose the nonce in a better than random way to minimize collisions, though that is not necessary for correct behaviour. Conversely, nodes can also abuse this ability to increase their ability to introduce collisions in the blocks they relay themselves. However, they can already cause more problems by simply refusing to relay blocks. That is inevitable, and this design only seeks to prevent network-wide misbehavior.
====Random collision probability====
Thanks to the block-header-based SipHash keys, we can assume that the only collisions on links between honest nodes are random ones.
For each of the ''t'' block transactions, the receiver will compare its received short ID with that of a set of ''m'' mempool transactions. We assume that each of those ''t'' has a chance ''r'' to be included in that set of ''m''. If we use ''B'' bits short IDs, for each comparison between a received short ID and a mempool transaction, there is a chance of ''P = 1 - 1 / 2^B'' that a mismatch is detected as such.
When comparing a given block transaction to the whole set of mempool transactions, there are 5 cases to distinguish:
# The receiver has exactly one match, which is the correct one. This has chance ''r * P^(m - 1)''.
# The receiver has no matches. This has chance ''(1 - r) * P^m''.
# The receiver has at least two matches, one of which is correct. This has chance ''r * (1 - P^(m - 1))''.
# The receiver has at least two matches, both of which are incorrect. This has chance ''(1 - r) * (1 - P^m - m * (1 - P) * P^(m - 1))''.
# The receiver has exactly one match, but an incorrect one. This has chance ''(1 - r) * m * (1 - P) * P^(m - 1)''.
(note that these 5 numbers always add up to 100%)
In case 1, we're good. In cases 2, 3, or 4, we request the full transaction because we know we're uncertain. Only in case 5, we fail to reconstruct. The chance that case 5 does not occur in any of the ''t'' transactions in a block is ''(1 - (1 - r) * m * (1 - P) * P^(m - 1))^t''. This expression is well approximated by ''1 - (1 - r) * m * (1 - P) * t'' = ''1 - (1 - r) * m * t / 2^B''. Thus, if we want only one in F block transmissions between honest nodes to fail under the conservative ''r = 0'' assumption, we need ''log2(F * m * t)'' bits hash functions.
This means that ''B = 48'' bits short IDs suffice for blocks with up to ''t = 10000'' transactions, mempools up to ''m = 100000'' transactions, with failure to reconstruct at most one in ''F = 281474'' blocks. Since failure to reconstruct just means we fall back to normal inv/header based relay, it isn't necessary to avoid such failure completely. It just needs to be sufficiently rare they have a lower impact than random transmission failures (for example, network disconnection, node overloaded, ...).
====Separate version for segregated witness====
The changes to transaction and block relay in BIP 144 introduce separate MSG_FILTERED_ versions of messages in getdata,
allowing a receiver to choose individually where witness data is wanted.
This method is not useful for compact blocks because `cmpctblock` blocks can be sent unsolicitedly in high-bandwidth
mode, so we need to negotiate at least whether those should include witness data up front. There is little use for a
validating node that only sometimes processes witness data, so we may as well use that negotiation for everything and
turn it into a separate protocol version. We also need a means to distinguish different versions of the same transaction
with different witnesses for correct reconstruction, so this also forces us to use wtxids instead of txids for short IDs
everywhere in that case.
==Backward compatibility==
Older clients remain fully compatible and interoperable after this change.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/8068 for version 1.
https://github.com/bitcoin/bitcoin/pull/8393 for version 2.
==Acknowledgements==
Thanks to Gregory Maxwell for the initial suggestion as well as a lot of back-and-forth design and significant testing.
Thanks to Nicolas Dorier for the protocol flow diagram.
==Copyright==
This document is placed in the public domain.
================================================
FILE: bip-0154.mediawiki
================================================
==Abstract==
An anti-DoS system which provides additional service for peers which perform proof of work.
==Definitions==
* '''POW''' : a proof of work using some arbitrary algorithm, such as SHA256
* '''challenge''' : a problem in the form of a POW specification and other data
* '''solution''' : a set of inputs which solve a given challenge
* '''free connection slot''' : an inbound connection slot that does not require POW
* '''POW connection slot''' : an inbound connection slot that requires POW
* '''SPH''' : Special Purpose Hardware, such as an ASIC chip
* '''GPH''' : General Purpose Hardware, such as a desktop computer
* '''Work''' : A measurement of optimized average resources (clock cycles, memory, ...) required to perform a single attempt at solving a given POW algorithm on GPH
==Motivation==
The Bitcoin network has a maximum number of inbound and outbound connections (125).
It is trivial and relatively cheap to flood the network with connections via dummy
nodes. Such an attack would result in (1) nodes evicting some other nodes in order to
facilitate the new connection, and (2) nodes' ability to connect to each other being
severely hampered. In this state, the network is vulnerable to e.g. a Sybil attack.
While the network is under pressure as in the above case, nodes could allow incoming
connections anyway by requiring that the incoming peer performs some form of proof
of work, to prove that they are not simply spamming the network. This would severely
ramp up the costs of a Sybil attack, as the attacker would now have to perform proof
of work for each node, beyond the free slots.
However, using the "standard" double-SHA256 POW algorithm in use by Bitcoin nodes to
generate blocks means attackers can use special-purpose hardware to greatly accelerate
the POW solving process. To counter this, the proof weight would have to be raised,
but this would mean standard nodes would need to solve unacceptably costly challenges
for simple operation. Therefore, a different proof of work which is arguably less
sensitive to special-purpose hardware implementations is introduced. As this is not
consensus sensitive, additional POW algorithms may be added in the future.
==Specification==
A peer that supports Proof of Work Rate Limiting defines two maximums:
* max connections, from which the maximum inbound connections is calculated as nMaxConnections - (nMaxOutbound + nMaxFeeler)
* POW connection slots, which define how many of the above inbound connections require a POW challenge
The peer must interpret two new network peer message types, challenge and solution.
In addition, the network handshake sequence must be altered slightly to facilitate the exchange of challenges and/or solutions:
* when a node connects, it may send a solution message prior to the version
* if it does, and
** the solution satisfies the local node, it is given a connection, but if
** the solution does not satisfy the local node (unknown, wrong, ...), a new challenge is sent and the connection is closed
* if it does not, and it is marked as needing to do POW, a challenge is sent and the connection is closed
This means nodes will be disconnected after receiving the challenge. It is then up to the individual nodes whether they
solve the challenge and reconnect, or discard it and find a different peer (or wait for the peer to have an open free slot).
===POW Identifiers===
There are two POW identifiers currently. When a new identifier is introduced, it should be added with an increment of 1
to the last identifier in the list. When an identifier is deprecated, its status should be changed to Deprecated but it should
retain its place in the list indefinitely.
{|class="wikitable"
! ID !! Algorithm Name !! Work !! Param size !! Solution size !! Provably Secure !! SPH Resistance !! Status
|-
| 1 || sha256 || 11k cycles || 11+ bytes || 0, 4 or 8 bytes || Yes || Low || Active
|-
| 2 || cuckoo-cycle || ss 28: 150G cycles / ~48M RAM || 6+ bytes || 168 bytes || No || High || Active
|}
====sha256====
Properties:
{|class="wikitable"
! Property !! Value
|-
| Solution probability || sum((1/2)^i*(1-targetBE[i]))
|}
Challenge format:
{|class="wikitable"
! Range !! Field Name !! Data Type !! Description
|-
| 0 || config_length || varint || Length of configuration part; always 9
|-
| 1..4 || target || uint32 || Difficulty target, in the form of a compact size (like nBits in blocks).
|-
| 5 || nonce_size || uint8 || Size of nonce in bytes; must be 0 (no nonce), 4 (uint32) or 8 (uint64)
|-
| 6..9 || nonce_offset || uint32 || Location of nonce value in target
|-
| 10.. || payload_length || varint || Length of the input data
|-
| .. || payload || byte array || Input data
|}
Solution format:
{|class="wikitable"
! Range !! Field Name !! Data Type !! Description
|-
| 0.. || nonce || uint32/64, or data || Nonce value that satisfies challenge; for zero-byte nonces, this is variable data that is appended to the challenge payload before hashing
|}
Note: SHA256 works in two "modes".
# One is where the task is to insert a nonce into an existing data block so that the hash of the data block matches a given target; this is the conventional block proof of work behavior.
# The other is where the whole or parts of the data chunk are given as input (a "big nonce"). In this case, the internal nonce size is zero bytes, and the task is simply to check whether the hash of the data matches the target. If it does not, there is no way to find a solution except by getting different input from the generator (a successor algorithm). This mode is used when SHA256 is a predecessor to another algorithm.
Additional notes:
* The initial nonce value (when present) for finding a suitable digest should be randomized, or a challenger may deliberately pick a challenge with "poor" outcomes to fool a node into spending more than predicted time solving.
====cuckoo-cycle====
Properties:
{|class="wikitable"
! Property !! Value
|-
| Solution probability || ~1.0 for sizeshift=28, proofsize-min:-max=12:228
|}
Challenge format:
{|class="wikitable"
! Range !! Field Name !! Data Type !! Description
|-
| 0 || config_length || varint || Length of configuration part; always 5
|-
| 1 || sizeshift || uint8 || Size shift; must be equal to 28, but may be variable in the future
|-
| 2..3 || proofsize-min || uint16 || Minimum number of edges in cycle; must be even and greater than or equal to 12 (recommended: 12)
|-
| 4..5 || proofsize-max || uint16 || Maximum number of edges in cycle; must be even, greater than or equal to proofsize-min, and smaller than or equal to 254 (recommended: 228)
|-
| 6 || payload_length || varint || Length of the input data; must be 76, but may be variable in the future
|-
| 7.. || payload || byte array || Input data
|}
Solution format:
{|class="wikitable"
! Range !! Field Name !! Data Type !! Description
|-
| 0..3 || nonce || uint32 || Nonce which is appended to challenge payload to form solution graph
|-
| 4..171 || edges || uint32 array || 42 values which identify each of the 42 edges in the cycle
|}
Additional notes:
* The initial nonce value used for finding a graph with a suitable solution should be randomized, or a challenger may deliberately pick a challenge with "poor" outcomes to fool a node into spending more than predicted time solving.
* Further information on the recommended challenge parameters can be found here: https://web.archive.org/web/20230207054058/http://bc-2.jp/cuckoo-profile.pdf
===Purpose Identifiers===
There is only one Purpose Identifier currently. In the future, more Purpose Identifiers could be added for at-DoS-risk operations,
such as bloom filters. When a new identifier is introduced, it should be added with an increment of 1 to the last identifier in the
list. When an identifier is deprecated, its status should be changed to Deprecated but it should retain its place in
the list indefinitely.
{|class="wikitable"
! ID !! Purpose Name !! Description !! Status
|-
| 1 || connect || Establish peer to peer connection || Active
|}
===Challenges===
Challenges consist of one or several chained POW identifiers with accompanying parameters, as well as indicators for the purpose of the challenge,
and a signature that lets the node verify the challenge authenticity.
After creating a challenge, the node signs it, delivers it to the peer, then discards it.
When a node provides a solution to a challenge, the node verifies the signature and adds the challenge hash to a list of solved
challenges along with its expiration time. This list is pruned on each insertion, removing any expired challenges.
If nodes needed to keep track of unsolved challenges, an attacker could hypothetically swarm a node, causing a DoS by having it generate so many
challenges that it runs out of memory and crashes.
By signing and discarding challenges, a node only has to retain challenges that were solved, and which have not yet expired, effectively DoS-
protecting the node via the challenges themselves.
===The challenge message type===
A challenge consists of four parts: the POW specification, a purpose identifier, an expiration date, and a signature.
The POW specification contains a list of tuples containing a POW identifier and corresponding POW parameters.
* Each POW identifier specifies a POW algorithm (see POW Identifiers)
* The POW parameters define the inputs and requirements of the POW algorithm
* The purpose identifier specifies the purpose of the challenge (see Purpose Identifiers)
* The expiration date is a UNIX timestamp indicating when the challenge expires
* The signed content should contain a signature of the hash SHA256(SHA256(pow-count || pow-id || pow-params || ... || purpose-id || expiration)), i.e. the hash of the entire challenge except for the signature length and data.
{|class="wikitable"
! Field Size !! Description !! Data type !! Description
|-
| 1 byte || pow-count || uint8 || Number of POW algorithms in the range [1..255]
|-
| 4 bytes || pow-id || uint32 || The POW algorithm to solve the problem with
|-
| ? || pow-params || ? || The POW parameters and payload
|-
| ... || ... || ... || pow-id and pow-params for algorithms 2 and beyond
|-
| 4 bytes || purpose-id || uint32 || The purpose of the challenge
|-
| 8 bytes || expiration || int64 || Expiration UNIX timestamp
|-
| ? || sign-len || varint || The length of the signature
|-
| ? || sign || byte array || The signature data
|}
For POW specifications with a pow-count > 1, the output of the succeeding POW algorithm will be appended to the input of the predecessor for all POW algorithms except the last one.
Normally mid-layer (all but the last) POW algorithms have a zero-length input. Example implementing sha256(cuckoo-cycle):
{|class="wikitable"
! Range !! Field Name !! Value !! Comment
|-
| 0 || pow-count || 2 || Two POW algorithms
|-
| 1..4 || pow-id || 1 || sha256
|-
| 5 || pow-params (config_length) || 9 ||
|-
| 6..9 || pow-params (target) || 0x207fffff || Resulting hash must be <= the compact hash 0x207fffff*
|-
| 10 || pow-params (nonce_size) || 0 || No nonce
|-
| 11..14 || pow-params (nonce_offset) || 0 || --
|-
| 15..18 || pow-params (payload_length) || 0 || 0 byte input (turns into 32 byte input from successor)
|-
| 19..22 || pow-id || 2 || cuckoo-cycle
|-
| 23 || pow-params (config_length) || 8 ||
|-
| 24 || pow-params (sizeshift) || 28
|-
| 25..26 || pow-params (proofsize-min) || 12 ||
|-
| 27..28 || pow-params (proofsize-max) || 228 ||
|-
| 29 || pow-params (payload_length) || 76 || 76 byte input
|-
| 30..105 || pow-params || (random data) || A randomized challenge of 76 bytes
|-
| 106..109 || purpose-id || 1 || Purpose is a peer-to-peer connection
|-
| 110..117 || expiration || 1491285696 || Expiration is April 4 2017, 15:01:36 (JST)
|-
| 118 || sign-len || 71 || 71 byte signature
|-
| 119..189 || sign || (signature) || Signature of above challenge
|}
(* Compact 0x207fffff = 0x7fffff0000000000000000000000000000000000000000000000000000000000.)
The above should be interpreted as SHA256(cuckoo-cycle(random data || nonce)) < 0x7fffff0000000000000000000000000000000000000000000000000000000000.
* Run cuckoo-cycle on random data || nonce; increment nonce until solution is found, then
** Run SHA256 on 32 byte digest from above; if less than 0x7fffff0000000000000000000000000000000000000000000000000000000000,
*** Mark solved.
* Otherwise loop back and increase nonce and continue finding solutions
===The solution message type===
A solution consists of two parts: the entire challenge, and solution parameters:
* The challenge must match the given challenge up to and including the signature bytes
* The solution parameters must form a valid solution to each POW step in the challenge
{|class="wikitable"
! Field Size !! Description !! Data type !! Description
|-
| 1 byte || pow-count || uint8 || Number of POW algorithms in the range [1..255]
|-
| 4 bytes || pow-id || uint32 || The POW algorithm used to solve the problem
|-
| ? || pow-params || ? || The input to the POW solver for the above algorithm
|-
| ... || ... || ... || pow-id and pow-params for algorithms 2 and beyond
|-
| 4 bytes || purpose-id || uint32 || The purpose of the challenge
|-
| 8 bytes || expiration || int64 || Expiration UNIX timestamp
|-
| ? || sign-len || varint || The length of the signature
|-
| ? || sign || byte array || The signature data
|-
| ? || solution || ? || The solution to the challenge
|}
Note that the solution contains the parameters for the last algorithm only.
For each algorithm except the last one, the input is derived from the output of the successor.
Example solution:
{|class="wikitable"
! Range !! Name !! Value !! Description
|-
| 0 || length || 4 || The input to the innermost POW is 4 bytes in length
|-
| 1..4 || nonce32 || 0x12345 || The nonce used as input is 0x12345
|}
The above example will provide a single nonce for the inner POW. For the SHA256(SHA256(challenge data || nonce32)) case, the solution would
claim that SHA256(SHA256(challenge data || 0x00012345)) solves the challenge.
==Signing and Verifying Challenges==
Below is a suggestion for how to sign a challenge. The implementation generates a new, random key-pair at launch and uses that
to sign all challenges until the node is shutdown.
===Signing a Challenge===
# (first time) Create a new random key-pair key and pubkey and keep these around until shutdown
# (second+ time) Fetch key created above
# Create a double-SHA256 sighash of the challenge in serialized form up until and including the expiration bytes
# Create a signature sign of sighash using key
# Append varint(len(sign)) and sign to challenge
===Verifying a Challenge===
# Fetch pubkey and declare failure if not defined (that means we never issued a challenge)
# Create a double-SHA256 sighash of the challenge provided with the solution up until and including the expiration bytes
# Verify sighash is not known, and add it to known hashes along with its expiration date for pruning purposes
# Set sign to the signature included in the challenge
# Verify the signature sign using pubkey and sighash
# Check that the solution solves the challenge
Note that a list of known hashes should be kept and pruned of expired challenges on verification. Otherwise nodes may reuse the same
solution repeatedly up until its expiration.
==Difficulty and Cost==
===Estimating Challenge Cost===
Nodes need to be able to make a judgement call on whether solving a given challenge is worth their efforts. If a challenge is expected to take
so much time that it would expire before being solved (on average), it should be immediately discarded. Beyond this, a threshold should be
established for nodes based on their "value" to the node, which is inversely proportional to the current number of connections as a function
of uptime, with arbitrary modifiers (a whitelisted node or a node added via -addnode has a much higher threshold).
It is hard to obtain an accurate value for cycles_per_second, and as such a fixed value of 1700000000=1.7e9 may be used.
Given a threshold t, calculate the estimated work required to solve the challenge as follows:
# Define p(alg) as the probability that an attempt at finding a solution given the algorithm alg succeeds
# Define w(alg) as the work parameter of the algorithm alg.
# Let Wc ← 0, Wm ← 1, Wi ← 1
# For each proof of work pow in the POW specification:
## Let p ← p(pow), w ← w(pow)
## Update Wc ← Wc + w_cycles, Wi ← Wi * 1/p, Wm ← Wm + w_ram
# Let eta ← (Wc * Wi) / cycles_per_second
# If date() + eta >= expiration, discard challenge
# If eta > t, discard challenge
Example: SHA256(cuckoo-cycle(...)) < 0x7fffff0000000000000000000000000000000000000000000000000000000000
# p(cuckoo-cycle) = 1, p(sha256, 0x7fffff000...) ~= (1/2)^1 = 1/2
# w(cuckoo-cycle) = (1.5e11 cycles, 5e7 ram), w(sha256, 0x7fffff000...) = (11e3 cycles)
# Wc = 0, Wm = 1, Wi = 1
## p = p(cuckoo-cycle) = 1, w = w(cuckoo-cycle) = (1.5e11 cycles, 5e7 ram)
## Wc = 0 + 1.5e11 = 1.5e11, Wi = 1 * 1 = 1, Wm = 1 + 5e7 = 5e7
## p = p(sha256) = 1/2, w = w(sha256) = (11e3 cycles)
## Wc = 1.5e11 + 11e3 ~= 1.5e11, Wi = 1 * 2 = 2, Wm = 5e7 + 0 = 5e7
# eta = (1.5e11 * 2) / cycles_per_second = 7.5e10 / 1.7e9 = 44.1 seconds
TODO: Determine how memory impacts threshold.
To avoid other nodes dropping our challenges due to early expiration, we use a fairly generous expiration based on the pressure value
expiration = date() + 600 * (1 + pressure)
which means the expiration is 10 minutes for the weakest challenge, and gradually rises to 20 minutes for the hardest one.
===Establishing Difficulty Parameters===
The difficulty setting for the network should change based on connection slot availability. The amount of pressure
on the network in the sense of connection slot availability is proportional to the number of established connections
over the number of total available connections. This can be locally approximated by a node to the number of
local connections compared to the local connection maximum.
In other words, the network pressure can be approximated by any node as connections / max and the difficulty
can be based on e.g. (connections - free) / pow_slots.
The challenge difficulty parameters can be set based on this, where 0.0 means "low pressure" and 1.0 means
"maximum pressure". The GetPressure method below gives 0.0 at 67 connections (for a 50 POW slot set up), and hits the 1.0 mark at (nMaxConnections - nMaxOutbound - nMaxFeeler), incrementing by 0.02 for each new connection:
An example of difficulty for a SHA256(Cuckoo-Cycle) specification would be based on a desired probability of a random SHA256 digest matching a given target:
prob_target = 1 / (1 + pressure^2 * 15)
This would result in probability targets according to the table below, for varying pressures (where the pressure is in the range [0..1]):
{|class="wikitable"
! pressure !! prob_target !! solution time sha256(cc)
|-
| 0.0 || 1.00 || 00:45
|-
| 0.1 || 0.87 || 00:51
|-
| 0.2 || 0.63 || 01:11
|-
| 0.3 || 0.43 || 01:45
|-
| 0.4 || 0.29 || 02:32
|-
| 0.5 || 0.21 || 03:32
|-
| 0.6 || 0.16 || 04:46
|-
| 0.7 || 0.12 || 06:13
|-
| 0.8 || 0.09 || 07:54
|-
| 0.9 || 0.08 || 09:48
|-
| 1.0 || 0.06 || 11:55
|-
|}
==Cuckoo Cycle==
Cuckoo Cycle[1] is a "graph-theoretic proof-of-work system, based on finding small cycles or other structures in large random graphs."
It is memory hard, which greatly increases the complexity and cost of producing dedicated (special purpose) hardware, an ideal property for an anti-DoS system.
The implementation specifics of the algorithm are beyond the scope of this BIP, but the github repository[2] has several reference implementations in various languages.
==Compatibility==
This proposal is backward compatible. Non-supporting peers will ignore the challenge message
and be disconnected, as if they hit the peer connection limit as normal.
==Reference implementation==
https://github.com/kallewoof/bitcoin/pull/2 (https://github.com/kallewoof/bitcoin/tree/pow-connection-slots)
==References==
* [1] Cuckoo Cycle https://github.com/tromp/cuckoo/blob/master/doc/cuckoo.pdf?raw=true
* [2] Cuckoo Cycle github https://github.com/tromp/cuckoo
==Test vectors==
===Cuckoo-Cycle===
Cuckoo Cycle header (76 bytes):
SHA256 hash: 262c8558c7c589b19b3d513abf5fcb15162745473e603f0146889ceff750bcc3
Must be less than: 5fffff0000000000000000000000000000000000000000000000000000000000
===Serialized challenge example===
SHA256 hash: 08210561257e26776135ec1cb92cfe17f46803613c0bdc02043e5545b18556ce
Must be less than: 21642c0000000000000000000000000000000000000000000000000000000000
===Serialized challenge example===
Note that the first 186 bytes are identical to the challenge above.
{|class="wikitable"
! Hex !! Description
|-
| 0x0201..f577 || Challenge
|-
| 0x5c || Solution is 92 bytes long
|-
| 0x04000000 || The cuckoo cycle nonce is 4
|-
| 0x5a0137007074ce00e3dbeb00e88f7901 || Cycle edges 0..3
|-
| 0x06d71d02984d3d02091b5002378a8e02 || Cycle edges 4..7
|-
| 0x90a6d202b3c67003757cb70344d9cf03 || Cycle edges 8..11
|-
| 0x297f20048e76a60467e44a057b077405 || Cycle edges 12..15
|-
| 0x634f840523e88c050d887606109d3e07 || Cycle edges 16..19
|-
| 0xc4bdcd073db2d407 || Cycle edges 20..21
|}
==Copyright==
This BIP is licensed under the BSD 2-clause license.
================================================
FILE: bip-0155.mediawiki
================================================
BIP: 155
Layer: Peer Services
Title: addrv2 message
Authors: Wladimir J. van der Laan
Status: Deployed
Type: Specification
Assigned: 2019-02-27
License: BSD-2-Clause
Version: 2.0.0
==Introduction==
===Abstract===
This document proposes a new P2P message to gossip longer node addresses over the P2P network.
This is required to support new-generation Onion addresses, I2P, and potentially other networks
that have longer endpoint addresses than fit in the 128 bits of the current addr message.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
Tor v3 hidden services are part of the stable release of Tor since version 0.3.2.9. They have
various advantages compared to the old hidden services, among which are better encryption and privacy
[https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt Tor Rendezvous Specification - Version 3].
These services have 256 bit addresses and thus do not fit in the existing addr message, which encapsulates onion addresses in OnionCat IPv6 addresses.
Other transport-layer protocols such as I2P have always used longer
addresses. This change would make it possible to gossip such addresses over the
P2P network, so that other peers can connect to them.
==Specification==
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in RFC 2119[https://tools.ietf.org/html/rfc2119 RFC 2119].
The addrv2 message is defined as a message where pchCommand == "addrv2".
It is serialized in the standard encoding for P2P messages.
Its format is similar to the current addr message format, with the difference that the
fixed 16-byte IP address is replaced by a network ID and a variable-length address, and the services format has been changed to [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer CompactSize].
This means that the message contains a serialized std::vector of the following structure:
{| class="wikitable" style="width: auto; text-align: center; font-size: smaller; table-layout: fixed;"
!Type
!Name
!Description
|-
| uint32_t
| time
| Time that this node was last seen as connected to the network. A time in Unix epoch time format.
|-
| CompactSize
| services
| Service bits. A bit field that is 64 bits wide, encoded in [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer CompactSize].
|-
| uint8_t
| networkID
| Network identifier. An 8-bit value that specifies which network is addressed.
|-
| std::vector
| addr
| Network address. The interpretation depends on networkID.
|-
| uint16_t
| port
| Network port. If not relevant for the network this MUST be 0.
|}
One message can contain up to 1,000 addresses. Clients SHOULD reject messages with more addresses.
Field addr has a variable length, with a maximum of 512 bytes (4096 bits).
Clients SHOULD reject messages with longer addresses, irrespective of the network ID.
The list of reserved network IDs is as follows:
{| class="wikitable" style="width: auto; text-align: center; font-size: smaller; table-layout: fixed;"
!Network ID
!Enumeration
!Address length (bytes)
!Description
|-
| 0x01
| IPV4
| 4
| IPv4 address (globally routed internet)
|-
| 0x02
| IPV6
| 16
| IPv6 address (globally routed internet)
|-
| 0x03
| TORV2
| 10
| Tor v2 hidden service address (no longer usedTor v2 is no longer operational; clients MUST NOT gossip or relay Tor v2 addresses and MUST ignore them on receive)
|-
| 0x04
| TORV3
| 32
| Tor v3 hidden service address
|-
| 0x05
| I2P
| 32
| I2P overlay network address
|-
| 0x06
| CJDNS
| 16
| Cjdns overlay network address
|-
| 0x07
| YGGDRASIL
| 16
| Yggdrasil overlay network address
|}
Clients are RECOMMENDED to gossip addresses from all known networks even if they are currently not connected to some of them. That could help multi-homed nodes and make it more difficult for an observer to tell which networks a node is connected to.
Clients SHOULD NOT gossip addresses from unknown networks because they have no means to validate those addresses and so can be tricked to gossip invalid addresses.
Further network ID numbers MUST be reserved in a new BIP document.
Clients SHOULD reject messages that contain addresses that have a different length than specified in this table for a specific network ID, as these are meaningless.
See the appendices for the address encodings to be used for the various networks.
==Signaling support and compatibility==
Introduce a new message type sendaddrv2. Sending such a message indicates that a node can understand and prefers to receive addrv2 messages instead of addr messages. I.e. "Send me addrv2". Sending or not sending this message does not imply any preference with respect to receiving unrequested address messages.
The sendaddrv2 message MUST only be sent in response to the version message from a peer and prior to sending the verack message.
For older peers, that did not emit sendaddrv2, keep sending the legacy addr message, ignoring addresses with the newly introduced address types.
==Reference implementation==
The reference implementation is available at (to be done)
==Acknowledgements==
- Jonas Schnelli: change services field to [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer CompactSize], to make the message more compact in the likely case instead of always using 8 bytes.
- Gregory Maxwell: various suggestions regarding extensibility
==Appendix A: Tor v2 address encoding (no longer used )==
The new message introduces a separate network ID for TORV2.
Clients MUST send Tor hidden service addresses with this network ID, with the 80-bit hidden service ID in the address field. This is the same as the representation in the legacy addr message, minus the 6 byte prefix of the OnionCat wrapping.
Clients SHOULD ignore OnionCat (fd87:d87e:eb43::/48) addresses on receive if they come with the IPV6 network ID.
==Appendix B: Tor v3 address encoding==
According to the spec [https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt Tor Rendezvous Specification - Version 3: Encoding onion addresses], next-gen .onion addresses are encoded as follows:
onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
where:
- PUBKEY is the 32 bytes ed25519 master pubkey of the hidden service
- VERSION is a one byte version field (default value '\x03')
- ".onion checksum" is a constant string
- CHECKSUM is truncated to two bytes before inserting it in onion_address
- H() is the SHA3-256 cryptographic hash function
Tor v3 addresses MUST be sent with the TORV3 network ID, with the 32-byte PUBKEY part in the address field. As VERSION will always be '\x03' in the case of v3 addresses, this is enough to reconstruct the onion address.
==Appendix C: I2P address encoding==
Like Tor, I2P naming uses a base32-encoded address format[https://geti2p.net/en/docs/naming#base32 I2P: Naming and address book].
I2P uses 52 characters (256 bits) to represent the full SHA-256 hash, followed by .b32.i2p.
I2P addresses MUST be sent with the I2P network ID, with the decoded SHA-256 hash as address field.
==Appendix D: Cjdns address encoding==
Cjdns addresses are simply IPv6 addresses in the fc00::/8 range[https://github.com/cjdelisle/cjdns/blob/6e46fa41f5647d6b414612d9d63626b0b952746b/doc/Whitepaper.md#pulling-it-all-together Cjdns whitepaper: Pulling It All Together]. They MUST be sent with the CJDNS network ID.
==Appendix E: Yggdrasil address encoding==
Yggdrasil addresses are simply IPv6 addresses in the 0200::/7 range[https://yggdrasil-network.github.io/faq.html#will-yggdrasil-conflict-with-my-network-routing Yggdrasil FAQ]. They MUST be sent with the YGGDRASIL network ID.
== Changelog ==
* 2.0.0 (2025-10-01):
** Add note that Tor v2 is no longer operational.
* 1.0.0 (2019-02-27):
** Initial version
==References==
================================================
FILE: bip-0156/bitcoin.conf
================================================
regtest=1 # Run this node on its own independent test network
debug=net # Enable network debug logs
debug=mempool # Enable mempool debug logs
debug=mempoolrej # Enable mempool rejection debug logs
debug=dandelion # Enable dandelion debug logs
logips=1 # Log IP addresses in debug output
logtimemicros=1 # Log timestamps with microsecond precision
printtoconsole=1 # Print debug logs to console instead of debug.log
server=1 # Accept command line JSON-RPC commands
rpcuser=xxx # Username for JSON-RPC connections
rpcpassword=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
rpcauth=xxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
dns=0 # Do not allow DNS lookups for -addnode, -seednode, and -connect
dnsseed=0 # Do not query for peer addresses via DNS lookup
persistmempool=0 # Do not save mempool on shutdown to load on restart
dandelion=1 # Enable Dandelion transactions
================================================
FILE: bip-0156.mediawiki
================================================
==Abstract==
Bitcoin's transaction spreading protocol is vulnerable to deanonymization
attacks. Dandelion is a transaction routing mechanism that provides formal
anonymity guarantees against these attacks. When a node generates a transaction
without Dandelion, it transmits that transaction to its peers with independent,
exponential delays. This approach, known as diffusion in academia, allows
network adversaries to link transactions to IP addresses.
Dandelion mitigates this class of attacks by sending transactions over a
randomly selected path before diffusion. Transactions travel along this path
during the "stem phase" and are then diffused during the "fluff phase" (hence
Dandelion). We have shown that this routing protocol provides near-optimal
anonymity guarantees among schemes that do not introduce additional encryption
mechanisms.
==Motivation==
Transaction diffusion in Bitcoin is vulnerable to deanonymization attacks.
Because transactions are sent to peers with independent, exponential delays,
messages spread through the network in a statistically symmetric manner. This
pattern allows colluding spy nodes to infer the transaction source. Breaking
this symmetry prevents the attack. However, we have shown that an adversary with
knowledge of the network topology can launch a much more effective "fingerprint"
attack if the symmetry breaking is not done properly.
Consider a botnet-style adversary with access to the P2P graph. Botnets of size
comparable to the Bitcoin P2P network are common and cheap, and these
adversaries can learn the network structure with probe messages. We have shown
that such an adversary can achieve total deanonymization of the entire network
after observing less than ten transactions per node.
Dandelion is a practical, lightweight privacy solution that provides the Bitcoin
network formal anonymity guarantees. While other privacy solutions aim to
protect individual users, Dandelion protects anonymity by limiting the
capability of adversaries to deanonymize the entire network.
==How Dandelion Works==
Dandelion enhances user privacy by sending transactions through an anonymity
phase before diffusing them throughout the network. At a high level, Dandelion
enhances privacy by (i) breaking the symmetry of diffusion and (ii) mixing
transactions by forwarding messages from different sources along the same path.
Dandelion routing can be conceptualized in three phases. First, a privacy graph
is constructed. In practice, this privacy graph is constructed in a fully
decentralized manner and is a subgraph of the existing Bitcoin P2P network.
Next, transactions are forwarded along this privacy graph during the "stem
phase." Finally, messages are broadcast to the network during the "fluff phase"
using the typical method of diffusion.
[[File:bip-0156/1-dandelion.png|framed|center|alt=An illustration of Dandelion routing|Figure 1]]
Figure 1
In order to select the privacy graph in a decentralized manner, each node
selects a subset of its outbound peers to be Dandelion destinations. Dandelion
transactions (transactions in their stem phase) that arrive at this node via
inbound connections are forwarded to these Dandelion destinations.
In an ideal setting, we have found that a Hamiltonian circuit provides
near-optimal privacy guarantees. However, constructing a Hamiltonian circuit
through the Bitcoin P2P network in a decentralized, trustless manner is not
feasible. Thus, we recommend that each node select two Dandelion destinations
uniformly at random without replacement from its list of outbound peers. Our
tests have shown that this method provides comparable privacy with increased
robustness.
During stem phase routing, there is a question of how to route messages in order
to protect privacy. For example, if two Dandelion transactions arrive at a node
from different inbound peers, to which Dandelion destination(s) should these
transactions be sent? We have found that some choices are much better than
others.
Consider the case in which each Dandelion transaction is forwarded to a
Dandelion destination selected uniformly at random. This approach results in a
fingerprint attack allowing network-level botnet adversaries to achieve total
deanonymization of the P2P network after observing less than ten transactions
per node.
[[File:bip-0156/2-attack.png|framed|center|alt=An illustration of a fingerprint attack|Figure 2]]
Figure 2
During a fingerprint attack, a botnet-style adversary with knowledge of the
graph structure first simulates transaction propagation. This offline step lets
the adversary generate fingerprints for each network node. During the online
attack, the adversary collects transactions at its spy nodes and matches these
observations to the simulated fingerprints. Our simulations have shown that this
attack results in devastating, network-wide deanonymization.
[[File:bip-0156/3-attack-plot.png|framed|center|alt=A plot illustrating total deanonymization|Figure 3]]
Figure 3
To avoid this issue, we suggest "per-inbound-edge" routing. Each inbound peer is
assigned a particular Dandelion destination. Each Dandelion transaction that
arrives via this peer is forwarded to the same Dandelion destination.
Per-inbound-edge routing breaks the described attack by blocking an adversary's
ability to construct useful fingerprints. Fingerprints arise when routing
decisions are made independently per transaction at each node. In this case, two
transactions from the same node generally take different paths through the
network. Crucially, this results in multiple, unique data points that are
aggregated to match with a fingerprint.
Dandelion ensures that two transactions from the same node take the same network
path, limiting adversaries to the far-left of the graph in Figure 3. In other
words, adversary knowledge is limited to the case of one observed message rather
than a rich profile of multiple transaction paths. Dandelion also breaks the
symmetry of diffusion, making the source of the transaction difficult to infer.
[[File:bip-0156/4-dandelion-plot.png|framed|center|alt=A plot illustrating limited deanonymization|Figure 4]]
Figure 4
After a transaction has traveled along a Dandelion stem for a random number of
hops, it transitions into the fluff phase of routing. The transaction is shared
with the network through the existing process of diffusion. In practice, this
fluff mechanism is enforced by a weighted coin flip at each node. If the random
value is below some threshold, the Dandelion transaction is transformed into a
typical transaction. In our testing, we have chosen a probability of ten percent
that a given Dandelion transaction enters fluff phase when leaving a given node.
This value strikes a good balance between stem path length and transaction
spreading latency.
Note that Dandelion's expected precision guarantees are a population-level
metric, whereas the expected recall guarantees can be interpreted as an
individual-level metric. Expected recall is equivalent to the probability that
an adversary associates a single transaction with a given source. These
guarantees are probabilistic. They do not address scenarios in which a node has
been eclipsed by other nodes, or when a node is specifically targeted by an
ISP-like adversary. Individuals who are concerned about targeted deanonymization
should still use Tor.
At a high level, Dandelion is like an "anonymity inoculation" for the public at
large - including users who are not aware of Bitcoin's privacy issues. Higher
adoption leads to greater benefits, even for users who do not use Tor. Early
adopters of Dandelion still receive privacy benefits. In the worst case when no
neighbors support Dandelion, transactions make at least one hop before
diffusing. Note that any solution based only on routing cannot be perfectly
anonymous due to the fundamental lower bounds on precision and recall shown in
the original Dandelion paper. Dandelion provides near-optimal anonymity
guarantees among such solutions.
==Specification==
Dandelion can be specified with a handful of features: Dandelion transaction
support, Dandelion routing data and logic, periodic Dandelion route shuffling,
memory pool logic, the fluff mechanism, transaction embargoes, and Dandelion
transaction logic. Specification details are summarized below.
===Dandelion transaction support===
During the stem phase, transactions are "Dandelion transactions." When a
Dandelion transaction enters fluff phase, it becomes a typical Bitcoin
transaction. Dandelion transactions and typical transactions differ only in
their NetMsgType.
Dandelion (stem phase) transactions MUST be differentiable from typical Bitcoin
transactions.
===Dandelion routing data and logic===
Dandelion routing during the stem phase requires notions of inbound peers,
outbound peers, Dandelion destinations, and Dandelion routes. Inbound peers
consist of all currently connected peers that initiated the peer connection.
Outbound peers consist of all currently connected peers that were connected to
by this node. Dandelion destinations are a subset of outbound peers. The number
of Dandelion destinations is limited by the
DANDELION_MAX_DESTINATIONS parameter. In the reference
implementation, this parameter is set to two. Our tests have shown that this
value provides both privacy and robustness (see the reference paper for more
details on the parameter tradeoffs). Dandelion routes are a map of inbound peers
to Dandelion destinations. Every inbound peer is mapped to a Dandelion
destination.
Note that a Dandelion node may choose a different
DANDELION_MAX_DESTINATIONS parameter without splitting from the
privacy graph. When mapping inbound connections to outbound connections for
Dandelion routes, we implement the following routing logic. First, select a set
of Dandelion destinations from the set of outbound peers. This set of Dandelion
destinations is of size less than or equal to
DANDELION_MAX_DESTINATIONS. For each inbound connection, first
identify the subset of Dandelion destinations with the least number of routes.
For example, some subset of Dandelion destinations may be affiliated with zero
routes while all other Dandelion destinations are affiliated with one or more
routes. From this subset, select one Dandelion destination uniformly at random.
Establish a Dandelion route from the inbound connection to this Dandelion
destination.
For a given Dandelion routing epoch, two distinct Dandelion destinations SHOULD
be selected uniformly at random from the set of outbound connections. All
Dandelion transactions that arrive via a given inbound connection MUST be
transmitted to the same Dandelion destination. When choosing a Dandelion
destination for a given inbound connection, the destination MUST be selected
uniformly at random from the set of Dandelion destinations with the least number
of inbound connections mapped to them.
===Periodic Dandelion route shuffling===
The map of Dandelion routes is cleared and reconstructed every ten minutes on
average. We have chosen the value of ten minutes heuristically in order to make
privacy graph learning difficult for adversaries. Note that a Dandelion node may
choose a different average shuffle time without splitting from the privacy
graph.
Dandelion routes MUST be cleared and reconstructed at random intervals.
Dandelion routes SHOULD be cleared and reconstructed every ten minutes on
average.
===Memory pool logic===
Dandelion transactions are segregated from typical transactions. The
mempool remains unchanged. Another instance of the
CTxMemPool class, called the stempool, is used for
Dandelion transactions. Information flows from mempool to
stempool in order to ensure proper transaction propagation.
Information does not flow from stempool to mempool,
except when a Dandelion transaction fluffs into a typical transaction.
When a Dandelion transaction arrives, the transaction MUST be added to the
stempool and MUST NOT be added to the mempool. When a typical Bitcoin
transaction arrives, the transaction MUST be added to the mempool and MUST be
added to the stempool. When a Dandelion transaction fluffs, the transaction MUST
be added to the mempool.
===The fluff mechanism===
When relaying a Dandelion transaction along a Dandelion route, there is a 10%
chance that the Dandelion transaction becomes a typical Bitcoin transaction and
is therefore relayed via diffusion. In our testing, this value strikes a good
balance between stem path length and transaction spreading latency. Note that a
Dandelion node may choose a different chance of fluffing without splitting from
the privacy graph.
When a node prepares to transmit a Dandelion transaction, the node MUST flip a
biased coin. If the outcome is "Dandelion transaction," then the node MUST
transmit the transaction to the appropriate Dandelion destination. Otherwise,
the node MUST convert the Dandelion transaction into a typical Bitcoin
transaction. A Dandelion transaction SHOULD fluff into a typical Bitcoin
transaction with a 10% probability.
===Transaction embargoes===
During the stem phase, transactions are relayed along a single path. If any node
in this path were to receive the Dandelion transaction and go offline, then the
transaction would cease to propagate. To increase robustness, every node that
forwards a Dandelion transaction initializes a timer at the time of reception.
If the Dandelion transaction does not appear in the memory pool by the time the
timer expires, then the transaction enters fluff phase and is forwarded via
diffusion.
When a Dandelion transaction arrives, the node MUST set an embargo timer for a
random time in the future. If the Dandelion transaction arrives as a typical
Bitcoin transaction, the node MUST cancel the timer. If the timer expires before
the Dandelion transaction is observed as a typical Bitcoin transaction, then the
node MUST fluff the Dandelion transaction.
===Dandelion transaction logic===
The following cases define a node's behavior when receiving network packets
referencing Dandelion transactions.
* Receive INV for Dandelion TX: If the peer is inbound and the Dandelion transaction has not been received from this peer, then reply with GETDATA.
* Receive GETDATA for Dandelion TX: If the peer is not inbound and the Dandelion transaction has been advertised to this peer, then reply with the Dandelion transaction.
* Receive Dandelion TX: If the peer is inbound, then relay the Dandelion TX to the appropriate Dandelion destination.
==Implementation==
A reference implementation is available at the following URL:
https://github.com/dandelion-org/bitcoin/tree/dandelion-feature-commits
All features have been compressed into a single commit at the following URL:
https://github.com/dandelion-org/bitcoin/tree/dandelion
==Compatibility==
Dandelion does not conflict with existing versions of Bitcoin. A Bitcoin node
that supports Dandelion appears no differently to Bitcoin nodes running older
software versions. Bitcoin nodes that support Dandelion can identify feature
support through a probe message. Obviously, older nodes are not capable of
Dandelion routing. If a Bitcoin node supporting Dandelion has no peers that also
support Dandelion, then its behavior naturally decays to that of a Bitcoin node
without Dandelion support due to the Dandelion transaction embargoes.
==Acknowledgements==
We would like to thank the Bitcoin Core developers and Gregory Maxwell in
particular for their insightful comments, which helped to inform this
implementation and some of the follow-up work we conducted. We would also like
to thank the Mimblewimble development community for coining the term "stempool,"
which we happily adopted for this implementation.
==References==
# An Analysis of Anonymity in Bitcoin Using P2P Network Traffic http://fc14.ifca.ai/papers/fc14_submission_71.pdf
# Deanonymisation of clients in Bitcoin P2P network https://arxiv.org/abs/1405.7418
# Discovering Bitcoin’s Public Topology and Influential Nodes https://cs.umd.edu/projects/coinscope/coinscope.pdf
# (Sigmetrics 2017) Dandelion: Redesigning the Bitcoin Network for Anonymity https://arxiv.org/abs/1701.04439
# (Sigmetrics 2018) Dandelion++: Lightweight Cryptocurrency Networking with Formal Anonymity Guarantees https://arxiv.org/pdf/1805.11060.pdf
==Copyright==
To the extent possible under law, the author(s) have dedicated all copyright and
related and neighboring rights to this work to the public domain worldwide. This
work is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication with this
work. If not, see https://creativecommons.org/publicdomain/zero/1.0/ .
================================================
FILE: bip-0157.mediawiki
================================================
BIP: 157
Layer: Peer Services
Title: Client Side Block Filtering
Authors: Olaoluwa Osuntokun
Alex Akselrod
Jim Posen
Status: Deployed
Type: Specification
Assigned: 2017-05-24
License: CC0-1.0
Requires: 158
== Abstract ==
This BIP describes a new light client protocol in Bitcoin that improves upon
currently available options. The standard light client protocol in use today,
defined in BIP
37https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki, has
known flaws that weaken the security and privacy of clients and allow
denial-of-service attack vectors on full
nodeshttps://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-May/012636.html.
The new protocol overcomes these issues by allowing light clients to obtain
compact probabilistic filters of block content from full nodes and download full
blocks if the filter matches relevant data.
New P2P messages empower light clients to securely sync the blockchain without
relying on a trusted source. This BIP also defines a filter header, which serves
as a commitment to all filters for previous blocks and provides the ability to
efficiently detect malicious or faulty peers serving invalid filters. The
resulting protocol guarantees that light clients with at least one honest peer
are able to identify the correct block filters.
== Motivation ==
Bitcoin light clients allow applications to read relevant transactions from the
blockchain without incurring the full cost of downloading and validating all
data. Such applications seek to simultaneously minimize the trust in peers and
the amount of bandwidth, storage space, and computation required. They achieve
this by downloading all block headers, verifying the proofs of work, and
following the longest proof-of-work chain. Since block headers are a fixed
80-bytes and are generated every 10 minutes on average, the bandwidth required
to sync the block headers is minimal. Light clients then download only the
blockchain data relevant to them directly from peers and validate inclusion in
the header chain. Though clients do not check the validity of all blocks in the
longest proof-of-work chain, they rely on miner incentives for security.
BIP 37 is currently the most widely used light client execution mode for
Bitcoin. With BIP 37, a client sends a Bloom filter it wants to watch to a full
node peer, then receives notifications for each new transaction or block that
matches the filter. The client then requests relevant transactions from the peer
along with Merkle proofs of inclusion in the blocks containing them, which are
verified against the block headers. The Bloom filters match data such as client
addresses and unspent outputs, and the filter size must be carefully tuned to
balance the false positive rate with the amount of information leaked to peer. It
has been shown, however, that most implementations available offer virtually
''zero privacy'' to wallets and other
applicationshttps://eprint.iacr.org/2014/763.pdfhttps://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj/.
Additionally, malicious full nodes serving light clients can omit critical data
with little risk of detection, which is unacceptable for some applications
(such as Lightning Network clients) that must respond to certain on-chain
events. Finally, honest nodes servicing BIP 37 light clients may incur
significant I/O and CPU resource usage due to maliciously crafted Bloom filters,
creating a denial-of-service (DoS) vector and disincentizing node operators from
supporting the
protocolhttps://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki.
The alternative detailed in this document can be seen as the opposite of BIP 37:
instead of the client sending a filter to a full node peer, full nodes generate
deterministic filters on block data that are served to the client. A light
client can then download an entire block if the filter matches the data it is
watching for. Since filters are deterministic, they only need to be constructed
once and stored on disk, whenever a new block is connected to the chain. This
keeps the computation required to serve filters minimal, and eliminates the I/O
asymmetry that makes BIP 37 enabled nodes vulnerable. Clients also get better
assurance of seeing all relevant transactions because they can check the
validity of filters received from peers more easily than they can check
completeness of filtered blocks. Finally, client privacy is improved because
blocks can be downloaded from ''any source'', so that no one peer gets complete
information on the data required by a client. Extremely privacy conscious light
clients may opt to anonymously fetch blocks using advanced techniques such a
Private Information
Retrievalhttps://en.wikipedia.org/wiki/Private_information_retrieval.
== Definitions ==
[]byte represents a vector of bytes.
[N]byte represents a fixed-size byte array with length N.
''CompactSize'' is a compact encoding of unsigned integers used in the Bitcoin
P2P protocol.
''double-SHA256'' is a hash algorithm defined by two invocations of SHA-256:
double-SHA256(x) = SHA256(SHA256(x)).
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in RFC 2119.
== Specification ==
=== Filter Types ===
For the sake of future extensibility and reducing filter sizes, there are
multiple ''filter types'' that determine which data is included in a block
filter as well as the method of filter construction/querying. In this model,
full nodes generate one filter per block per filter type supported.
Each type is identified by a one byte code, and specifies the contents and
serialization format of the filter. A full node MAY signal support for
particular filter types using service bits. The initial filter types are defined
separately in [[bip-0158.mediawiki|BIP 158]], and one service bit is allocated
to signal support for them.
=== Filter Headers ===
This proposal draws inspiration from the headers-first mechanism that Bitcoin
nodes use to sync the block
chainhttps://bitcoin.org/en/developer-guide#headers-first. Similar to
how block headers have a Merkle commitment to all transaction data in the block,
we define filter headers that have commitments to the block filters. Also like
block headers, filter headers each have a commitment to the preceding one.
Before downloading the block filters themselves, a light client can download all
filter headers for the current block chain and use them to verify the
authenticity of the filters. If the filter header chains differ between multiple
peers, the client can identify the point where they diverge, then download the
full block and compute the correct filter, thus identifying which peer is
faulty.
The canonical hash of a block filter is the double-SHA256 of the serialized
filter. Filter headers are 32-byte hashes derived for each block filter. They
are computed as the double-SHA256 of the concatenation of the filter hash with
the previous filter header. The previous filter header used to calculate that of
the genesis block is defined to be the 32-byte array of 0's.
=== New Messages ===
==== getcfilters ====
getcfilters is used to request the compact filters of a particular
type for a particular range of blocks. The message contains the following
fields:
{| class="wikitable"
! Field Name
! Data Type
! Byte Size
! Description
|-
| FilterType
| byte
| 1
| Filter type for which headers are requested
|-
| StartHeight
| uint32
| 4
| The height of the first block in the requested range
|-
| StopHash
| [32]byte
| 32
| The hash of the last block in the requested range
|}
# Nodes SHOULD NOT send getcfilters unless the peer has signaled support for this filter type. Nodes receiving getcfilters with an unsupported filter type SHOULD NOT respond.
# StopHash MUST be known to belong to a block accepted by the receiving peer. This is the case if the peer had previously sent a headers or inv message with that block or any descendents. A node that receives getcfilters with an unknown StopHash SHOULD NOT respond.
# The height of the block with hash StopHash MUST be greater than or equal to StartHeight, and the difference MUST be strictly less than 1000.
# The receiving node MUST respond to valid requests by sending one cfilter message for each block in the requested range, sequentially in order by block height.
==== cfilter ====
cfilter is sent in response to getcfilters, one for
each block in the requested range. The message contains the following fields:
{| class="wikitable"
! Field Name
! Data Type
! Byte Size
! Description
|-
| FilterType
| byte
| 1
| Byte identifying the type of filter being returned
|-
| BlockHash
| [32]byte
| 32
| Block hash of the Bitcoin block for which the filter is being returned
|-
| NumFilterBytes
| CompactSize
| 1-5
| A variable length integer representing the size of the filter in the following field
|-
| FilterBytes
| []byte
| NumFilterBytes
| The serialized compact filter for this block
|}
# The FilterType SHOULD match the field in the getcfilters request, and BlockHash must correspond to a block that is an ancestor of StopHash with height greater than or equal to StartHeight.
==== getcfheaders ====
getcfheaders is used to request verifiable filter headers for a
range of blocks. The message contains the following fields:
{| class="wikitable"
! Field Name
! Data Type
! Byte Size
! Description
|-
| FilterType
| byte
| 1
| Filter type for which headers are requested
|-
| StartHeight
| uint32
| 4
| The height of the first block in the requested range
|-
| StopHash
| [32]byte
| 32
| The hash of the last block in the requested range
|}
# Nodes SHOULD NOT send getcfheaders unless the peer has signaled support for this filter type. Nodes receiving getcfheaders with an unsupported filter type SHOULD NOT respond.
# StopHash MUST be known to belong to a block accepted by the receiving peer. This is the case if the peer had previously sent a headers or inv message with that block or any descendents. A node that receives getcfheaders with an unknown StopHash SHOULD NOT respond.
# The height of the block with hash StopHash MUST be greater than or equal to StartHeight, and the difference MUST be strictly less than 2,000.
==== cfheaders ====
cfheaders is sent in response to getcfheaders. Instead
of including the filter headers themselves, the response includes one filter
header and a sequence of filter hashes, from which the headers can be derived.
This has the benefit that the client can verify the binding links between the
headers. The message contains the following fields:
{| class="wikitable"
! Field Name
! Data Type
! Byte Size
! Description
|-
| FilterType
| byte
| 1
| Filter type for which hashes are requested
|-
| StopHash
| [32]byte
| 32
| The hash of the last block in the requested range
|-
| PreviousFilterHeader
| [32]byte
| 32
| The filter header preceding the first block in the requested range
|-
| FilterHashesLength
| CompactSize
| 1-3
| The length of the following vector of filter hashes
|-
| FilterHashes
| [][32]byte
| FilterHashesLength * 32
| The filter hashes for each block in the requested range
|}
# The FilterType and StopHash SHOULD match the fields in the getcfheaders request.
# FilterHashesLength MUST NOT be greater than 2,000.
# FilterHashes MUST have one entry for each block on the chain terminating with tip StopHash, starting with the block at height StartHeight. The entries MUST be the filter hashes of the given type for each block in that range, in ascending order by height.
# PreviousFilterHeader MUST be set to the previous filter header of first block in the requested range.
==== getcfcheckpt ====
getcfcheckpt is used to request filter headers at evenly spaced
intervals over a range of blocks. Clients may use filter hashes from
getcfheaders to connect these checkpoints, as is described in the
[[#client-operation|Client Operation]] section below. The
getcfcheckpt message contains the following fields:
{| class="wikitable"
! Field Name
! Data Type
! Byte Size
! Description
|-
| FilterType
| byte
| 1
| Filter type for which headers are requested
|-
| StopHash
| [32]byte
| 32
| The hash of the last block in the chain that headers are requested for
|}
# Nodes SHOULD NOT send getcfcheckpt unless the peer has signaled support for this filter type. Nodes receiving getcfcheckpt with an unsupported filter type SHOULD NOT respond.
# StopHash MUST be known to belong to a block accepted by the receiving peer. This is the case if the peer had previously sent a headers or inv message with any descendent blocks. A node that receives getcfcheckpt with an unknown StopHash SHOULD NOT respond.
==== cfcheckpt ====
cfcheckpt is sent in response to getcfcheckpt. The
filter headers included are the set of all filter headers on the requested chain
where the height is a positive multiple of 1,000. The message contains the
following fields:
{| class="wikitable"
! Field Name
! Data Type
! Byte Size
! Description
|-
| FilterType
| byte
| 1
| Filter type for which headers are requested
|-
| StopHash
| [32]byte
| 32
| The hash of the last block in the chain that headers are requested for
|-
| FilterHeadersLength
| CompactSize
| 1-3
| The length of the following vector of filter headers
|-
| FilterHeaders
| [][32]byte
| FilterHeadersLength * 32
| The filter headers at intervals of 1,000
|}
# The FilterType and StopHash SHOULD match the fields in the getcfcheckpt request.
# FilterHeaders MUST have exactly one entry for each block on the chain terminating in StopHash, where the block height is a multiple of 1,000 greater than 0. The entries MUST be the filter headers of the given type for each such block, in ascending order by height.
=== Node Operation ===
Full nodes MAY opt to support this BIP and generate filters for any of the
specified filter types. Such nodes SHOULD treat the filters as an additional
index of the blockchain. For each new block that is connected to the main chain,
nodes SHOULD generate filters for all supported types and persist them. Nodes
that are missing filters and are already synced with the blockchain SHOULD
reindex the chain upon start-up, constructing filters for each block from
genesis to the current tip. They also SHOULD keep every checkpoint header in
memory, so that getcfcheckpt requests do not result in many
random-access disk reads.
Nodes SHOULD NOT generate filters dynamically on request, as malicious peers may
be able to perform DoS attacks by requesting small filters derived from large
blocks. This would require an asymmetrical amount of I/O on the node to compute
and serve, similar to attacks against BIP 37 enabled nodes noted in BIP 111.
Nodes MAY prune block data after generating and storing all filters for a block.
=== Client Operation ===
This section provides recommendations for light clients to download filters with
maximal security.
Clients SHOULD first sync the entire block header chain from peers using the
standard headers-first syncing mechanism before downloading any block filters or
filter headers. Clients configured with trusted checkpoints MAY only sync
headers started from the last checkpoint. Clients SHOULD disconnect any outbound
peers whose best chain has significantly less work than the known longest
proof-of-work chain.
Once a client's block headers are in sync, it SHOULD download and verify filter
headers for all blocks and filter types that it might later download. The client
SHOULD send getcfheaders messages to peers and derive and store the
filter headers for each block. The client MAY first fetch headers at evenly
spaced intervals of 1,000 by sending getcfcheckpt. The header
checkpoints allow the client to download filter headers for different intervals
from multiple peers in parallel, verifying each range of 1,000 headers against
the checkpoints.
Unless securely connected to a trusted peer that is serving filter headers, the
client SHOULD connect to multiple outbound peers that support each filter type
to mitigate the risk of downloading incorrect headers. If the client receives
conflicting filter headers from different peers for any block and filter type,
it SHOULD interrogate them to determine which is faulty. The client SHOULD use
getcfheaders and/or getcfcheckpt to first identify
the first filter headers that the peers disagree on. The client then SHOULD
download the full block from any peer and derive the correct filter and filter
header. The client SHOULD ban any peers that sent a filter header that does not
match the computed one.
Once the client has downloaded and verified all filter headers needed, ''and''
no outbound peers have sent conflicting headers, the client can download the
actual block filters it needs. The client MAY backfill filter headers before the
first verified one at this point if it only downloaded them starting at a later
point. Clients SHOULD persist the verified filter headers for the last 100 blocks in
the chain (or whatever finality depth is desired), to compare against headers
received from new peers after restart. They MAY store more filter headers to
avoid redownloading them if a rescan is later necessary.
Starting from the first block in the desired range, the client now MAY download
the filters. The client SHOULD test that each filter links to its corresponding
filter header and ban peers that send incorrect filters. The client MAY download
multiple filters at once to increase throughput, though it SHOULD test the
filters sequentially. The client MAY check if a filter is empty before
requesting it by checking if the filter header commits to the hash of the empty
filter, saving a round trip if that is the case.
Each time a new valid block header is received, the client SHOULD request the
corresponding filter headers from all eligible peers. If two peers send
conflicting filter headers, the client should interrogate them as described
above and ban any peers that send an invalid header.
If a client is fetching full blocks from the P2P network, they SHOULD be downloaded
from outbound peers at random to mitigate privacy loss due to transaction
intersection analysis. Note that blocks may be downloaded from peers that do not
support this BIP.
== Rationale ==
The filter headers and checkpoints messages are defined to help clients identify
the correct filter for a block when connected to peers sending conflicting
information. An alternative solution is to require Bitcoin blocks to include
commitments to derived block filters, so light clients can verify authenticity
given block headers and some additional witness data. This would require a
network-wide change to the Bitcoin consensus rules, however, whereas this
document proposes a solution purely at the P2P layer.
The constant interval of 1,000 blocks between checkpoints was chosen so that,
given the current chain height and rate of growth, the size of a
cfcheckpt message is not drastically different from a
cfheaders message between two checkpoints. Also, 1,000 is a nice
round number, at least to those of us who think in decimal.
== Compatibility ==
This light client mode is not compatible with current node deployments and
requires support for the new P2P messages. The node implementation of this
proposal is not incompatible with the current P2P network rules (ie. doesn't
affect network topology of full nodes). Light clients may adopt protocols based
on this as an alternative to the existing BIP 37. Adoption of this BIP may
result in reduced network support for BIP 37.
== Acknowledgments ==
We would like to thank bfd (from the bitcoin-dev mailing list) for bringing the
basis of this BIP to our attention, Joseph Poon for suggesting the filter header
chain scheme, and Pedro Martelletto for writing the initial indexing code for
btcd.
We would also like to thank Dave Collins, JJ Jeffrey, Eric Lombrozo, and Matt
Corallo for useful discussions.
== Reference Implementation ==
Light client: [https://github.com/lightninglabs/neutrino]
Full-node indexing: https://github.com/Roasbeef/btcd/tree/segwit-cbf
Golomb-Rice Coded sets: https://github.com/Roasbeef/btcutil/tree/gcs/gcs
== References ==
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
================================================
FILE: bip-0158/gentestvectors.go
================================================
// This program connects to your local btcd and generates test vectors for
// 5 blocks and collision space sizes of 1-32 bits. Change the RPC cert path
// and credentials to run on your system. The program assumes you're running
// a btcd with cfilter support, which mainline btcd doesn't have; in order to
// circumvent this assumption, comment out the if block that checks the
// filter size of DefaultP.
package main
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/gcs/builder"
"github.com/davecgh/go-spew/spew"
)
var (
// testBlockHeights are the heights of the blocks to include in the test
// vectors. Any new entries must be added in sorted order.
testBlockHeights = []testBlockCase{
{0, "Genesis block"},
{2, ""},
{3, ""},
{15007, "Tx has non-standard OP_RETURN output followed by opcodes"},
{49291, "Tx pays to empty output script"},
{180480, "Tx spends from empty output script"},
{926485, "Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"},
{987876, "Coinbase tx has unparsable output script"},
{1263442, "Includes witness data"},
{1414221, "Empty data"},
}
defaultBtcdDir = btcutil.AppDataDir("btcd", false)
defaultBtcdRPCCertFile = filepath.Join(defaultBtcdDir, "rpc.cert")
)
const (
fp = 19
)
type testBlockCase struct {
height uint32
comment string
}
type JSONTestWriter struct {
writer io.Writer
firstRowWritten bool
}
func NewJSONTestWriter(writer io.Writer) *JSONTestWriter {
return &JSONTestWriter{writer: writer}
}
func (w *JSONTestWriter) WriteComment(comment string) error {
return w.WriteTestCase([]interface{}{comment})
}
func (w *JSONTestWriter) WriteTestCase(row []interface{}) error {
var err error
if w.firstRowWritten {
_, err = io.WriteString(w.writer, ",\n")
} else {
_, err = io.WriteString(w.writer, "[\n")
w.firstRowWritten = true
}
if err != nil {
return err
}
rowBytes, err := json.Marshal(row)
if err != nil {
return err
}
_, err = w.writer.Write(rowBytes)
return err
}
func (w *JSONTestWriter) Close() error {
if !w.firstRowWritten {
return nil
}
_, err := io.WriteString(w.writer, "\n]\n")
return err
}
func fetchPrevOutputScripts(client *rpcclient.Client, block *wire.MsgBlock) ([][]byte, error) {
var prevScripts [][]byte
txCache := make(map[chainhash.Hash]*wire.MsgTx)
for _, tx := range block.Transactions {
if blockchain.IsCoinBaseTx(tx) {
continue
}
for _, txIn := range tx.TxIn {
prevOp := txIn.PreviousOutPoint
tx, ok := txCache[prevOp.Hash]
if !ok {
originTx, err := client.GetRawTransaction(
&prevOp.Hash,
)
if err != nil {
return nil, fmt.Errorf("unable to get "+
"txid=%v: %v", prevOp.Hash, err)
}
txCache[prevOp.Hash] = originTx.MsgTx()
tx = originTx.MsgTx()
}
index := prevOp.Index
prevScripts = append(
prevScripts, tx.TxOut[index].PkScript,
)
}
}
return prevScripts, nil
}
func main() {
var (
writerFile *JSONTestWriter
prevBasicHeader chainhash.Hash
)
fName := fmt.Sprintf("testnet-%02d.json", fp)
file, err := os.Create(fName)
if err != nil {
fmt.Println("Error creating output file: ", err.Error())
return
}
defer file.Close()
writer := &JSONTestWriter{
writer: file,
}
defer writer.Close()
err = writer.WriteComment("Block Height,Block Hash,Block," +
"[Prev Output Scripts for Block],Previous Basic Header," +
"Basic Filter,Basic Header,Notes")
if err != nil {
fmt.Println("Error writing to output file: ", err.Error())
return
}
writerFile = writer
cert, err := ioutil.ReadFile(defaultBtcdRPCCertFile)
if err != nil {
fmt.Println("Couldn't read RPC cert: ", err.Error())
return
}
conf := rpcclient.ConnConfig{
Host: "127.0.0.1:18334",
Endpoint: "ws",
User: "kek",
Pass: "kek",
Certificates: cert,
}
client, err := rpcclient.New(&conf, nil)
if err != nil {
fmt.Println("Couldn't create a new client: ", err.Error())
return
}
var testBlockIndex int
for height := 0; testBlockIndex < len(testBlockHeights); height++ {
blockHash, err := client.GetBlockHash(int64(height))
if err != nil {
fmt.Println("Couldn't get block hash: ", err.Error())
return
}
block, err := client.GetBlock(blockHash)
if err != nil {
fmt.Println("Couldn't get block data: ", err.Error())
return
}
var blockBuf bytes.Buffer
err = block.Serialize(&blockBuf)
if err != nil {
fmt.Println("Error serializing block to buffer: ", err.Error())
return
}
blockBytes := blockBuf.Bytes()
prevOutputScripts, err := fetchPrevOutputScripts(client, block)
if err != nil {
fmt.Println("Couldn't fetch prev output scripts: ", err)
return
}
basicFilter, err := builder.BuildBasicFilter(block, prevOutputScripts)
if err != nil {
fmt.Println("Error generating basic filter: ", err.Error())
return
}
basicHeader, err := builder.MakeHeaderForFilter(basicFilter, prevBasicHeader)
if err != nil {
fmt.Println("Error generating header for filter: ", err.Error())
return
}
// We'll now ensure that we've constructed the same filter as
// the chain server we're fetching blocks from.
filter, err := client.GetCFilter(
blockHash, wire.GCSFilterRegular,
)
if err != nil {
fmt.Println("Error getting basic filter: ",
err.Error())
return
}
nBytes, err := basicFilter.NBytes()
if err != nil {
fmt.Println("Couldn't get NBytes(): ", err)
return
}
if !bytes.Equal(filter.Data, nBytes) {
// Don't error on empty filters
fmt.Printf("basic filter doesn't match: generated "+
"%x, rpc returns %x, block %v", nBytes,
filter.Data, spew.Sdump(block))
return
}
header, err := client.GetCFilterHeader(
blockHash, wire.GCSFilterRegular,
)
if err != nil {
fmt.Println("Error getting basic header: ", err.Error())
return
}
if !bytes.Equal(header.PrevFilterHeader[:], basicHeader[:]) {
fmt.Println("Basic header doesn't match!")
return
}
if height%1000 == 0 {
fmt.Printf("Verified height %v against server\n", height)
}
if uint32(height) == testBlockHeights[testBlockIndex].height {
var bfBytes []byte
bfBytes, err = basicFilter.NBytes()
if err != nil {
fmt.Println("Couldn't get NBytes(): ", err)
return
}
prevScriptStrings := make([]string, len(prevOutputScripts))
for i, prevScript := range prevOutputScripts {
prevScriptStrings[i] = hex.EncodeToString(prevScript)
}
row := []interface{}{
height,
blockHash.String(),
hex.EncodeToString(blockBytes),
prevScriptStrings,
prevBasicHeader.String(),
hex.EncodeToString(bfBytes),
basicHeader.String(),
testBlockHeights[testBlockIndex].comment,
}
err = writerFile.WriteTestCase(row)
if err != nil {
fmt.Println("Error writing test case to output: ", err.Error())
return
}
testBlockIndex++
}
prevBasicHeader = basicHeader
}
}
================================================
FILE: bip-0158/go.mod
================================================
module github.com/bitcoin/bips/bip-0158
require (
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803
github.com/davecgh/go-spew v1.1.1
)
================================================
FILE: bip-0158/go.sum
================================================
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d h1:xG8Pj6Y6J760xwETNmMzmlt38QSwz0BLp1cZ09g27uw=
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803 h1:j3AgPKKZtZStM2nyhrDSLSYgT7YHrZKdSkq1OYeLjvM=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44 h1:9lP3x0pW80sDI6t1UMSLA4to18W7R7imwAI/sWS9S8Q=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
================================================
FILE: bip-0158/testnet-19.json
================================================
[
["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"],
[0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"],
[2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""],
[3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""],
[15007,"0000000038c44c703bae0f98cdd6bf30922326340a5996cc692aaae8bacf47ad","0100000002394092aa378fe35d7e9ac79c869b975c4de4374cd75eb5484b0e1e00000000eb9b8670abd44ad6c55cee18e3020fb0c6519e7004b01a16e9164867531b67afc33bc94fffff001d123f10050101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e04c33bc94f0115062f503253482fffffffff0100f2052a01000000232103f268e9ae07e0f8cb2f6e901d87c510d650b97230c0365b021df8f467363cafb1ac00000000",[],"18b5c2b0146d2d09d24fb00ff5b52bd0742f36c9e65527abdb9de30c027a4748","013c3710","07384b01311867949e0c046607c66b7a766d338474bb67f66c8ae9dbd454b20e","Tx has non-standard OP_RETURN output followed by opcodes"],
[49291,"0000000018b07dca1b28b4b5a119f6d6e71698ce1ed96f143f54179ce177a19c","02000000abfaf47274223ca2fea22797e44498240e482cb4c2f2baea088962f800000000604b5b52c32305b15d7542071d8b04e750a547500005d4010727694b6e72a776e55d0d51ffff001d211806480201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038bc0000102062f503253482fffffffff01a078072a01000000232102971dd6034ed0cf52450b608d196c07d6345184fcb14deb277a6b82d526a6163dac0000000001000000081cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff000000009300493046022100866859c21f306538152e83f115bcfbf59ab4bb34887a88c03483a5dff9895f96022100a6dfd83caa609bf0516debc2bf65c3df91813a4842650a1858b3f61cfa8af249014730440220296d4b818bb037d0f83f9f7111665f49532dfdcbec1e6b784526e9ac4046eaa602204acf3a5cb2695e8404d80bf49ab04828bcbe6fc31d25a2844ced7a8d24afbdff01ffffffff1cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff020000009400483045022100e87899175991aa008176cb553c6f2badbb5b741f328c9845fcab89f8b18cae2302200acce689896dc82933015e7230e5230d5cff8a1ffe82d334d60162ac2c5b0c9601493046022100994ad29d1e7b03e41731a4316e5f4992f0d9b6e2efc40a1ccd2c949b461175c502210099b69fdc2db00fbba214f16e286f6a49e2d8a0d5ffc6409d87796add475478d601ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272010000009500493046022100a27400ba52fd842ce07398a1de102f710a10c5599545e6c95798934352c2e4df022100f6383b0b14c9f64b6718139f55b6b9494374755b86bae7d63f5d3e583b57255a01493046022100fdf543292f34e1eeb1703b264965339ec4a450ec47585009c606b3edbc5b617b022100a5fbb1c8de8aaaa582988cdb23622838e38de90bebcaab3928d949aa502a65d401ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272020000009400493046022100ac626ac3051f875145b4fe4cfe089ea895aac73f65ab837b1ac30f5d875874fa022100bc03e79fa4b7eb707fb735b95ff6613ca33adeaf3a0607cdcead4cfd3b51729801483045022100b720b04a5c5e2f61b7df0fcf334ab6fea167b7aaede5695d3f7c6973496adbf1022043328c4cc1cdc3e5db7bb895ccc37133e960b2fd3ece98350f774596badb387201ffffffff23a8733e349c97d6cd90f520fdd084ba15ce0a395aad03cd51370602bb9e5db3010000004a00483045022100e8556b72c5e9c0da7371913a45861a61c5df434dfd962de7b23848e1a28c86ca02205d41ceda00136267281be0974be132ac4cda1459fe2090ce455619d8b91045e901ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a6000000006a473044022040a1c631554b8b210fbdf2a73f191b2851afb51d5171fb53502a3a040a38d2c0022040d11cf6e7b41fe1b66c3d08f6ada1aee07a047cb77f242b8ecc63812c832c9a012102bcfad931b502761e452962a5976c79158a0f6d307ad31b739611dac6a297c256ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a601000000930048304502205b109df098f7e932fbf71a45869c3f80323974a826ee2770789eae178a21bfc8022100c0e75615e53ee4b6e32b9bb5faa36ac539e9c05fa2ae6b6de5d09c08455c8b9601483045022009fb7d27375c47bea23b24818634df6a54ecf72d52e0c1268fb2a2c84f1885de022100e0ed4f15d62e7f537da0d0f1863498f9c7c0c0a4e00e4679588c8d1a9eb20bb801ffffffffa563c3722b7b39481836d5edfc1461f97335d5d1e9a23ade13680d0e2c1c371f030000006c493046022100ecc38ae2b1565643dc3c0dad5e961a5f0ea09cab28d024f92fa05c922924157e022100ebc166edf6fbe4004c72bfe8cf40130263f98ddff728c8e67b113dbd621906a601210211a4ed241174708c07206601b44a4c1c29e5ad8b1f731c50ca7e1d4b2a06dc1fffffffff02d0223a00000000001976a91445db0b779c0b9fa207f12a8218c94fc77aff504588ac80f0fa02000000000000000000",["5221033423007d8f263819a2e42becaaf5b06f34cb09919e06304349d950668209eaed21021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","522102a7ae1e0971fc1689bd66d2a7296da3a1662fd21a53c9e38979e0f090a375c12d21022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","512103b9d1d0e2b4355ec3cdef7c11a5c0beff9e8b8d8372ab4b4e0aaf30e80173001951ae","76a9149144761ebaccd5b4bbdc2a35453585b5637b2f8588ac","522103f1848b40621c5d48471d9784c8174ca060555891ace6d2b03c58eece946b1a9121020ee5d32b54d429c152fdc7b1db84f2074b0564d35400d89d11870f9273ec140c52ae","76a914f4fa1cc7de742d135ea82c17adf0bb9cf5f4fb8388ac"],"ed47705334f4643892ca46396eb3f4196a5e30880589e4009ef38eae895d4a13","0afbc2920af1b027f31f87b592276eb4c32094bb4d3697021b4c6380","b6d98692cec5145f67585f3434ec3c2b3030182e1cb3ec58b855c5c164dfaaa3","Tx pays to empty output script"],
[180480,"00000000fd3ceb2404ff07a785c7fdcc76619edc8ed61bd25134eaa22084366a","020000006058aa080a655aa991a444bd7d1f2defd9a3bbe68aabb69030cf3b4e00000000d2e826bfd7ef0beaa891a7eedbc92cd6a544a6cb61c7bdaa436762eb2123ef9790f5f552ffff001d0002c90f0501000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0300c102024608062f503253482fffffffff01c0c6072a01000000232102e769e60137a4df6b0df8ebd387cca44c4c57ae74cc0114a8e8317c8f3bfd85e9ac00000000010000000381a0802911a01ffb025c4dea0bc77963e8c1bb46313b71164c53f72f37fe5248010000000151ffffffffc904b267833d215e2128bd9575242232ac2bc311550c7fc1f0ef6f264b40d14c010000000151ffffffffdf0915666649dba81886519c531649b7b02180b4af67d6885e871299e9d5f775000000000151ffffffff0180817dcb00000000232103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba4ac0000000001000000018da38b434fba82d66052af74fc5e4e94301b114d9bc03f819dc876398404c8b4010000006c493046022100fe738b7580dc5fb5168e51fc61b5aed211125eb71068031009a22d9bbad752c5022100be5086baa384d40bcab0fa586e4f728397388d86e18b66cc417dc4f7fa4f9878012103f233299455134caa2687bdf15cb0becdfb03bd0ff2ff38e65ec6b7834295c34fffffffff022ebc1400000000001976a9147779b7fba1c1e06b717069b80ca170e8b04458a488ac9879c40f000000001976a9142a0307cd925dbb66b534c4db33003dd18c57015788ac0000000001000000026139a62e3422a602de36c873a225c1d3ca5aeee598539ceecb9f0dc8d1ad0f83010000006b483045022100ad9f32b4a0a2ddc19b5a74eba78123e57616f1b3cfd72ce68c03ea35a3dda1f002200dbd22aa6da17213df5e70dfc3b2611d40f70c98ed9626aa5e2cde9d97461f0a012103ddb295d2f1e8319187738fb4b230fdd9aa29d0e01647f69f6d770b9ab24eea90ffffffff983c82c87cf020040d671956525014d5c2b28c6d948c85e1a522362c0059eeae010000006b4830450221009ca544274c786d30a5d5d25e17759201ea16d3aedddf0b9e9721246f7ef6b32e02202cfa5564b6e87dfd9fd98957820e4d4e6238baeb0f65fe305d91506bb13f5f4f012103c99113deac0d5d044e3ac0346abc02501542af8c8d3759f1382c72ff84e704f7ffffffff02c0c62d00000000001976a914ae19d27efe12f5a886dc79af37ad6805db6f922d88ac70ce2000000000001976a9143b8d051d37a07ea1042067e93efe63dbf73920b988ac000000000100000002be566e8cd9933f0c75c4a82c027f7d0c544d5c101d0607ef6ae5d07b98e7f1dc000000006b483045022036a8cdfd5ea7ebc06c2bfb6e4f942bbf9a1caeded41680d11a3a9f5d8284abad022100cacb92a5be3f39e8bc14db1710910ef7b395fa1e18f45d41c28d914fcdde33be012102bf59abf110b5131fae0a3ce1ec379329b4c896a6ae5d443edb68529cc2bc7816ffffffff96cf67645b76ceb23fe922874847456a15feee1655082ff32d25a6bf2c0dfc90000000006a47304402203471ca2001784a5ac0abab583581f2613523da47ec5f53df833c117b5abd81500220618a2847723d57324f2984678db556dbca1a72230fc7e39df04c2239942ba942012102925c9794fd7bb9f8b29e207d5fc491b1150135a21f505041858889fa4edf436fffffffff026c840f00000000001976a914797fb8777d7991d8284d88bfd421ce520f0f843188ac00ca9a3b000000001976a9146d10f3f592699265d10b106eda37c3ce793f7a8588ac00000000",["","","","76a9142903b138c24be9e070b3e73ec495d77a204615e788ac","76a91433a1941fd9a37b9821d376f5a51bd4b52fa50e2888ac","76a914e4374e8155d0865742ca12b8d4d14d41b57d682f88ac","76a914001fa7459a6cfc64bdc178ba7e7a21603bb2568f88ac","76a914f6039952bc2b307aeec5371bfb96b66078ec17f688ac"],"d34ef98386f413769502808d4bac5f20f8dfd5bffc9eedafaa71de0eb1f01489","0db414c859a07e8205876354a210a75042d0463404913d61a8e068e58a3ae2aa080026","c582d51c0ca365e3fcf36c51cb646d7f83a67e867cb4743fd2128e3e022b700c","Tx spends from empty output script"],
[926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"8f13b9a9c85611635b47906c3053ac53cfcec7211455d4cb0d63dc9acc13d472","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","546c574a0472144bcaf9b6aeabf26372ad87c7af7d1ee0dbfae5e099abeae49c","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"],
[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"fe4d230dbb0f4fec9bed23a5283e08baf996e3f32b93f52c7de1f641ddfd04ad","010c0b40","0965a544743bbfa36f254446e75630c09404b3d164a261892372977538928ed5","Coinbase tx has unparseable output script"],
[1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"31d66d516a9eda7de865df29f6ef6cb8e4bf9309e5dac899968a9a62a5df61e3","0385acb4f0fe889ef0","4e6d564c2a2452065c205dd7eb2791124e0c4e0dbb064c410c24968572589dec","Includes witness data"],
[1414221,"0000000000000027b2b3b3381f114f674f481544ff2be37ae3788d7e078383b1","000000204ea88307a7959d8207968f152bedca5a93aefab253f1fb2cfb032a400000000070cebb14ec6dbc27a9dfd066d9849a4d3bac5f674665f73a5fe1de01a022a0c851fda85bf05f4c19a779d1450102000000010000000000000000000000000000000000000000000000000000000000000000ffffffff18034d94154d696e6572476174653030310d000000f238f401ffffffff01c817a804000000000000000000",[],"5e5e12d90693c8e936f01847859404c67482439681928353ca1296982042864e","00","021e8882ef5a0ed932edeebbecfeda1d7ce528ec7b3daa27641acf1189d7b5dc","Empty data"]
]
================================================
FILE: bip-0158.mediawiki
================================================
== Abstract ==
This BIP describes a structure for compact filters on block data, for use in the
BIP 157 light client protocolbip-0157.mediawiki. The filter
construction proposed is an alternative to Bloom filters, as used in BIP 37,
that minimizes filter size by using Golomb-Rice coding for compression. This
document specifies one initial filter type based on this construction that
enables basic wallets and applications with more advanced smart contracts.
== Motivation ==
[[bip-0157.mediawiki|BIP 157]] defines a light client protocol based on
deterministic filters of block content. The filters are designed to
minimize the expected bandwidth consumed by light clients, downloading filters
and full blocks. This document defines the initial filter type ''basic''
that is designed to reduce the filter size for regular wallets.
== Definitions ==
[]byte represents a vector of bytes.
[N]byte represents a fixed-size byte array with length N.
''CompactSize'' is a compact encoding of unsigned integers used in the Bitcoin
P2P protocol.
''Bit streams'' are readable and writable streams of individual bits. The
following functions are used in the pseudocode in this document:
* new_bit_stream instantiates a new writable bit stream
* new_bit_stream(vector) instantiates a new bit stream reading data from vector
* write_bit(stream, b) appends the bit b to the end of the stream
* read_bit(stream) reads the next available bit from the stream
* write_bits_big_endian(stream, n, k) appends the k least significant bits of integer n to the end of the stream in big-endian bit order
* read_bits_big_endian(stream, k) reads the next available k bits from the stream and interprets them as the least significant bits of a big-endian integer
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
interpreted as described in RFC 2119.
== Specification ==
=== Golomb-Coded Sets ===
For each block, compact filters are derived containing sets of items associated
with the block (eg. addresses sent to, outpoints spent, etc.). A set of such
data objects is compressed into a probabilistic structure called a
''Golomb-coded set'' (GCS), which matches all items in the set with probability
1, and matches other items with probability 1/M for some
integer parameter M. The encoding is also parameterized by
P, the bit length of the remainder code. Each filter defined
specifies values for P and M.
At a high level, a GCS is constructed from a set of N items by:
# hashing all items to 64-bit integers in the range [0, N * M)
# sorting the hashed values in ascending order
# computing the differences between each value and the previous one
# writing the differences sequentially, compressed with Golomb-Rice coding
The following sections describe each step in greater detail.
==== Hashing Data Objects ====
The first step in the filter construction is hashing the variable-sized raw
items in the set to the range [0, F), where F = N *
M. Customarily, M is set to 2^P. However, if
one is able to select both Parameters independently, then more optimal values
can be
selectedhttps://gist.github.com/sipa/576d5f09c3b86c3b1b75598d799fc845.
Set membership queries against the hash outputs will have a false positive rate
of 1 / M. To avoid integer overflow, the number of items N
MUST be <2^32 and M MUST be <2^32.
The items are first passed through the pseudorandom function ''SipHash'', which
takes a 128-bit key k and a variable-sized byte vector and produces
a uniformly random 64-bit output. Implementations of this BIP MUST use the
SipHash parameters c = 2 and d = 4.
The 64-bit SipHash outputs are then mapped uniformly over the desired range by
multiplying with F and taking the top 64 bits of the 128-bit result. This
algorithm is a faster alternative to modulo reduction, as it avoids the
expensive division
operationhttps://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/.
Note that care must be taken when implementing this reduction to ensure the
upper 64 bits of the integer multiplication are not truncated; certain
architectures and high level languages may require code that decomposes the
64-bit multiplication into four 32-bit multiplications and recombines into the
result.
hash_to_range(item: []byte, F: uint64, k: [16]byte) -> uint64:
return (siphash(k, item) * F) >> 64
hashed_set_construct(raw_items: [][]byte, k: [16]byte, M: uint) -> []uint64:
let N = len(raw_items)
let F = N * M
let set_items = []
for item in raw_items:
let set_value = hash_to_range(item, F, k)
set_items.append(set_value)
return set_items
==== Golomb-Rice Coding ====
Instead of writing the items in the hashed set directly to the filter, greater
compression is achieved by only writing the differences between successive
items in sorted order. Since the items are distributed uniformly, it can be
shown that the differences resemble a geometric
distributionhttps://en.wikipedia.org/wiki/Geometric_distribution.
''Golomb-Rice''
''coding''https://en.wikipedia.org/wiki/Golomb_coding#Rice_coding
is a technique that optimally compresses geometrically distributed values.
With Golomb-Rice, a value is split into a quotient and remainder modulo
2^P, which are encoded separately. The quotient q is
encoded as ''unary'', with a string of q 1's followed by one 0. The
remainder r is represented in big-endian by P bits. For example,
this is a table of Golomb-Rice coded values using P=2:
{| class="wikitable"
! n !! (q, r) !! c
|-
| 0 || (0, 0) || 0 00
|-
| 1 || (0, 1) || 0 01
|-
| 2 || (0, 2) || 0 10
|-
| 3 || (0, 3) || 0 11
|-
| 4 || (1, 0) || 10 00
|-
| 5 || (1, 1) || 10 01
|-
| 6 || (1, 2) || 10 10
|-
| 7 || (1, 3) || 10 11
|-
| 8 || (2, 0) || 110 00
|-
| 9 || (2, 1) || 110 01
|}
golomb_encode(stream, x: uint64, P: uint):
let q = x >> P
while q > 0:
write_bit(stream, 1)
q--
write_bit(stream, 0)
write_bits_big_endian(stream, x, P)
golomb_decode(stream, P: uint) -> uint64:
let q = 0
while read_bit(stream) == 1:
q++
let r = read_bits_big_endian(stream, P)
let x = (q << P) + r
return x
==== Set Construction ====
A GCS is constructed from four parameters:
* L, a vector of N raw items
* P, the bit parameter of the Golomb-Rice coding
* M, the inverse of the target false positive rate
* k, the 128-bit key used to randomize the SipHash outputs
The result is a byte vector with a minimum size of N * (P + 1)
bits.
The raw items in L are first hashed to 64-bit unsigned integers as
specified above and sorted. The differences between consecutive values,
hereafter referred to as ''deltas'', are encoded sequentially to a bit stream
with Golomb-Rice coding. Finally, the bit stream is padded with 0's to the
nearest byte boundary and serialized to the output byte vector.
construct_gcs(L: [][]byte, P: uint, k: [16]byte, M: uint) -> []byte:
let set_items = hashed_set_construct(L, k, M)
set_items.sort()
let output_stream = new_bit_stream()
let last_value = 0
for item in set_items:
let delta = item - last_value
golomb_encode(output_stream, delta, P)
last_value = item
return output_stream.bytes()
==== Set Querying/Decompression ====
To check membership of an item in a compressed GCS, one must reconstruct the
hashed set members from the encoded deltas. The procedure to do so is the
reverse of the compression: deltas are decoded one by one and added to a
cumulative sum. Each intermediate sum represents a hashed value in the original
set. The queried item is hashed in the same way as the set members and compared
against the reconstructed values. Note that querying does not require the entire
decompressed set be held in memory at once.
gcs_match(key: [16]byte, compressed_set: []byte, target: []byte, P: uint, N: uint, M: uint) -> bool:
let F = N * M
let target_hash = hash_to_range(target, F, k)
stream = new_bit_stream(compressed_set)
let last_value = 0
loop N times:
let delta = golomb_decode(stream, P)
let set_item = last_value + delta
if set_item == target_hash:
return true
// Since the values in the set are sorted, terminate the search once
// the decoded value exceeds the target.
if set_item > target_hash:
break
last_value = set_item
return false
Some applications may need to check for set intersection instead of membership
of a single item. This can be performed far more efficiently than checking each
item individually by leveraging the sorted structure of the compressed GCS.
First the query elements are all hashed and sorted, then compared in order
against the decompressed GCS contents. See
[[#golomb-coded-set-multi-match|Appendix B]] for pseudocode.
=== Block Filters ===
This BIP defines one initial filter type:
* Basic (0x00)
** M = 784931
** P = 19
==== Contents ====
The basic filter is designed to contain everything that a light client needs to
sync a regular Bitcoin wallet. A basic filter MUST contain exactly the
following items for each transaction in a block:
* The previous output script (the script being spent) for each input, except for the coinbase transaction.
* The scriptPubKey of each output, aside from all OP_RETURN output scripts.
Any "nil" items MUST NOT be included into the final set of filter elements.
We exclude all outputs that start with OP_RETURN in order to allow
filters to easily be committed to in the future via a soft-fork. A likely area
for future commitments is an additional OP_RETURN output in the
coinbase transaction similar to the current witness commitment
https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki. By
excluding all OP_RETURN outputs we avoid a circular dependency
between the commitment, and the item being committed to.
==== Construction ====
The basic type is constructed as Golomb-coded sets with the following
parameters.
The parameter P MUST be set to 19, and the parameter
M MUST be set to 784931. Analysis has shown that if
one is able to select P and M independently, then
setting M=1.497137 * 2^P is close to optimal
https://gist.github.com/sipa/576d5f09c3b86c3b1b75598d799fc845.
Empirical analysis also shows that these parameters minimize the bandwidth
utilized, considering both the expected number of blocks downloaded due to false
positives and the size of the filters themselves.
The parameter k MUST be set to the first 16 bytes of the hash
(in standard little-endian representation) of the block for which the filter is
constructed. This ensures the key is deterministic while still varying from
block to block.
Since the value N is required to decode a GCS, a serialized GCS
includes it as a prefix, written as a CompactSize. Thus, the
complete serialization of a filter is:
* N, encoded as a CompactSize
* The bytes of the compressed filter itself
A zero element filter MUST be written as one byte containing zeroes.
==== Signaling ====
This BIP allocates a new service bit:
{| class="wikitable"
|-
| NODE_COMPACT_FILTERS
| style="white-space: nowrap;" | 1 << 6
| If enabled, the node MUST respond to all BIP 157 messages for filter type 0x00
|}
== Compatibility ==
This block filter construction is not incompatible with existing software,
though it requires implementation of the new filters.
== Acknowledgments ==
We would like to thank bfd (from the bitcoin-dev mailing list) for bringing the
basis of this BIP to our attention, Greg Maxwell for pointing us in the
direction of Golomb-Rice coding and fast range optimization, Pieter Wullie for
his analysis of optimal GCS parameters, and Pedro
Martelletto for writing the initial indexing code for btcd.
We would also like to thank Dave Collins, JJ Jeffrey, and Eric Lombrozo for
useful discussions.
== Reference Implementation ==
Light client: [https://github.com/lightninglabs/neutrino]
Full-node indexing: https://github.com/Roasbeef/btcd/tree/segwit-cbf
Golomb-Rice Coded sets: https://github.com/btcsuite/btcd/tree/master/btcutil/gcs
== Appendix A: Alternatives ==
A number of alternative set encodings were considered before Golomb-coded
sets were settled upon. In this appendix section, we'll list a few of the
alternatives along with our rationale for not pursuing them.
==== Bloom Filters ====
Bloom Filters are perhaps the best known probabilistic data structure for
testing set membership, and were introduced into the Bitcoin protocol with BIP
37. The size of a Bloom filter is larger than the expected size of a GCS with
the same false positive rate, which is the main reason the option was rejected.
==== Cryptographic Accumulators ====
Cryptographic
accumulatorshttps://en.wikipedia.org/wiki/Accumulator_(cryptography)
are a cryptographic data structures that enable (amongst other operations) a one
way membership test. One advantage of accumulators are that they are constant
size, independent of the number of elements inserted into the accumulator.
However, current constructions of cryptographic accumulators require an initial
trusted set up. Additionally, accumulators based on the Strong-RSA Assumption
require mapping set items to prime representatives in the associated group which
can be preemptively expensive.
==== Matrix Based Probabilistic Set Data Structures ====
There exist data structures based on matrix solving which are even more space
efficient compared to Bloom
filtershttps://arxiv.org/pdf/0804.1845.pdf. We instead opted for our
GCS-based filters as they have a much lower implementation complexity and are
easier to understand.
== Appendix B: Pseudocode ==
=== Golomb-Coded Set Multi-Match ===
gcs_match_any(key: [16]byte, compressed_set: []byte, targets: [][]byte, P: uint, N: uint, M: uint) -> bool:
let F = N * M
// Map targets to the same range as the set hashes.
let target_hashes = []
for target in targets:
let target_hash = hash_to_range(target, F, k)
target_hashes.append(target_hash)
// Sort targets so matching can be checked in linear time.
target_hashes.sort()
stream = new_bit_stream(compressed_set)
let value = 0
let target_idx = 0
let target_val = target_hashes[target_idx]
loop N times:
let delta = golomb_decode(stream, P)
value += delta
inner loop:
if target_val == value:
return true
// Move on to the next set value.
else if target_val > value:
break inner loop
// Move on to the next target value.
else if target_val < value:
target_idx++
// If there are no targets left, then there are no matches.
if target_idx == len(targets):
break outer loop
target_val = target_hashes[target_idx]
return false
== Appendix C: Test Vectors ==
Test vectors for basic block filters on five testnet blocks, including the filters and filter headers, can be found [[bip-0158/testnet-19.json|here]]. The code to generate them can be found [[bip-0158/gentestvectors.go|here]].
== References ==
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
================================================
FILE: bip-0159.mediawiki
================================================
BIP: 159
Layer: Peer Services
Title: NODE_NETWORK_LIMITED service bit
Authors: Jonas Schnelli
Status: Deployed
Type: Specification
Assigned: 2017-05-11
License: BSD-2-Clause
== Abstract ==
Define a service bit that allows pruned peers to signal their limited services.
==Motivation==
Pruned peers can offer the same services as traditional peers, except that of serving all historical blocks.
Bitcoin right now only offers the NODE_NETWORK service bit to indicate that a peer can serve
all historical blocks.
# Pruned peers can relay blocks, headers, transactions, and addresses, but they only guarantee serving a minimum number of historical blocks; thus, they should have a way to announce their service(s)
# Peers no longer in initial block download should consider connecting some of their outbound connections to pruned peers, to allow other peers to bootstrap from non-pruned peers
== Specification ==
=== New service bit ===
This BIP proposes a new service bit
{|class="wikitable"
|-
| NODE_NETWORK_LIMITED || bit 10 (0x400) || If signaled, the peer MUST be capable of serving at least the last 288 blocks (~2 days).
|}
Pruned/limited peers MUST NOT set a service bit that signals serving the complete block chain (e.g., NODE_NETWORK). Rationale: nodes that signal serving the complete block chain may also signal NODE_NETWORK_LIMITED.
A safety buffer of 144 blocks to handle chain reorganizations SHOULD be taken into account when connecting to a peer signaling the NODE_NETWORK_LIMITED service bit.
=== Address relay ===
Full nodes following this BIP SHOULD relay address/services (addr message) from peers they would connect to (including peers signaling NODE_NETWORK_LIMITED).
=== Counter-measures for peer fingerprinting ===
Peers may have different prune depths (depending on their configuration, disk space, etc.), which can result in a fingerprinting weakness (finding the prune depth through getdata requests).
Pruned nodes should therefore avoid leaking the prune depth and SHOULD NOT serve blocks deeper than the signaled NODE_NETWORK_LIMITED threshold of 288 blocks.
=== Risks ===
Pruned peers following this BIP may consume more outbound bandwidth.
Light clients (and such) who are not checking the nServiceFlags (service bits) from a relayed addr-message may unwittingly connect to a pruned peer and ask for (filtered) blocks at a depth below the peer’s pruned depth. Light clients should therefore check the service bits and either (1) connect to peers signaling NODE_NETWORK_LIMITED that preferably do not also signal serving the full block chain, if they only require (filtered) blocks around the tip, or (2) connect to peers signaling serving the full block chain if they need data older than the latest 288 blocks. Light clients obtaining peer IPs through DNS seeds should use the DNS filtering option.
== Compatibility ==
This proposal is backward compatible.
== Reference implementation ==
* https://github.com/bitcoin/bitcoin/pull/11740 (signaling)
* https://github.com/bitcoin/bitcoin/pull/10387 (connection and relay)
== Copyright ==
This BIP is licensed under the 2-clause BSD license.
================================================
FILE: bip-0171.mediawiki
================================================
BIP: 171
Layer: Applications
Title: Currency/exchange rate information API
Authors: Luke Dashjr
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0171
Status: Closed
Type: Specification
Assigned: 2017-03-04
License: BSD-2-Clause
==Abstract==
A common interface for requesting currency exchange rate information from a server.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Specification==
Four requests are defined, which are all made by a GET request to a common URI with parameters encoded in application/x-www-form-urlencoded format.
All matching parameters may be specified with multiple comma-separated values, which are to be interpreted as "any of these".
Each result is always in JSON format, with a line-feed (never a carriage-return) separating multiple results.
Authentication for subscription-based services MAY be supported using standard HTTP authentication.
It is recommended to use TLS (HTTPS) and/or Linked Data Signatures, so that MITM attackers cannot deceive the client.
To be BIP 171 compatible, servers MUST support at least one currency-pair compared to XBT.
All inquiries for bitcoin amounts MUST be specified in XBT, even if the presentation to the end user is in another unit.
(FIXME: or should this be satoshis?)
Currency-pair tokens are arbitrary Strings no longer than 255 characters, which may include any ASCII [https://tools.ietf.org/html/rfc3986#section-2.3 RFC 3986 unreserved characters] (ie, alphanumerics and the hyphen, underscore, period, and tilde symbols).
Currency code(s) used herein are defined as such:
* All ISO 4217 codes are valid currency codes.
* XBT is defined as 100000000 satoshis (commonly known as 1 BTC).
* Strings longer than 3 characters may be used for currencies without an applicable code. (If a shorter code is desired despite this, it may be padded with space(s) to the left until it is 4 characters. Software MAY strip these spaces.)
Rate is defined as the amount of quote-currency to be exchanged for one unit of the base-currency.
In other words, 1 baseCurrency = rate quoteCurrency.
===Enumerating supported currency-pair tokens===
Parameters:
* ''mode'' - Always "list" for this request.
* ''quote'' - If provided, the server MAY limit the results to only currency-pairs describing a currency with the given currency code(s).
* ''base'' - If provided, the server MAY limit the results to only currency-pairs describing currency rates compared to the given currency code(s).
* ''locale'' - If provided, the server MAY limit the results to only currency-pairs supporting the given Unicode CLDR locale(s).
Each currency-pair will receive a separate result, a JSON Object, with the following information:
* ''cp'' - The currency-pair token.
* ''quote'' - The currency code for the quote currency.
* ''base'' - The currency code for the base currency.
* ''locale'' - If provided, a String with the applicable Unicode CLDR locale.
* ''desc'' - Optional description. For example, it could be "Based on Florida BTM prices." or any other short String that provides information useful to the user. SHOULD be shorter than 45 characters.
* ''signature'' - Optional. May be used for Linked Data Signatures.
Example:
Request: http://api.example.tld/?mode=list"e=USD&base=XBT&locale=en_US,en_GB
Result:
{"cp":"XBTUSD-ver4", "quote":"USD", "base": "XBT", "locale": "en_US", "desc": "Smoothed averages"}
{"cp":"2", "quote":"USD", "base": "XBT", "locale": "en_US", "desc": "Updated per-trade"}
{"cp":"XBTUSD-european", "quote":"USD", "base": "XBT", "locale": "en_GB"}
===Currency-pair information===
Parameters:
* ''mode'' - Always "info" for this request.
* ''cp'' - Currency pair(s) for which information is requested.
Each currency-pair will receive a separate result, a JSON Object, with the following information:
* ''cp'' - The currency-pair token.
* ''quote'' - The currency code for the quote currency.
* ''base'' - The currency code for the base currency.
* ''locale'' - If provided, a String with the applicable Unicode CLDR locale.
* ''desc'' - Optional description. For example, it could be "Based on Florida BTM prices." or any other short String that provides information useful to the user. SHOULD be shorter than 45 characters.
* ''longdesc'' - Optional description, but may be longer and include newlines.
* ''symbol'' - An Array of prefix and suffix for the quote currency. Each may be either a fixed String, an Array of two Strings (negative and positive), or null. Any positive or negative symbols must be included in this prefix/suffix; it MUST NOT be implied otherwise.
* ''digits'' - The type of digits to use for the quote currency's numbers. "arabic" should be used for common 0-9 digits.
* ''grouping'' - An Array alternating between Numbers representing a series of digits, and Strings used as delimiters. If terminated by a zero, the final grouping is to be repeated continually. For example, the common US locale thousands grouping would be [3, ",", 0]
* ''fraction_sep'' - A String to be placed between whole numbers and a fractional amount.
* ''fraction_digits'' - Array of absolute minimum (even for whole numbers) number of fractional digits, minimum fractional digits when a fraction exists, and maximum number of fractional digits when absolute precision is not demanded (below which is to be rounded in an implementation-dependent manner).
* ''minpoll'' - A Number of seconds indicating a minimum time between polls to the server. Clients should be prudent about not polling too often, even if this number is low.
* ''longpoll'' - If provided and true, indicates longpolling is supported by the server.
* ''history'' - If provided, indicates the server has historical records going back no earlier than the POSIX timestamp provided as a value.
* ''archive'' - If provided, indicates the server no longer has current rates, and has no historical rates more recent than the POSIX timestamp provided as a value.
* ''signature'' - Optional. May be used for Linked Data Signatures.
Example:
Request: http://api.example.tld/?mode=info&cp=XBTUSD-ver4,2
Result:
{"cp":"XBTUSD-ver4", "quote":"USD", "base": "XBT", "locale": "en_US", "desc": "Smoothed averages", "longdesc": "USD price quotes as compared to Bitcoin value\n\nRecommended for casual usage", "symbol": [["-$", "$"], null], "digits": "arabic", "grouping": [3, ",", 0], "fraction_sep": ".", "fraction_digits": [0, 2, 2], "minpoll": 300, "longpoll": true, "history": 1457231416}
{"cp":"2", "quote":"USD", "base": "XBT", "locale": "en_US", "desc": "Updated per-trade", "longdesc": "Maximum precision USD price quotes as compared to Bitcoin value", "symbol": [["-$", "$"], null], "digits": "arabic", "grouping": [3, ",", 0], "fraction_sep": ".", "fraction_digits": [0, 2, 2], "minpoll": 3600, "longpoll": false, "history": 1467458333.1225}
===Current exchange rate===
Parameters:
* ''mode'' - Always "rate" for this request.
* ''cp'' - Currency pair(s) for which rate is requested.
* ''type'' - Type of exchange rate data being requested. May be "high", "low", "average", "typical", or any other arbitrary name. If omitted, the server may provide any rates it deems appropriate.
* ''minrate'', ''maxrate'' - If specified, indicates this request is a longpoll. The server should not send a response until the rate(s) fall below or above (respectively) the provided value.
* ''nonce'' - If specified, the server SHOULD return it in each result.
Each currency-pair receives a separate result (a JSON Object) with all requested rate types:
* ''cp'' - The currency-pair token.
* ''time'' - The time (as a POSIX timestamp) the rate information is applicable to (should be approximately the request time).
* ''rates'' - A JSON Object with each rate type provided as a key, and a Number as the value specifying the rate.
* ''nonce'' - Only if the request specified a nonce, the server SHOULD include it here as a JSON String.
* ''signature'' - Optional. May be used for Linked Data Signatures.
Example:
Request: http://api.example.tld/?mode=rate&cp=XBTUSD-ver4,2&type=typical,high
Result:
{"cp":"XBTUSD-ver4", "time": 1488767410.5463133, "rates": {"typical": 1349.332215, "high": 1351.2}}
{"cp":"2", "time": 1488767410, "rates": {"typical": 1350.111332}}
===Historical exchange rates===
Parameters:
* ''mode'' - Always "history" for this request.
* ''cp'' - Currency pair(s) for which rate is requested.
* ''type'' - Type of exchange rate data being requested. May be "high", "low", "average", "typical", or any other arbitrary name. If omitted, the server may provide any rates it deems appropriate.
* ''from'' - POSIX timestamp the results should begin with.
* ''to'' - POSIX timestamp the results should end with. If omitted, the present time shall be used.
* ''nearest'' - If provided and true, indicates that only the nearest timestamp to "from" must be returned, and a range is not desired. ("to" should be omitted in this case.)
* ''ratedelta'', ''timedelta'' - If specified, the server may omit data where the rate or time has not changed since the last provided rate and time. If both are provided, either a significant rate change OR time change should trigger a new record in the results.
A result is provided for each currency-pair and timestamp record, in the same format as the current exchange rate request.
Records MUST be provided in chronological order, but only within the scope of the applicable currency-pair (ie, it is okay to send the full history for one currency-pair, and then the full history for the next; or to intermix them out of any given order).
If there is no exact record for the times specified by "from" and/or "to", a single record before "from" and/or after "to" should also be included.
This is not necessary when only the nearest record is requested, or when "to" is omitted (ie, ending at the most recent record).
Example:
Request: http://api.example.tld/?mode=history&cp=XBTUSD-ver4,2&type=typical&ratedelta=0.1&timedelta=10&from=1488759998&to=1488760090
Result:
{"cp":"XBTUSD-ver4", "time": 1488760000, "rates": {"typical": 1300}}
{"cp":"XBTUSD-ver4", "time": 1488760010, "rates": {"typical": 1301.1}}
{"cp":"XBTUSD-ver4", "time": 1488760020, "rates": {"typical": 1320}}
{"cp":"XBTUSD-ver4", "time": 1488760030, "rates": {"typical": 1305}}
{"cp":"2", "time": 1488760000.1, "rates": {"typical": 1300}}
{"cp":"2", "time": 1488760010.2, "rates": {"typical": 1301.1}}
{"cp":"2", "time": 1488760020.2, "rates": {"typical": 1320.111332}}
{"cp":"2", "time": 1488760031, "rates": {"typical": 1305.222311}}
{"cp":"XBTUSD-ver4", "time": 1488760040, "rates": {"typical": 1303.33}}
{"cp":"2", "time": 1488760042, "rates": {"typical": 1303.33}}
{"cp":"XBTUSD-ver4", "time": 1488760050, "rates": {"typical": 1305}}
{"cp":"2", "time": 1488760052, "rates": {"typical": 1307}}
{"cp":"XBTUSD-ver4", "time": 1488760060, "rates": {"typical": 1309}}
{"cp":"XBTUSD-ver4", "time": 1488760072, "rates": {"typical": 1308}}
{"cp":"2", "time": 1488760062, "rates": {"typical": 1309.55555555}}
{"cp":"2", "time": 1488760072, "rates": {"typical": 1308}}
{"cp":"XBTUSD-ver4", "time": 1488760082, "rates": {"typical": 1309}}
{"cp":"2", "time": 1488760082, "rates": {"typical": 1309.1}}
==Motivation==
End users often desire to see fiat currency information in their Bitcoin wallet software.
Due to the nature of Bitcoin, there is inherently no authoritative source for exchange rates.
There are many independent providers of such information, but they all use different formats for providing it, so wallet software is currently forced to implement dedicated code for each provider.
By providing a standard interface for retrieving this information, wallets (and other software) and service providers can implement it once, and become immediately interoperable with all other compatible implementations.
==Rationale==
Why are multiple results separated by a line-feed rather than using a JSON Array?
* Clients ought to cache historical data, and using a line-feed format allows them to simply append to a cache file.
* Parsing JSON typically requires the entire data parsed together as a single memory object. Using simple lines to separate results, however, allows parsing a single result at a time.
What if long descriptions require line and paragraph breaks?
* Clients should word-wrap long lines, and JSON escapes newlines as "\n" which can be used doubly ("\n\n") for paragraph breaks.
==Backwards compatibility==
While this new standard is adopted, software and providers can continue to use and provide their current formats until they are no longer needed.
==Reference implementation==
TODO
==See also==
* [https://w3c-dvcg.github.io/ld-signatures/ Draft W3c Linked Data Signatures specification]
================================================
FILE: bip-0172.mediawiki
================================================
== Abstract ==
This BIP proposes to formally define and standardize Bitcoin's smallest indivisible unit (1/100,000,000 of a bitcoin) as "satoshi" (singular) or "satoshis" (plural), with "sats" as the standard abbreviated form. This standardization aims to improve clarity in communication, user interfaces, documentation, and development across the Bitcoin ecosystem.
== Motivation ==
As Bitcoin adoption grows, the need for a clear, standardized terminology for its subunits becomes increasingly important. Currently, there are various terms used to refer to Bitcoin's smallest unit (1/100,000,000 BTC), including "satoshi", "satoshis", "sat", "sats" and sometimes simply expressed as decimal values of bitcoin (0.00000001 BTC).
This lack of standardization can lead to:
# Confusion for newcomers to the Bitcoin ecosystem
# Inconsistent user experiences across different applications and services
# Ambiguity in technical documentation and discussions
# Potential errors in development and implementation of Bitcoin-related software
By formally establishing "satoshi"/"satoshis" as the standard term with "sats" as the recognized abbreviation, we can improve clarity and consistency throughout the ecosystem.
== Specification ==
This BIP formally defines:
# The term "satoshi" (singular) or "satoshis" (plural) shall be the standard term for 1/100,000,000 of a bitcoin (0.00000001 BTC).
# The abbreviation "sat" (singular) or "sats" (plural) shall be the standard short form for "satoshi"/"satoshis".
# The relationship between units shall be expressed as:
#* 1 bitcoin (BTC) = 100,000,000 satoshis
#* 1 satoshi = 0.00000001 bitcoin
# The terms "satoshi" and "sats" are not proper nouns when referring to the unit of currency and should not be capitalized except at the beginning of sentences or in titles.
# Bitcoin-related applications, services, documentation, and communications are encouraged to use these standardized terms to promote consistency across the ecosystem.
== Accessibility Considerations ==
To ensure clarity and inclusiveness in user interfaces and assistive technologies, the following recommendations apply:
# Pronunciation:
#* The abbreviation "sat" should be pronounced as /sæt/, and "sats" (plural) should be pronounced as /sæts/ (rhyming with "cats") by screen readers and voice assistants.
#* "Satoshi" (singular) is pronounced /səˈtoʊʃi/. "Satoshis" (plural) is pronounced /səˈtoʊʃiz/.
# Singular vs. Plural: Preserve correct pluralization when reading amounts:
#* "1 sat" should be read as "one satoshi" (/wʌn səˈtoʊʃi/)
#* "100 sats" should be read as "one hundred satoshis" (/wʌn ˈhʌndrəd səˈtoʊʃiz/)
# Readable Formats:
#* Prefer full terms in accessibility modes (e.g., "satoshis" instead of "sats")
#* Group digits to assist parsing (e.g., "12,345" instead of "12345")
# Contextual Labels:
#* Interfaces should use clear alt-text or aria-labels such as: alt="Transaction fee: 14 satoshis per virtual byte"
#* This enables screen readers and other assistive technologies to accurately interpret and communicate the content
== Rationale ==
Satoshi Nakamoto, the creator of Bitcoin, established that one bitcoin would be divisible to eight decimal places, creating 100,000,000 units per bitcoin. The community has organically adopted the term "satoshi" to refer to this smallest unit.
As Bitcoin's value has increased, expressing smaller values in fractional bitcoins has become increasingly unwieldy (e.g., 0.00000546 BTC). Using satoshis as the unit of account for smaller values (e.g., 546 sats) is more intuitive and less error-prone for humans.
The term "satoshi" and its abbreviation "sats" have already gained widespread adoption within the Bitcoin community. This BIP seeks to formalize this existing convention rather than introduce new terminology.
=== Analogous to Traditional Currency Systems ===
The proposed bitcoin/satoshi (or BTC/sat) standard follows the established pattern of major world currencies, which typically have a primary unit and a smaller subunit. Most notably, the United States dollar—the world's primary reserve currency—uses dollars and cents in a two-tier denomination system. This familiar dollars/cents model has proven effective and intuitive for everyday transactions across different scales.
The bitcoin/satoshi system mirrors this approach while accounting for Bitcoin's higher divisibility requirements. Furthermore, the phonetic similarity between "sat" and "cent" creates an intuitive bridge for newcomers to understand Bitcoin's smallest unit, making the learning curve less steep for those familiar with traditional currency systems. This natural familiarity leverages existing mental models of how currency denominations work.
=== Comparison with Alternative Approaches ===
Two notable proposals related to Bitcoin denomination have been put forward:
Our proposal represents a minimally disruptive approach to standardization, formalizing existing common practice rather than introducing new terms (BIP-176) or redefining existing ones (BIP-177).
==== BIP-176: Bits Denomination ====
BIP-176 proposes using "bits" as a standard term for 100 satoshis (or 0.000001 BTC). While this proposal has merit for creating a middle-ground denomination that avoids small decimal places when bitcoin's value is high, our approach differs in that it:
* Formalizes existing widely adopted terminology rather than introducing or prioritizing a different unit
* Focuses on the fundamental base unit that cannot be subdivided further within the Bitcoin protocol
* Maintains the simplicity of a two-tier system (bitcoin and satoshi) rather than adding a third tier
==== BIP-177: Redefine Bitcoin's Base Unit ====
BIP-177 takes a more radical approach by proposing to redefine the term "bitcoin" to refer to what is currently called a "satoshi" (1/100,000,000 of the current bitcoin). While this proposal aims to eliminate decimal points and simplify mental calculations, our approach differs in that it:
* Preserves the established meaning of "bitcoin" which has global recognition and avoids potentially confusing redefinition
* Maintains compatibility with existing systems, documentation, and user understanding
* Achieves similar clarity benefits through standardization without requiring a fundamental redefinition of terms
== Backwards Compatibility ==
This proposal does not affect the technical operation of Bitcoin or its protocol. It is purely a standardization of terminology for human communication and user interfaces.
Existing applications that use other terms or conventions can continue to operate but are encouraged to adopt the standardized terms to improve overall ecosystem clarity.
== Copyright ==
This BIP is licensed under the BSD 2-clause license.
== Reference Implementation ==
Not applicable as this is an Informational BIP that standardizes terminology rather than implementing technical changes.
== Examples ==
Before standardization, various formats might be used:
* 0.00000100 BTC
* 100 satoshi
* 100 satoshis
* 100 sat
* 100 sats
After standardization, the preferred formats would be:
* 100 satoshis (formal)
* 100 sats (abbreviated)
== Acknowledgements ==
Thanks to the entire Bitcoin community who has organically adopted the terms "satoshi" and "sats" over the years. If anyone can point to early references of the term being used in this way please leave a comment so we can amend this BIP to acknowledge it.
== References ==
# Satoshi Nakamoto. "Bitcoin: A Peer-to-Peer Electronic Cash System" (2008)
# BIP-176: Bits Denomination (Jimmy Song)
== Glossary ==
* BTC: The current universal ticker symbol for bitcoin, the cryptocurrency.
* Satoshi: The smallest unit of bitcoin, equal to 0.00000001 BTC.
* Sats: Abbreviation for "satoshis".
================================================
FILE: bip-0173.mediawiki
================================================
==Introduction==
===Abstract===
This document proposes a checksummed base32 format, "Bech32", and a standard for native segregated witness output addresses using it.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
For most of its history, Bitcoin has relied on base58 addresses with a
truncated double-SHA256 checksum. They were part of the original
software and their scope was extended in
[https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki BIP13]
for Pay-to-script-hash
([https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki P2SH]).
However, both the character set and the checksum algorithm have limitations:
* Base58 needs a lot of space in QR codes, as it cannot use the ''alphanumeric mode''.
* The mixed case in base58 makes it inconvenient to reliably write down, type on mobile keyboards, or read out loud.
* The double SHA256 checksum is slow and has no error-detection guarantees.
* Most of the research on error-detecting codes only applies to character-set sizes that are a [https://en.wikipedia.org/wiki/Prime_power prime power], which 58 is not.
* Base58 decoding is complicated and relatively slow.
Included in the Segregated Witness proposal are a new class of outputs
(witness programs, see
[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]),
and two instances of it ("P2WPKH" and "P2WSH", see
[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143]).
Their functionality is available indirectly to older clients by embedding in P2SH
outputs, but for optimal efficiency and security it is best to use it
directly. In this document we propose a new address format for native
witness outputs (current and future versions).
This replaces
[https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki BIP142],
and was previously discussed
[https://bitcoincore.org/logs/2016-05-zurich-meeting-notes.html#base32 here] (summarized
[https://bitcoincore.org/en/meetings/2016/05/20/#error-correcting-codes-for-future-address-types here]).
===Examples===
All examples use public key
0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798.
The P2WSH examples use key OP_CHECKSIG as script.
* Mainnet P2WPKH: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
* Testnet P2WPKH: tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx
* Mainnet P2WSH: bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3
* Testnet P2WSH: tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7
==Specification==
We first describe the general checksummed base32'''Why use base32 at all?''' The lack of mixed case makes it more
efficient to read out loud or to put into QR codes. It does come with a 15% length
increase, but that does not matter when copy-pasting addresses. format called
''Bech32'' and then define Segregated Witness addresses using it.
===Bech32===
A Bech32'''Why call it Bech32?''' "Bech" contains the characters BCH (the error
detection algorithm used) and sounds a bit like "base". string is at most 90 characters long and consists of:
* The '''human-readable part''', which is intended to convey the type of data, or anything else that is relevant to the reader. This part MUST contain 1 to 83 US-ASCII characters, with each character having a value in the range [33-126]. HRP validity may be further restricted by specific applications.
* The '''separator''', which is always "1". In case "1" is allowed inside the human-readable part, the last one in the string is the separator'''Why include a separator in addresses?''' That way the human-readable
part is unambiguously separated from the data part, avoiding potential
collisions with other human-readable parts that share a prefix. It also
allows us to avoid having character-set restrictions on the human-readable part. The
separator is ''1'' because using a non-alphanumeric character would
complicate copy-pasting of addresses (with no double-click selection in
several applications). Therefore an alphanumeric character outside the normal character set
was chosen..
* The '''data part''', which is at least 6 characters long and only consists of alphanumeric characters excluding "1", "b", "i", and "o"'''Why not use an existing character set like [http://www.faqs.org/rfcs/rfc3548.html RFC3548] or [https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt z-base-32]'''?
The character set is chosen to minimize ambiguity according to
[https://hissa.nist.gov/~black/GTLD/ this] visual similarity data, and
the ordering is chosen to minimize the number of pairs of similar
characters (according to the same data) that differ in more than 1 bit.
As the checksum is chosen to maximize detection capabilities for low
numbers of bit errors, this choice improves its performance under some
error models..
{| class="wikitable"
|-
!
!0
!1
!2
!3
!4
!5
!6
!7
|-
!+0
|q||p||z||r||y||9||x||8
|-
!+8
|g||f||2||t||v||d||w||0
|-
!+16
|s||3||j||n||5||4||k||h
|-
!+24
|c||e||6||m||u||a||7||l
|}
'''Checksum'''
The last six characters of the data part form a checksum and contain no
information. Valid strings MUST pass the criteria for validity specified
by the Python3 code snippet below. The function
bech32_verify_checksum must return true when its arguments are:
* hrp: the human-readable part as a string
* data: the data part as a list of integers representing the characters after conversion using the table above
def bech32_polymod(values):
GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
chk = 1
for v in values:
b = (chk >> 25)
chk = (chk & 0x1ffffff) << 5 ^ v
for i in range(5):
chk ^= GEN[i] if ((b >> i) & 1) else 0
return chk
def bech32_hrp_expand(s):
return [ord(x) >> 5 for x in s] + [0] + [ord(x) & 31 for x in s]
def bech32_verify_checksum(hrp, data):
return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1
This implements a [https://en.wikipedia.org/wiki/BCH_code BCH code] that
guarantees detection of '''any error affecting at most 4 characters'''
and has less than a 1 in 109 chance of failing to detect more
errors. More details about the properties can be found in the
Checksum Design appendix. The human-readable part is processed by first
feeding the higher bits of each character's US-ASCII value into the
checksum calculation followed by a zero and then the lower bits of each'''Why are the high bits of the human-readable part processed first?'''
This results in the actually checksummed data being ''[high hrp] 0 [low hrp] [data]''. This means that under the assumption that errors to the
human readable part only change the low 5 bits (like changing an alphabetical character into another), errors are restricted to the ''[low hrp] [data]''
part, which is at most 89 characters, and thus all error detection properties (see appendix) remain applicable..
To construct a valid checksum given the human-readable part and (non-checksum) values of the data-part characters, the code below can be used:
def bech32_create_checksum(hrp, data):
values = bech32_hrp_expand(hrp) + data
polymod = bech32_polymod(values + [0,0,0,0,0,0]) ^ 1
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
'''Error correction'''
One of the properties of these BCH codes is that they can be used for
error correction. An unfortunate side effect of error correction is that
it erodes error detection: correction changes invalid inputs into valid
inputs, but if more than a few errors were made then the valid input may
not be the correct input. Use of an incorrect but valid input can cause
funds to be lost irrecoverably. Because of this, implementations SHOULD
NOT implement correction beyond potentially suggesting to the user where
in the string an error might be found, without suggesting the correction
to make.
'''Uppercase/lowercase'''
The lowercase form is used when determining a character's value for checksum purposes.
Encoders MUST always output an all lowercase Bech32 string.
If an uppercase version of the encoding result is desired, (e.g.- for presentation purposes, or QR code use),
then an uppercasing procedure can be performed external to the encoding process.
Decoders MUST NOT accept strings where some characters are uppercase and some are lowercase (such strings are referred to as mixed case strings).
For presentation, lowercase is usually preferable, but inside QR codes uppercase SHOULD be used, as those permit the use of
''[http://www.thonky.com/qr-code-tutorial/alphanumeric-mode-encoding alphanumeric mode]'', which is 45% more compact than the normal
''[http://www.thonky.com/qr-code-tutorial/byte-mode-encoding byte mode]''.
===Segwit address format===
A segwit address'''Why not make an address format that is generic for all scriptPubKeys?'''
That would lead to confusion about addresses for
existing scriptPubKey types. Furthermore, if addresses that do not have a one-to-one mapping with scriptPubKeys (such as ECDH-based
addresses) are ever introduced, having a fully generic old address type available would
permit reinterpreting the resulting scriptPubKeys using the old address
format, with lost funds as a result if bitcoins are sent to them. is a Bech32 encoding of:
* The human-readable part "bc"'''Why use 'bc' as human-readable part and not 'btc'?''' 'bc' is shorter. for mainnet, and "tb"'''Why use 'tb' as human-readable part for testnet?''' It was chosen to
be of the same length as the mainnet counterpart (to simplify
implementations' assumptions about lengths), but still be visually
distinct. for testnet.
* The data-part values:
** 1 character (representing 5 bits of data): the witness version
** A conversion of the 2-to-40-byte witness program (as defined by [https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) to base32:
*** Start with the bits of the witness program, most significant bit per byte first.
*** Re-arrange those bits into groups of 5, and pad with zeroes at the end if needed.
*** Translate those bits to characters using the table above.
'''Decoding'''
Software interpreting a segwit address:
* MUST verify that the human-readable part is "bc" for mainnet and "tb" for testnet.
* MUST verify that the first decoded data value (the witness version) is between 0 and 16, inclusive.
* Convert the rest of the data to bytes:
** Translate the values to 5 bits, most significant bit first.
** Re-arrange those bits into groups of 8 bits. Any incomplete group at the end MUST be 4 bits or less, MUST be all zeroes, and is discarded.
** There MUST be between 2 and 40 groups, which are interpreted as the bytes of the witness program.
Decoders SHOULD enforce known-length restrictions on witness programs.
For example, BIP141 specifies ''If the version byte is 0, but the witness
program is neither 20 nor 32 bytes, the script must fail.''
As a result of the previous rules, addresses are always between 14 and 74 characters long, and their length modulo 8 cannot be 0, 3, or 5.
Version 0 witness addresses are always 42 or 62 characters, but implementations MUST allow the use of any version.
Implementations should take special care when converting the address to a
scriptPubkey, where witness version ''n'' is stored as ''OP_n''. OP_0 is
encoded as 0x00, but OP_1 through OP_16 are encoded as 0x51 though 0x60
(81 to 96 in decimal). If a bech32 address is converted to an incorrect
scriptPubKey the result will likely be either unspendable or insecure.
===Compatibility===
Only new software will be able to use these addresses, and only for
receivers with segwit-enabled new software. In all other cases, P2SH or
P2PKH addresses can be used.
==Rationale==
==Reference implementations==
* Reference encoder and decoder:
** [https://github.com/sipa/bech32/tree/master/ref/c For C]
** [https://github.com/sipa/bech32/tree/master/ref/c++ For C++]
** [https://github.com/sipa/bech32/tree/master/ref/javascript For JavaScript]
** [https://github.com/sipa/bech32/tree/master/ref/go For Go]
** [https://github.com/sipa/bech32/tree/master/ref/python For Python]
** [https://github.com/sipa/bech32/tree/master/ref/haskell For Haskell]
** [https://github.com/sipa/bech32/tree/master/ref/ruby For Ruby]
** [https://github.com/sipa/bech32/tree/master/ref/rust For Rust]
* Fancy decoder that localizes errors:
** [https://github.com/sipa/bech32/tree/master/ecc/javascript For JavaScript] ([http://bitcoin.sipa.be/bech32/demo/demo.html demo website])
==Registered Human-readable Prefixes==
SatoshiLabs maintains a full list of registered human-readable parts for other cryptocurrencies:
[https://github.com/satoshilabs/slips/blob/master/slip-0173.md SLIP-0173 : Registered human-readable parts for BIP-0173]
==Appendices==
===Test vectors===
The following strings are valid Bech32:
* A12UEL5L
* a12uel5l
* an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs
* abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw
* 11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j
* split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w
* ?1ezyfcl WARNING: During conversion to US-ASCII some encoders may set unmappable characters to a valid US-ASCII character, such as '?'. For example:
The following string are not valid Bech32 (with reason for invalidity):
* 0x20 + 1nwldj5: HRP character out of range
* 0x7F + 1axkwrx: HRP character out of range
* 0x80 + 1eym55h: HRP character out of range
* an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx: overall max length exceeded
* pzry9x0s0muk: No separator character
* 1pzry9x0s0muk: Empty HRP
* x1b4n0q5v: Invalid data character
* li1dgmt3: Too short checksum
* de1lg7wt + 0xFF: Invalid character in checksum
* A1G7SGD8: checksum calculated with uppercase form of HRP
* 10a06t8: empty HRP
* 1qzzfhee: empty HRP
The following list gives valid segwit addresses and the scriptPubKey that they
translate to in hex.
* BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4: 0014751e76e8199196d454941c45d1b3a323f1433bd6
* tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7: 00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262
* bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx: 5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6
* BC1SW50QA3JX3S: 6002751e
* bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj: 5210751e76e8199196d454941c45d1b3a323
* tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy: 0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433
The following list gives invalid segwit addresses and the reason for
their invalidity.
* tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty: Invalid human-readable part
* bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5: Invalid checksum
* BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2: Invalid witness version
* bc1rw5uspcuh: Invalid program length
* bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90: Invalid program length
* BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P: Invalid program length for witness version 0 (per BIP141)
* tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7: Mixed case
* bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du: zero padding of more than 4 bits
* tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv: Non-zero padding in 8-to-5 conversion
* bc1gmk9yu: Empty data section
===Checksum design===
'''Design choices'''
BCH codes can be constructed over any prime-power alphabet and can be chosen to have a good trade-off between
size and error-detection capabilities. While most work around BCH codes uses a binary alphabet, that is not a requirement.
This makes them more appropriate for our use case than [https://en.wikipedia.org/wiki/Cyclic_redundancy_check CRC codes]. Unlike
[https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction Reed-Solomon codes],
they are not restricted in length to one less than the alphabet size. While they also support efficient error correction,
the implementation of just error detection is very simple.
We pick 6 checksum characters as a trade-off between length of the addresses and the error-detection capabilities, as 6
characters is the lowest number sufficient for a random failure chance below 1 per billion. For the length of data
we're interested in protecting (up to 71 bytes for a potential future 40-byte witness
program), BCH codes can be constructed that guarantee detecting up to 4 errors.
'''Selected properties'''
Many of these codes perform badly when dealing with more errors than they are designed to detect, but not all.
For that reason, we consider codes that are designed to detect only 3 errors as well as 4 errors,
and analyse how well they perform in practice.
The specific code chosen here is the result
of:
* Starting with an exhaustive list of 159605 BCH codes designed to detect 3 or 4 errors up to length 93, 151, 165, 341, 1023, and 1057.
* From those, requiring the detection of 4 errors up to length 71, resulting in 28825 remaining codes.
* From those, choosing the codes with the best worst-case window for 5-character errors, resulting in 310 remaining codes.
* From those, picking the code with the lowest chance for not detecting small numbers of ''bit'' errors.
As a naive search would require over 6.5 * 1019 checksum evaluations, a collision-search approach was used for
analysis. The code can be found [https://github.com/sipa/ezbase32/ here].
'''Properties'''
The following table summarizes the chances for detection failure (as
multiples of 1 in 109).
{| class="wikitable"
|-
!colspan="2" | Window length
!colspan="6" | Number of wrong characters
|-
!Length
!Description
!≤4
!5
!6
!7
!8
!≥9
|-
| 8 || Longest detecting 6 errors || colspan="3" | 0 || 1.127 || 0.909 || n/a
|-
| 18 || Longest detecting 5 errors || colspan="2" | 0 || 0.965 || 0.929 || 0.932 || 0.931
|-
| 19 || Worst case for 6 errors || 0 || 0.093 || 0.972 || 0.928 || colspan="2" | 0.931
|-
| 39 || Length for a P2WPKH address || 0 || 0.756 || 0.935 || 0.932 || colspan="2" | 0.931
|-
| 59 || Length for a P2WSH address || 0 || 0.805 || 0.933 || colspan="3" | 0.931
|-
| 71 || Length for a 40-byte program address || 0 || 0.830 || 0.934 || colspan="3" | 0.931
|-
| 89 || Longest detecting 4 errors || 0 || 0.867 || 0.933 || colspan="3" | 0.931
|}
This means that when 5 changed characters occur randomly distributed in
the 39 characters of a P2WPKH address, there is a chance of
''0.756 per billion'' that it will go undetected. When those 5 changes
occur randomly within a 19-character window, that chance goes down to
''0.093 per billion''. As the number of errors goes up, the chance
converges towards ''1 in 230'' = ''0.931 per billion''.
Even though the chosen code performs reasonably well up to 1023 characters,
other designs are preferable for lengths above 89 characters (excluding the
separator).
==Acknowledgements==
This document is inspired by the [https://rusty.ozlabs.org/?p=578 address proposal] by Rusty Russell, the
[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2014-February/004402.html base32] proposal by Mark Friedenbach, and had input from Luke Dashjr,
Johnson Lau, Eric Lombrozo, Peter Todd, and various other reviewers.
==Disclosures (added 2024)==
Due to an oversight in the design of bech32, this checksum scheme is not always
robust against
[[https://gist.github.com/sipa/a9845b37c1b298a7301c33a04090b2eb|the insertion
and deletion of fewer than 5 consecutive characters]]. Due to this weakness,
[[bip-0350.mediawiki|BIP-350]] proposes using the scheme described in this BIP
only for Native Segwit v0 outputs.
================================================
FILE: bip-0174/build.sh
================================================
#!/bin/bash
pdflatex -output-format=pdf coinjoin-workflow.tex && \
inkscape --with-gui --export-text-to-path \
--export-plain-svg=coinjoin-workflow.svg coinjoin-workflow.pdf && \
pdflatex -output-format=pdf multisig-workflow.tex && \
inkscape --with-gui --export-text-to-path \
--export-plain-svg=multisig-workflow.svg multisig-workflow.pdf && \
echo '"success"'
================================================
FILE: bip-0174/coinjoin-workflow.tex
================================================
% using the PGF/TikZ package with pdflatex
\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
%~ \usepackage[english]{babel}
\usepackage[none]{hyphenat}% prevent hyphenation
\usepackage{lmodern}
\renewcommand*\familydefault{\sfdefault}
\usepackage{tikz}
\usetikzlibrary{shapes,arrows.meta}
\tikzset{>=latex}
\begin{document}
% \sffamily{}
\tikzstyle{block_center} =
[rectangle, draw=black, thick, fill=white,
text width=12em, text centered,
minimum height=5em]
\tikzstyle{block_rounded} = [rectangle,
draw=black, thick, fill=white,
text width=8em, text centered,
minimum height=5em,
rounded corners]
\begin{tikzpicture}[auto]
% outlining the flowchart on a grid
\matrix[column sep=3ex,row sep=3ex]{
\node [block_center] (0alice1)
{Alice creates a PSBT with only her inputs
with UTXOs filled in.\\Sends it to Bob.};
&
\node [block_center] (1bob1)
{Bob adds his inputs and fills in his
UTXOs.};
&
\node [block_center] (2carol1)
{Carol adds her inputs, fills in her
UTXOs, adds signatures, and finalizes her inputs.};
\\
\node [block_rounded] (5alice2)
{Alice extracts the network serialized
transaction and broadcasts it.};
&
\node [block_center] (4alice1)
{Alice signs the transaction, adds her
signatures, and finalizes her inputs.};
&
\node [block_center] (3bob2)
{Bob signs the transaction, adds his
signatures, and finalizes his inputs.};
\\
};% end matrix
% connecting nodes with paths
\draw [ultra thick, draw=black, -{Stealth[length=8pt]}]
(0alice1) edge (1bob1)
(1bob1) edge (2carol1)
(2carol1) edge (3bob2)
(3bob2) edge (4alice1)
(4alice1) edge (5alice2);
\draw [thin, white, -{Stealth[color=black, fill=white, length=8pt]}]
(0alice1) edge (1bob1)
(1bob1) edge (2carol1)
(2carol1) edge (3bob2)
(3bob2) edge (4alice1)
(4alice1) edge (5alice2);
\end{tikzpicture}
\end{document}
================================================
FILE: bip-0174/multisig-workflow.tex
================================================
% using the PGF/TikZ package with pdflatex
\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
%~ \usepackage[english]{babel}
\usepackage[none]{hyphenat}% prevent hyphenation
\usepackage{lmodern}
\renewcommand*\familydefault{\sfdefault}
\usepackage{tikz}
\usetikzlibrary{shapes,arrows.meta}
\tikzset{>=latex}
%\pgfdeclarelayer{bg} % declare background layer
%\pgfsetlayers{bg,main} % set order of layers
\newcommand{\h}{\hspace{1em}}
\begin{document}
% \sffamily{}
\tikzstyle{block_center} =
[rectangle, draw=black, thick, fill=white,
text width=10.5em, text centered,
minimum height=1em]
\tikzstyle{block_rounded} = [rectangle,
draw=black, thick, fill=white,
text width=8em, text centered,
minimum height=5em,
rounded corners]
\begin{tikzpicture}[auto]
% outlining the flowchart on a grid
\matrix[column sep=3ex,row sep=2.5ex]{
\h &
\node [block_center] (R1)
{Alice, Bob and Carol
wish to spend from a
2-of-3 Multisig.};
& \h \\
\h &
\node [block_center] (R2)
{Alice uses a full node
to create a PSBT with
all input UTXOs filled in.};
& \h \\
\h &
\node [block_center] (R3)
{PSBT distributed.};
& \h \\
\node [block_center] (R4C1)
{Alice signs the
PSBT with her wallet.};
&
\node [block_center] (R4C2)
{Bob signs the PSBT
with his SPV wallet.};
&
\node [block_center] (R4C3)
{Carol signs the PSBT
with a completely
offline signing machine.};
\\
%~ \h & \node (blind) & \h \\
\h &
\node [block_center] (R5)
{PSBTs are returned
to Alice.};
& \h \\
\h &
\node [block_center] (R6)
{Alices combines the
PSBTs. All inputs now
have 3 signatures.};
& \h \\
\h &
\node [block_center] (R7)
{Alice finalizes the PSBT
by creating each input's
final scriptSig. One signature
for each input is dropped.};
& \h \\
\h &
\node [block_rounded] (stop)
{Alice extracts the network
serialized transaction and
broadcasts it to the network.};
& \h \\
};% end matrix
% connecting nodes with paths
% \begin{pgfonlayer}{bg}
\draw [ultra thick, draw=black, -{Stealth[length=8pt]}]
(R1) edge (R2)
(R2) edge (R3)
(R3) -| (R4C1)
(R3) edge (R4C2)
(R5) edge (R6)
(R6) edge (R7)
(R7) edge (stop);
\draw [thin, white, -{Stealth[color=black, fill=white, length=8pt]}]
(R1) edge (R2)
(R2) edge (R3)
(R3) -| (R4C1)
(R3) edge (R4C2)
(R5) edge (R6)
(R6) edge (R7)
(R7) edge (stop);
% circumvent missing arrow
\draw [ultra thick, draw=black, -{Stealth[length=8pt]}]
(R4C1) |-+(0,-2.2em)-| (R5)
(R4C2) edge (R5)
(R4C3) |-+(0,-2.2em)-| (R5)
(R3) -| (R4C3);
\draw [thin, white, -{Stealth[color=black, fill=white, length=8pt]}]
(R4C1) |-+(0,-2.2em)-| (R5)
(R4C2) edge (R5)
(R4C3) |-+(0,-2.2em)-| (R5)
(R3) -| (R4C3);
% \end{pgfonlayer}
\end{tikzpicture}
\end{document}
================================================
FILE: bip-0174.mediawiki
================================================
BIP: 174
Layer: Applications
Title: Partially Signed Bitcoin Transaction Format
Authors: Ava Chow
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0174
Status: Deployed
Type: Specification
Assigned: 2017-07-12
License: BSD-2-Clause
==Introduction==
===Abstract===
This document proposes a binary transaction format which contains the information
necessary for a signer to produce signatures for the transaction and holds the
signatures for an input while the input does not have a complete set of signatures.
The signer can be offline as all necessary information will be provided in the
transaction.
The generic format is described here in addition to the specification for version 0
of this format.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
Creating unsigned or partially signed transactions to be passed around to multiple
signers is currently implementation dependent, making it hard for people who use
different wallet software from being able to easily do so. One of the goals of this
document is to create a standard and extensible format that can be used between clients to allow
people to pass around the same transaction to sign and combine their signatures. The
format is also designed to be easily extended for future use which is harder to do
with existing transaction formats.
Signing transactions also requires users to have access to the UTXOs being spent. This transaction
format will allow offline signers such as air-gapped wallets and hardware wallets
to be able to sign transactions without needing direct access to the UTXO set and without
risk of being defrauded.
==Specification==
The Partially Signed Bitcoin Transaction (PSBT) format consists of key-value maps.
Each map consists of a sequence of key-value records, terminated by a 0x00 byte '''Why
is the separator here 0x00 instead of 0xff?'''
The separator here is used to distinguish between each chunk of data. A separator of 0x00 would mean that
the unserializer can read it as a key length of 0, which would never occur with actual keys. It can thus
be used as a separator and allow for easier unserializer implementation..
:= * *
:= 0x70 0x73 0x62 0x74 0xFF
:= * 0x00
:= * 0x00
:= * 0x00
:= := :=
Where:
;
: A [https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer compact size] unsigned integer representing the type. This compact size unsigned integer must be minimally encoded, i.e. if the value can be represented using one byte, it must be represented as one byte. There can be multiple entries with the same within a specific , but the must be unique.
;
: The compact size unsigned integer containing the combined length of and
;
: The compact size unsigned integer containing the length of (which must be exactly this many bytes).
;
: Magic bytes which are ASCII for psbt '''Why use 4 bytes for psbt?''' The
transaction format needed to start with a 5 byte header which uniquely identifies
it. The first bytes were chosen to be the ASCII for psbt because that stands for
Partially Signed Bitcoin Transaction. followed by a separator of 0xFF'''Why Use a separator after the magic bytes?''' The separator
is part of the 5 byte header for PSBT. This byte is a separator of 0xff because
this will cause any non-PSBT unserializer to fail to properly unserialize the PSBT
as a normal transaction. Likewise, since the 5 byte header is fixed, no transaction
in the non-PSBT format will be able to be unserialized by a PSBT unserializer.. This integer must be serialized in most significant byte order.
The currently defined global types are as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
! Parent BIP
|-
| Unsigned Transaction
| PSBT_GLOBAL_UNSIGNED_TX = 0x00
| None
| No key data
|
| The transaction in network serialization. The scriptSigs and witnesses for each input must be empty. The transaction must be in the old serialization format (without witnesses).
| 0
| 2
| 0
| 174
|-
| Extended Public Key
| PSBT_GLOBAL_XPUB = 0x01
|
| The 78 byte serialized extended public key as defined by BIP 32. Extended public keys are those that can be used to derive public keys used in the inputs and outputs of this transaction. It should be the public key at the highest hardened derivation index so that the unhardened child keys used in the transaction can be derived.
| <4 byte fingerprint> <32-bit little endian uint path element>*
| The master key fingerprint as defined by BIP 32 concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. The number of 32 bit unsigned integer indexes must match the depth provided in the extended public key.
|
|
| 0, 2
| 174
|-
| Transaction Version
| PSBT_GLOBAL_TX_VERSION = 0x02
| None
| No key data
| <32-bit little endian int version>
| The 32-bit little endian signed integer representing the version number of the transaction being created. Note that this is not the same as the PSBT version number specified by the PSBT_GLOBAL_VERSION field.
| 2
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Fallback Locktime
| PSBT_GLOBAL_FALLBACK_LOCKTIME = 0x03
| None
| No key data
| <32-bit little endian uint locktime>
| The 32-bit little endian unsigned integer representing the transaction locktime to use if no inputs specify a required locktime.
|
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Input Count
| PSBT_GLOBAL_INPUT_COUNT = 0x04
| None
| No key data
|
| Compact size unsigned integer representing the number of inputs in this PSBT.
| 2
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Output Count
| PSBT_GLOBAL_OUTPUT_COUNT = 0x05
| None
| No key data
|
| Compact size unsigned integer representing the number of outputs in this PSBT.
| 2
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Transaction Modifiable Flags
| PSBT_GLOBAL_TX_MODIFIABLE = 0x06
| None
| No key data
| <8-bit uint flags>
| An 8 bit little endian unsigned integer as a bitfield for various transaction modification flags. Bit 0 is the Inputs Modifiable Flag and indicates whether inputs can be modified. Bit 1 is the Outputs Modifiable Flag and indicates whether outputs can be modified. Bit 2 is the Has SIGHASH_SINGLE flag and indicates whether the transaction has a SIGHASH_SINGLE signature who's input and output pairing must be preserved. Bit 2 essentially indicates that the Constructor must iterate the inputs to determine whether and how to add an input.
|
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Silent Payment Global ECDH Share
| PSBT_GLOBAL_SP_ECDH_SHARE = 0x07
| <33 byte scan key>
| The scan key that this ECDH share is for.
| <33 byte share>
| An ECDH share for a scan key. The ECDH shared is computed with ''a * B_scan'', where ''a'' is the sum of all private keys of all eligible inputs, and ''B_scan'' is the scan key of a recipient.
|
| 0
| 2
| [[bip-0375.mediawiki|375]]
|-
| Silent Payment Global DLEQ Proof
| PSBT_GLOBAL_SP_DLEQ = 0x08
| <33 byte scan key>
| The scan key that this proof covers.
| <64-byte proof>
| A BIP374 DLEQ proof computed for the matching ECDH share.
|
| 0
| 2
| [[bip-0375.mediawiki|375]]
|-
| PSBT Version Number
| PSBT_GLOBAL_VERSION = 0xFB
| None
| No key data
| <32-bit little endian uint version>
| The 32-bit little endian unsigned integer representing the version number of this PSBT. If omitted, the version number is 0.
|
|
| 0, 2
| 174
|-
| Proprietary Use Type
| PSBT_GLOBAL_PROPRIETARY = 0xFC
|
| Compact size unsigned integer of the length of the identifier, followed by identifier prefix, followed by a compact size unsigned integer subtype, followed by the key data itself.
|
| Any value data as defined by the proprietary type user.
|
|
| 0, 2
| 174
|}
The currently defined per-input types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
! Parent BIP
|-
| Non-Witness UTXO
| PSBT_IN_NON_WITNESS_UTXO = 0x00
| None
| No key data
|
| The transaction in network serialization format the current input spends from. This should be present for inputs that spend non-segwit outputs and can be present for inputs that spend segwit outputs. An input can have both PSBT_IN_NON_WITNESS_UTXO and PSBT_IN_WITNESS_UTXO. '''Why can both UTXO types be provided?''' Many wallets began requiring the full previous transaction (i.e. PSBT_IN_NON_WITNESS_UTXO) for segwit inputs when PSBT was already in use. In order to be compatible with software which were expecting PSBT_IN_WITNESS_UTXO, both UTXO types must be allowed.
|
|
| 0, 2
| 174
|-
| Witness UTXO
| PSBT_IN_WITNESS_UTXO = 0x01
| None
| No key data
| <64-bit little endian int amount>
| The entire transaction output in network serialization which the current input spends from. This should only be present for inputs which spend segwit outputs, including P2SH embedded ones. An input can have both PSBT_IN_NON_WITNESS_UTXO and PSBT_IN_WITNESS_UTXO
|
|
| 0, 2
| 174
|-
| Partial Signature
| PSBT_IN_PARTIAL_SIG = 0x02
|
| The public key which corresponds to this signature.
|
| The signature as would be pushed to the stack from a scriptSig or witness. The signature should be a valid ECDSA signature corresponding to the pubkey that would return true when verified and not a value that would return false or be invalid otherwise (such as a NULLDUMMY).
|
|
| 0, 2
| 174
|-
| Sighash Type
| PSBT_IN_SIGHASH_TYPE = 0x03
| None
| No key data
| <32-bit little endian uint sighash type>
| The 32-bit unsigned integer specifying the sighash type to be used for this input. Signatures for this input must use the sighash type, finalizers must fail to finalize inputs which have signatures that do not match the specified sighash type. Signers who cannot produce signatures with the sighash type must not provide a signature.
|
|
| 0, 2
| 174
|-
| Redeem Script
| PSBT_IN_REDEEM_SCRIPT = 0x04
| None
| No key data
|
| The redeemScript for this input if it has one.
|
|
| 0, 2
| 174
|-
| Witness Script
| PSBT_IN_WITNESS_SCRIPT = 0x05
| None
| No key data
|
| The witnessScript for this input if it has one.
|
|
| 0, 2
| 174
|-
| BIP 32 Derivation Path
| PSBT_IN_BIP32_DERIVATION = 0x06
|
| The public key
| <4 byte fingerprint> <32-bit little endian uint path element>*
| The master key fingerprint as defined by BIP 32 concatenated with the derivation path of the public key. The derivation path is represented as 32 bit unsigned integer indexes concatenated with each other. Public keys are those that will be needed to sign this input.
|
|
| 0, 2
| 174
|-
| Finalized scriptSig
| PSBT_IN_FINAL_SCRIPTSIG = 0x07
| None
| No key data
|
| The Finalized scriptSig contains a fully constructed scriptSig with signatures and any other scripts necessary for the input to pass validation.
|
|
| 0, 2
| 174
|-
| Finalized scriptWitness
| PSBT_IN_FINAL_SCRIPTWITNESS = 0x08
| None
| No key data
|
| The Finalized scriptWitness contains a fully constructed scriptWitness with signatures and any other scripts necessary for the input to pass validation.
|
|
| 0, 2
| 174
|-
| Proof-of-reserves commitment
| PSBT_IN_POR_COMMITMENT = 0x09
| None
| No key data
|
| The UTF-8 encoded commitment message string for the proof-of-reserves. See [[bip-0127.mediawiki|BIP 127]] for more information.
|
|
| 0, 2
| [[bip-0127.mediawiki|127]]
|-
| RIPEMD160 preimage
| PSBT_IN_RIPEMD160 = 0x0a
| <20-byte hash>
| The resulting hash of the preimage
|
| The hash preimage, encoded as a byte vector, which must equal the key when run through the RIPEMD160 algorithm
|
|
| 0, 2
| 174
|-
| SHA256 preimage
| PSBT_IN_SHA256 = 0x0b
| <32-byte hash>
| The resulting hash of the preimage
|
| The hash preimage, encoded as a byte vector, which must equal the key when run through the SHA256 algorithm
|
|
| 0, 2
| 174
|-
| HASH160 preimage
| PSBT_IN_HASH160 = 0x0c
| <20-byte hash>
| The resulting hash of the preimage
|
| The hash preimage, encoded as a byte vector, which must equal the key when run through the SHA256 algorithm followed by the RIPEMD160 algorithm
|
|
| 0, 2
| 174
|-
| HASH256 preimage
| PSBT_IN_HASH256 = 0x0d
| <32-byte hash>
| The resulting hash of the preimage
|
| The hash preimage, encoded as a byte vector, which must equal the key when run through the SHA256 algorithm twice
|
|
| 0, 2
| 174
|-
| Previous TXID
| PSBT_IN_PREVIOUS_TXID = 0x0e
| None
| No key data
| <32 byte txid>
| 32 byte txid in standard byte order, not display byte order, of the previous transaction whose output at PSBT_IN_OUTPUT_INDEX is being spent.
| 2
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Spent Output Index
| PSBT_IN_OUTPUT_INDEX = 0x0f
| None
| No key data
| <32-bit little endian uint index>
| 32 bit little endian integer representing the index of the output being spent in the transaction with the txid of PSBT_IN_PREVIOUS_TXID.
| 2
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Sequence Number
| PSBT_IN_SEQUENCE = 0x10
| None
| No key data
| <32-bit little endian uint sequence>
| The 32 bit unsigned little endian integer for the sequence number of this input. If omitted, the sequence number is assumed to be the final sequence number (0xffffffff).
|
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Required Time-based Locktime
| PSBT_IN_REQUIRED_TIME_LOCKTIME = 0x11
| None
| No key data
| <32-bit little endian uint locktime>
| 32 bit unsigned little endian integer greater than or equal to 500000000 representing the minimum Unix timestamp that this input requires to be set as the transaction's lock time.
|
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Required Height-based Locktime
| PSBT_IN_REQUIRED_HEIGHT_LOCKTIME = 0x12
| None
| No key data
| <32-bit uint locktime>
| 32 bit unsigned little endian integer less than 500000000 representing the minimum block height that this input requires to be set as the transaction's lock time.
|
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Taproot Key Spend Signature
| PSBT_IN_TAP_KEY_SIG = 0x13
| None
| No key data
| <64 or 65 byte signature>
| The 64 or 65 byte Schnorr signature for key path spending a Taproot output. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Script Spend Signature
| PSBT_IN_TAP_SCRIPT_SIG = 0x14
| <32 byte xonlypubkey>
| A 32 byte X-only public key involved in a leaf script concatenated with the 32 byte hash of the leaf it is part of.
| <64 or 65 byte signature>
| The 64 or 65 byte Schnorr signature for this pubkey and leaf combination. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Leaf Script
| PSBT_IN_TAP_LEAF_SCRIPT = 0x15
|
| The control block for this leaf as specified in BIP 341. The control block contains the merkle tree path to this leaf.
| <8-bit uint leaf version>
| The script for this leaf as would be provided in the witness stack followed by the single byte leaf version. Note that the leaves included in this field should be those that the signers of this input are expected to be able to sign for. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Key BIP 32 Derivation Path
| PSBT_IN_TAP_BIP32_DERIVATION = 0x16
| <32 byte xonlypubkey>
| A 32 byte X-only public key involved in this input. It may be the output key, the internal key, or a key present in a leaf script.
| <32 byte leaf hash>* <4 byte fingerprint> <32-bit little endian uint path element>*
| A compact size unsigned integer representing the number of leaf hashes, followed by a list of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output. The leaf hashes are of the leaves which involve this public key. The internal key does not have leaf hashes, so can be indicated with a hashes len of 0. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Internal Key
| PSBT_IN_TAP_INTERNAL_KEY = 0x17
| None
| No key data
| <32 byte xonlypubkey>
| The X-only pubkey used as the internal key in this output. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Merkle Root
| PSBT_IN_TAP_MERKLE_ROOT = 0x18
| None
| No key data
| <32-byte hash>
| The 32 byte Merkle root hash. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| MuSig2 Participant Public Keys
| PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS = 0x1a
| <33 byte aggregate pubkey (compressed)>
| The MuSig2 aggregate public key (compressed) from the KeyAgg algorithm. This key may or may not
be in the script directly (as x-only). It may instead be a parent public key from which the public keys in the
script were derived.
| <33 byte participant pubkey (compressed)>*
| A list of the compressed public keys of the participants in the MuSig2 aggregate key in the order
required for aggregation. If sorting was done, then the keys must be in the sorted order.
|
|
| 0, 2
| [[bip-0373.mediawiki|373]]
|-
| MuSig2 Public Nonce
| PSBT_IN_MUSIG2_PUB_NONCE = 0x1b
| <33 byte participant pubkey (compressed)> <33 byte aggregate pubkey (compressed)> <32 byte hash or omitted>
| The compressed public key of the participant providing this nonce, followed by the compressed aggregate public
key the participant is providing the nonce for, followed by the BIP 341 tapleaf hash of
the Taproot leaf script that will be signed. If the aggregate key is the taproot internal key or the
taproot output key, then the tapleaf hash must be omitted. The compressed participant public key must be
the key found in the script and not the aggregate public key that it was derived from, if it was
derived from an aggregate key.
| <66 byte public nonce>
| The public nonce produced by the NonceGen algorithm.
|
|
| 0, 2
| [[bip-0373.mediawiki|373]]
|-
| MuSig2 Participant Partial Signature
| PSBT_IN_MUSIG2_PARTIAL_SIG = 0x1c
| <33 byte participant pubkey (compressed)> <33 byte aggregate pubkey (compressed)> <32 byte hash or omitted>
| The compressed public key of the participant providing this partial signature, followed by the
compressed public key the participant is providing the signature for, followed by the BIP 341 tapleaf hash
of the Taproot leaf script that will be signed. If the aggregate key is the Taproot internal key or
the Taproot output key, then the tapleaf hash must be omitted. Note that the compressed participant public key must be
be the key found in the script and not the aggregate public key that it was derived from, if it was
derived from an aggregate key.
| <32 byte partial signature>
| The partial signature produced by the Sign algorithm.
|
|
| 0, 2
| [[bip-0373.mediawiki|373]]
|-
| Silent Payment Input ECDH Share
| PSBT_IN_SP_ECDH_SHARE = 0x1d
| <33 byte scan key>
| The scan key that this ECDH share is for.
| <33 byte share>
| An ECDH share for a scan key. The ECDH shared is computed with ''a * B_scan'', where ''a'' is the private key of the corresponding prevout public key, and ''B_scan'' is the scan key of a recipient.
|
| 0
| 2
| [[bip-0375.mediawiki|375]]
|-
| Silent Payment Input DLEQ Proof
| PSBT_IN_SP_DLEQ = 0x1e
| <33 byte scan key>
| The scan key that this proof covers.
| <64-byte proof>
| A BIP374 DLEQ proof computed for the matching ECDH share.
|
| 0
| 2
| [[bip-0375.mediawiki|375]]
|-
| Proprietary Use Type
| PSBT_IN_PROPRIETARY = 0xFC
|
| Compact size unsigned integer of the length of the identifier, followed by identifier prefix, followed by a compact size unsigned integer subtype, followed by the key data itself.
|
| Any value data as defined by the proprietary type user.
|
|
| 0, 2
| 174
|}
The currently defined per-output '''Why do we need per-output data?''' Per-output data allows signers
to verify that the outputs are going to the intended recipient. The output data can also be use by signers to
determine which outputs are change outputs and verify that the change is returning to the correct place. types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
! Parent BIP
|-
| Redeem Script
| PSBT_OUT_REDEEM_SCRIPT = 0x00
| None
| No key data
|
| The redeemScript for this output if it has one.
|
|
| 0, 2
| 174
|-
| Witness Script
| PSBT_OUT_WITNESS_SCRIPT = 0x01
| None
| No key data
|
| The witnessScript for this output if it has one.
|
|
| 0, 2
| 174
|-
| BIP 32 Derivation Path
| PSBT_OUT_BIP32_DERIVATION = 0x02
|
| The public key
| <4 byte fingerprint> <32-bit little endian uint path element>*
| The master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output.
|
|
| 0, 2
| 174
|-
| Output Amount
| PSBT_OUT_AMOUNT = 0x03
| None
| No key data
| <64-bit int amount>
| 64 bit signed little endian integer representing the output's amount in satoshis.
| 2
| 0
| 2
| [[bip-0370.mediawiki|370]]
|-
| Output Script
| PSBT_OUT_SCRIPT = 0x04
| None
| No key data
|
| The script for this output, also known as the scriptPubKey. Must be omitted in PSBTv0. Must be provided in PSBTv2 if not sending to a BIP352 silent payment address, otherwise may be omitted.
|
| 0
| 2
| [[bip-0370.mediawiki|370]], [[bip-0375.mediawiki|375]]
|-
| Taproot Internal Key
| PSBT_OUT_TAP_INTERNAL_KEY = 0x05
| None
| No key data
| <32 byte xonlypubkey>
| The X-only pubkey used as the internal key in this output.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Tree
| PSBT_OUT_TAP_TREE = 0x06
| None
| No key data
| {<8-bit uint depth> <8-bit uint leaf version> }*
| One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree, allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that the tree is correctly reconstructed. Each tuple is an 8-bit unsigned integer representing the depth in the Taproot tree for this script, an 8-bit unsigned integer representing the leaf version, the length of the script as a compact size unsigned integer, and the script itself.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| Taproot Key BIP 32 Derivation Path
| PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
| <32 byte xonlypubkey>
| A 32 byte X-only public key involved in this output. It may be the output key, the internal key, or a key present in a leaf script.
| <32 byte leaf hash>* <4 byte fingerprint> <32-bit little endian uint path element>*
| A compact size unsigned integer representing the number of leaf hashes, followed by a list of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output. The leaf hashes are of the leaves which involve this public key. The internal key does not have leaf hashes, so can be indicated with a hashes len of 0. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
| [[bip-0371.mediawiki|371]]
|-
| MuSig2 Participant Public Keys
| PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS = 0x08
| <33 byte aggregate pubkey (compressed)>
| The MuSig2 compressed aggregate public key from the KeyAgg algorithm. This key may or may not
be in the script directly. It may instead be a parent public key from which the public keys in the
script were derived.
| <33 byte participant pubkey (compressed)>*
| A list of the compressed public keys of the participants in the MuSig2 aggregate key in the order
required for aggregation. If sorting was done, then the keys must be in the sorted order.
|
|
| 0, 2
| [[bip-0373.mediawiki|373]]
|-
| Silent Payment Data
| PSBT_OUT_SP_V0_INFO = 0x09
| None
| No key data
| <33 byte scan key> <33 byte spend key>
| The scan and spend public keys from the silent payments address.
|
| 0
| 2
| [[bip-0375.mediawiki|375]]
|-
| Silent Payment Label
| PSBT_OUT_SP_V0_LABEL = 0x0a
| None
| No key data
| <32-bit little endian uint label>
| The label to use to compute the spend key of the silent payments address to verify change.
|
| 0
| 2
| [[bip-0375.mediawiki|375]]
|-
| BIP 353 DNSSEC proof
| PSBT_OUT_DNSSEC_PROOF = 0x35
| None
| No key data
| <1-byte-length-prefixed BIP 353 human-readable name>
| A BIP 353 human-readable name (without the ₿ prefix), prefixed by a 1-byte length.
Followed by an [[https://www.rfc-editor.org/rfc/rfc9102.html#name-dnssec-authentication-chain|RFC 9102 DNSSEC AuthenticationChain]] (i.e. a series of DNS Resource Records in no particular order) providing a DNSSEC proof to a BIP 353 DNS TXT record.
|
|
| 0, 2
| [[bip-0353.mediawiki|353]]
|-
| Proprietary Use Type
| PSBT_OUT_PROPRIETARY = 0xFC
|
| Compact size unsigned integer of the length of the identifier, followed by identifier prefix, followed by a compact size unsigned integer subtype, followed by the key data itself.
|
| Any value data as defined by the proprietary type user.
|
|
| 0, 2
| 174
|}
Types can be skipped when they are unnecessary. For example, if an input is a witness
input, then it should not have a Non-Witness UTXO key-value pair.
If the signer encounters key-value pairs that it does not understand, it must
pass those key-value pairs through when re-serializing the transaction.
All keys must have the data that they specify. If any key or value does not match the
specified format for that type, the PSBT must be considered invalid. For example, any
key that has no data except for the type specifier must only have the type specifier in
the key.
===Handling Duplicated Keys===
Keys within each scope should never be duplicated; all keys in the format are unique. PSBTs containing duplicate keys are invalid. However implementers
will still need to handle events where keys are duplicated when combining transactions with duplicated fields. In this event, the software may choose
whichever value it wishes.'''Why can the values be arbitrarily chosen?''' When there are duplicated keys, the values that can be chosen will either be
valid or invalid. If the values are invalid, a signer would simply produce an invalid signature and the final transaction itself would be invalid. If the
values are valid, then it does not matter which is chosen as either way the transaction is still valid.
===Proprietary Use Type===
For all global, per-input, and per-output maps, the type 0xFC is reserved for proprietary use.
The proprietary use type requires keys that follow the type with a compact size unsigned integer representing the length of the string identifier, followed by the string identifier, then a subtype, and finally any key data.
The identifier can be any variable length string that software can use to identify whether the particular data in the proprietary type can be used by it.
It can also be the empty string although this is not recommended.
The subtype is defined by the proprietary type user and can mean whatever they want it to mean.
The subtype must also be a compact size unsigned integer in the same form as the normal types.
The key data and value data are defined by the proprietary type user.
The proprietary use type is for private use by individuals and organizations who wish to use PSBT in their processes.
It is useful when there are additional data that they need attached to a PSBT but such data are not useful or available for the general public.
The proprietary use type is not to be used by any public specification and there is no expectation that any publicly available software be able to understand any specific meanings of it and the subtypes.
This type must be used for internal processes only.
==Version 0==
Partially Signed Bitcoin Transactions version 0 is the first version of the PSBT format.
Version 0 PSBTs must either omit PSBT_GLOBAL_VERSION or include it and set it to 0.
Version 0 PSBTs must include PSBT_GLOBAL_UNSIGNED_TX, if omitted, the PSBT is invalid.
==Roles==
Using the transaction format involves many different roles. Multiple roles can be handled by a single entity, but each role is specialized in what it should be capable of doing.
===Creator===
The Creator creates a new PSBT. It must create an unsigned transaction and place it in the PSBT.
The Creator must create empty input and output fields.
===Updater===
The Updater must only accept a PSBT.
The Updater adds information to the PSBT that it has access to. If it has the UTXO for an input, it should add it to the PSBT.
The Updater should also add redeemScripts, witnessScripts, and BIP 32 derivation paths to the input and output data if it knows them.
A single entity is likely to be both a Creator and Updater.
===Signer===
The Signer must only accept a PSBT.
The Signer must only use the UTXOs provided in the PSBT to produce signatures for inputs.
Before signing a non-witness input, the Signer must verify that the TXID of the non-witness UTXO matches the TXID specified in the unsigned transaction.
Before signing a witness input, the Signer must verify that the witnessScript (if provided) matches the hash specified in the UTXO or the redeemScript, and the redeemScript (if provided) matches the hash in the UTXO.
The Signer may choose to fail to sign a segwit input if a non-witness UTXO is not provided. '''Why would non-witness UTXOs be provided for segwit inputs?''' The sighash algorithm for Segwit specified in BIP 143 is known to have an issue where an attacker could trick a user to sending Bitcoin to fees if they are able to convince the user to sign a malicious transaction multiple times. This is possible because the amounts in PSBT_IN_WITNESS_UTXO of other segwit inputs can be modified without effecting the signature for a particular input. In order to prevent this kind of attack, many wallets are requiring that the full previous transaction (i.e. PSBT_IN_NON_WITNESS_UTXO) be provided to ensure that the amounts of other inputs are not being tampered with.
The Signer should not need any additional data sources, as all necessary information is provided in the PSBT format.
The Signer must only add data to a PSBT.
Any signatures created by the Signer must be added as a "Partial Signature" key-value pair for the respective input it relates to.
If a Signer cannot sign a transaction, it must not add a Partial Signature.
The Signer can additionally compute the addresses and values being sent, and the transaction fee, optionally showing this data to the user as a confirmation of intent and the consequences of signing the PSBT.
Signers do not need to sign for all possible input types. For example, a signer may choose to only sign Segwit inputs.
A single entity is likely to be both a Signer and an Updater as it can update a PSBT with necessary information prior to signing it.
====Data Signers Check For====
For a Signer to only produce valid signatures for what it expects to sign, it must check that the following conditions are true:
* If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
* If a witness UTXO is provided, no non-witness signature may be created
* If a redeemScript is provided, the scriptPubKey must be for that redeemScript
* If a witnessScript is provided, the scriptPubKey or the redeemScript must be for that witnessScript
* If a sighash type is provided, the signer must check that the sighash is acceptable. If unacceptable, they must fail.
* If a sighash type is not provided, the signer should sign using SIGHASH_ALL, but may use any sighash type they wish.
=====Simple Signer Algorithm=====
A simple signer can use the following algorithm to determine what and how to sign
sign_witness(script_code, i):
for key, sighash_type in psbt.inputs[i].items:
if sighash_type == None:
sighash_type = SIGHASH_ALL
if IsMine(key) and IsAcceptable(sighash_type):
sign(witness_sighash(script_code, i, input))
sign_non_witness(script_code, i):
for key, sighash_type in psbt.inputs[i].items:
if sighash_type == None:
sighash_type = SIGHASH_ALL
if IsMine(key) and IsAcceptable(sighash_type):
sign(non_witness_sighash(script_code, i, input))
for input, i in enumerate(psbt.inputs):
if witness_utxo.exists:
if redeemScript.exists:
assert(witness_utxo.scriptPubKey == P2SH(redeemScript))
script = redeemScript
else:
script = witness_utxo.scriptPubKey
if IsP2WPKH(script):
sign_witness(P2PKH(script[2:22]), i)
else if IsP2WSH(script):
assert(script == P2WSH(witnessScript))
sign_witness(witnessScript, i)
else if non_witness_utxo.exists:
assert(sha256d(non_witness_utxo) == psbt.tx.input[i].prevout.hash)
if redeemScript.exists:
assert(non_witness_utxo.vout[psbt.tx.input[i].prevout.n].scriptPubKey == P2SH(redeemScript))
sign_non_witness(redeemScript, i)
else:
sign_non_witness(non_witness_utxo.vout[psbt.tx.input[i].prevout.n].scriptPubKey, i)
else:
assert False
====Change Detection====
Signers may wish to display the inputs and outputs to users for extra verification.
In such displays, signers may wish to identify which outputs are change outputs in order to omit them to avoid additional user confusion.
In order to detect change, a signer can use the BIP 32 derivation paths provided in inputs and outputs as well as the extended public keys provided globally.
For a single key output, a signer can observe whether the master fingerprint for the public key for that output belongs to itself.
If it does, it can then derive the public key at the specified derivation path and check whether that key is the one present in that output.
For outputs involving multiple keys, a signer can first examine the inputs that it is signing.
It should determine the general pattern of the script and internally produce a representation of the policy that the script represents.
Such a policy can include things like how many keys are present, what order they are in, how many signers are necessary, which signers are required, etc.
The signer can then use the BIP 32 derivation paths for each of the pubkeys to find which global extended public key is the one that can derive that particular public key.
To do so, the signer would extract the derivation path to the highest hardened index and use that to lookup the public key with that index and master fingerprint.
The signer would construct this script policy with extended public keys for all of the inputs and outputs.
Change outputs would then be identified as being the outputs which have the same script policy as the inputs that are being signed.
===Combiner===
The Combiner can accept 1 or many PSBTs.
The Combiner must merge them into one PSBT (if possible), or fail.
The resulting PSBT must contain all of the key-value pairs from each of the PSBTs.
The Combiner must remove any duplicate key-value pairs, in accordance with the specification. It can pick arbitrarily when conflicts occur.
A Combiner must not combine two different PSBTs. PSBTs can be uniquely identified by 0x00 global transaction typed key-value pair.
For every type that a Combiner understands, it may refuse to combine PSBTs if it detects that there will be inconsistencies or conflicts for that type in the combined PSBT.
The Combiner does not need to know how to interpret scripts in order to combine PSBTs. It can do so without understanding scripts or the network serialization format.
In general, the result of a Combiner combining two PSBTs from independent participants A and B should be functionally equivalent to a result obtained from processing the original PSBT by A and then B in a sequence.
Or, for participants performing fA(psbt) and fB(psbt): Combine(fA(psbt), fB(psbt)) == fA(fB(psbt)) == fB(fA(psbt))
===Input Finalizer===
The Input Finalizer must only accept a PSBT.
For each input, the Input Finalizer determines if the input has enough data to pass validation. If it does, it must construct the 0x07 Finalized scriptSig and 0x08 Finalized scriptWitness and place them into the input key-value map.
If scriptSig is empty for an input, 0x07 should remain unset rather than assigned an empty array.
Likewise, if no scriptWitness exists for an input, 0x08 should remain unset rather than assigned an empty array.
All other data except the UTXO and unknown fields in the input key-value map should be cleared from the PSBT. The UTXO should be kept to allow Transaction Extractors to verify the final network serialized transaction.
===Transaction Extractor===
The Transaction Extractor must only accept a PSBT.
It checks whether all inputs have complete scriptSigs and scriptWitnesses by checking for the presence of 0x07 Finalized scriptSig and 0x08 Finalized scriptWitness typed records. If they do, the Transaction Extractor should construct complete scriptSigs and scriptWitnesses and encode them into network serialized transactions. Otherwise the Extractor must not modify the PSBT.
The Extractor should produce a fully valid, network serialized transaction if all inputs are complete.
The Transaction Extractor does not need to know how to interpret scripts in order to extract the network serialized transaction. However it may be able to in order to validate the network serialized transaction at the same time.
A single entity is likely to be both a Transaction Extractor and an Input Finalizer.
==Encoding==
A PSBT can be represented in two ways: in binary (as a file) or as a Base64 string using the encoding described in [https://tools.ietf.org/html/rfc4648#section-4 RFC4648].
Binary PSBT files should use the .psbt file extension.
A MIME type name will be added to this document once one has been registered.
==Extensibility==
The Partially Signed Transaction format can be extended in the future by adding
new types for key-value pairs. Backwards compatibility will still be maintained as those new
types will be ignored and passed-through by signers which do not know about them.
===Version Numbers===
The Version number field exists only as a safeguard in the event that a backwards incompatible change is introduced to PSBT.
If a parser encounters a version number it does not recognize, it should exit immediately as this indicates that the PSBT will contain types that it does not know about and cannot be ignored.
Current PSBTs are Version 0. Any PSBT that does not have the version field is version 0.
It is not expected that any backwards incompatible change will be introduced to PSBT, so it is not expected that the version field will ever actually be seen.
Updaters and combiners that need to add a version number to a PSBT should use the highest version number required.
For example, if a combiner sees two PSBTs for the same transaction, one with version 0, and the other with version 1, then it should combine them and produce a PSBT with version 1.
If an updater is updating a PSBT and needs to add a field that is only available in version 1, then it should set the PSBT version number to 1 unless a version higher than that is already specified.
===Procedure For New Fields===
New fields should first be proposed on the bitcoin-dev mailing list.
If a field requires significant description as to its usage, it should be accompanied by a separate BIP.
The field must be added to the field listing tables in the Specification section.
Although some PSBT version 0 implementations encode types as uint8_t rather than compact size,
it is still safe to add >0xFD fields to PSBT 0, because these old parsers ignore
unknown fields, and is prefixed by its length.
===Procedure For New Versions===
New PSBT versions must be described in a separate BIP.
The BIP may reference this BIP and any components of PSBT version 0 that are retained in the new version.
Any new fields described in the new version must be added to the field listing tables in the Specification section.
==Compatibility==
This transaction format is designed so that it is unable to be properly unserialized
by normal transaction unserializers. Likewise, a normal transaction will not be
able to be unserialized by an unserializer for the PSBT format.
==Examples==
===Manual CoinJoin Workflow===
===2-of-3 Multisig Workflow===
==Test Vectors==
The following are invalid PSBTs:
* Case: Network transaction, not PSBT format
** Bytes in Hex:
* Case: PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.
** Bytes in Hex:
* Case: PSBT with one P2SH-P2WSH input of a 2-of-2 multisig, redeemScript, witnessScript, and keypaths are available. Contains one signature.
** Bytes in Hex:
* Case: PSBT with one P2WSH input of a 2-of-2 multisig. witnessScript, keypaths, and global xpubs are available. Contains no signatures. Outputs filled.
** Bytes in Hex:
A creator creating a PSBT for a transaction which creates the following outputs:
* scriptPubKey: 0014d85c2b71d0060b09c9886aeb815e50991dda124d, Amount: 1.49990000
* scriptPubKey: 001400aea9a2e5f0f876a588df5546e8742d1d87008f, Amount: 1.00000000
and spends the following inputs:
* TXID: 75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858, Index: 0
* TXID: 1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83, Index: 1
must create this PSBT:
* Bytes in Hex:
Given the above PSBT, an updater with only the following:
* Redeem Scripts:
** 5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae
** 00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903
* Witness Scripts:
** 522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae
* Previous Transactions:
**
Given the above updated PSBT, a signer that supports SIGHASH_ALL for P2PKH and P2WPKH spends and uses RFC6979 for nonce generation and has the following keys:
* cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr (m/0'/0'/0')
* cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d (m/0'/0'/2')
must create this PSBT:
* Bytes in Hex:
Given the above updated PSBT, a signer with the following keys:
* cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au (m/0'/0'/1')
* cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE (m/0'/0'/3')
must create this PSBT:
* Bytes in Hex:
==Rationale==
==Reference implementation==
The reference implementation of the PSBT format is available at https://github.com/achow101/bitcoin/tree/psbt.
==Acknowledgements==
Special thanks to Pieter Wuille for suggesting that such a transaction format should be made
and for coming up with the name and abbreviation of PSBT.
Thanks to Pieter Wuille, Gregory Maxwell, Jonathan Underwood, Daniel Cousens and those who commented on the bitcoin-dev mailing list for additional comments
and suggestions for improving this proposal.
================================================
FILE: bip-0175.mediawiki
================================================
==Abstract==
Utilizing hierarchical deterministic wallets as described in BIP-0032 and the "Purpose Field" in BIP-0043, this document specifies the multiparty pay-to-contract key derivation scheme outlined by Ilja Gerhardt and Timo Hanke.[0]
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
==Motivation==
A Bitcoin transaction represents a "real world" contract between two parties transferring value. Counterparties in a business interaction traditionally keep track of a payment with bills (invoices) and receipts. Delivery of a good is made by the payee once the payer has signed the receipt, agreeing to pay for the items on the invoice. Gerhardt and Hanke [0] formulate this interaction within the confines of the Bitcoin protocol using homomorphic payment addresses and the multiparty pay-to-contract protocol.
The protocol is constructed in such a way that all parties have cryptographic proof of both who is being paid and for what. Using the technique described in this BIP, an address can be provably derived from the terms of a contract and the payee's public key. This derivation scheme does not bloat the UTXO and is completely hidden to network participants; the derived address looks like any other P2(W)PKH or P2(W)SH address. Redemption of the funds requires knowledge of the contract and the payee's private key.
This scheme utilizes the foundations of BIP-0032, providing a consistent way for preexisting wallet developers to implement the specification.
==Specification==
This key derivation scheme requires two parties: a payer (customer) and a payee (merchant).
The customer submits to the merchant a purchase request, specifying what goods/services they would like to buy. From the purchase request the merchant constructs an invoice (contract), specifying the billable items and total amount to be paid.
The merchant must give this contract alongside a “payment base” extended public key to the customer. Given this information, the customer will be able to fulfill the contract by generating the public key of the payment address associated with the contract and the payment base, then sending the funds there.
We define the following levels in BIP32 path:
m / purpose' / coin_type' / contract_hash
contract_hash consists of multiple levels.
Apostrophe in the path indicates that BIP32 hardened derivation is used.
We define the following extended public keys:
Payment base denoted as payment_base:
m / purpose' / coin_type'
Payment address denoted as payment_address:
m / purpose' / coin_type' / contract_hash
or
m / payment_base / contract_hash
Each level has special meaning described in the chapters below.
===Purpose===
Purpose is a constant set to 175' (or 0x800000AF) following the BIP-0043 recommendation. It indicates that the subtree of this node is used according to this specification.
m / 175' / *
Hardened derivation is used at this level.
===Coin type===
The coin type field is identical to the same field in BIP-0044.
Hardened derivation is used at this level.
===Payment address generation===
For a given contract documents denoted by c1,...,cn, payment base extended public key denoted by payment_base, and cryptographic hash function denoted by h.
1. Compute cryptographic hashes for all contract documents, by applying the hash function.
h(c1),...,h(cn)
2. Sort all hashes lexicographically.
hash_1,...,hash_n
3. Prepend payment_base and concatenate the sorted hashes and apply the hash function.
h(payment_base+hash_1+...+hash_n)
4. Compute a partial BIP32 derivation path from the combined hash as defined in Hash to Partial Derivation Path Mapping procedure below.
contract_hash
5. Prepend payment_base to contract_hash derivation path.
payment_base / contract_hash
6. Compute public extended key from the derivation path in step 5.
7. Compute address of the public extended key (P2PKH) from step 6.
===Payment address verification===
For a given Bitcoin address, payment_base extended public key, contract documents denoted by c1,...,cn, and cryptographic hash function denoted by h, we can verify the integrity of the address by the following steps:
1. Compute contract address from the given inputs as described in Contract Address Generation section.
2. Compare the computed address from step 1 with the given Bitcoin address as an input.
===Redemption===
The merchant is able to construct the private key offline using the method described in the Payment Address Generation section.
The merchant should actively monitor the blockchain for the payment to the payment address.
Because the address is generated from the payment base and the contract, the merchant must implicitly agree to those terms in order to spend the funds.
The act of making the payment to that address thus serves as a receipt for the customer.
===Hash to partial derivation path mapping===
At this section, we define hash to partial BIP32 derivation path mapping procedure that maps between an arbitrary hex number to a partial BIP32 derivation path.
For a given hex number, do the following:
1. Partition hex number into parts, each part length is 4 chars.
2. Convert each part to integer in decimal format.
3. Concatenate all numbers with slash /.
==Examples==
For the following given inputs:
master private extended key:
xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73
coin type:
0
we can compute payment base as follows:
payment base derivation path:
m/175'/0'
contract base public extended key:
xpub6B3JSEWjqm5GgfzcjPwBixxLPzi15pFM3jq4E4yCzXXUFS5MFdXiSdw7b5dbdPGHuc7c1V4zXbbFRtc9G1njMUt9ZvMdGVGYQSQsurD6HAW
In the below examples, we are going to use SHA256 as a cryptographic hash function, and the above contract base public key.
====Payment address generation====
As an input, we have a contract that consists of two documents, below are contents:
document 1:
bar
document 2:
foo
1. Apply the hash function:
document 1:
fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
document 2:
2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
2. Sort all hashes lexicographically:
2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae
fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
3. Concatenate hashes and apply the hash function.
concatenated hash: payment_base
xpub6B3JSEWjqm5GgfzcjPwBixxLPzi15pFM3jq4E4yCzXXUFS5MFdXiSdw7b5dbdPGHuc7c1V4zXbbFRtc9G1njMUt9ZvMdGVGYQSQsurD6HAW2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7aefcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9
combined hash:
310057788c6073640dc222466d003411cd5c1cc0bf2803fc6ebbfae03ceb4451
4. Compute the partial BIP32 derivation path of the combined hash.
12544/22392/35936/29540/3522/8774/27904/13329/52572/7360/48936/1020/28347/64224/15595/17489
5. Prepend payment_base to contract_hash derivation path.
contract_base_pub/12544/22392/35936/29540/3522/8774/27904/13329/52572/7360/48936/1020/28347/64224/15595/17489
or
m/175'/0'/12544/22392/35936/29540/3522/8774/27904/13329/52572/7360/48936/1020/28347/64224/15595/17489
6. Compute public extended key.
xpub6hefaATTG5LbcwyPDvmNfnkyzefoM2TJDoo5astH7Gvs1g8vZURviBWvAvBnWc2CNb8ybJ6mDpnQYVsvNSZ3oUmbssX3rUVG97TFYa6AXVk
7. Compute address of the public extended key (P2PKH).
1C7f322izqMqLzZzfzkPAjxBzprxDi47Yf
====Verification example (negative test)====
Similar to the input above, except this time we have a contract that consists of one document, below is the content:
document 1:
baz
1. Apply the hash function.
baa5a0964d3320fbc0c6a922140453c8513ea24ab8fd0577034804a967248096
2. Prepend payment_base
xpub6B3JSEWjqm5GgfzcjPwBixxLPzi15pFM3jq4E4yCzXXUFS5MFdXiSdw7b5dbdPGHuc7c1V4zXbbFRtc9G1njMUt9ZvMdGVGYQSQsurD6HAWbaa5a0964d3320fbc0c6a922140453c8513ea24ab8fd0577034804a967248096
2. Apply hash function
3a08605829413ce0bf551b08d21e4a28dbda6e407f90eff1c448e839050c73a1
3. Compute the partial derivation path.
5338/54412/19213/962/30664/62597/11873/59874/56779/24089/54550/19585/28087/36422/18666/17562
4. Prepend contract_basepub to contract_hash derivation path.
contract_base_pub/5338/54412/19213/962/30664/62597/11873/59874/56779/24089/54550/19585/28087/36422/18666/17562
or
m/175'/0'/5338/54412/19213/962/30664/62597/11873/59874/56779/24089/54550/19585/28087/36422/18666/17562
5. Compute public extended key.
xpub6h9k2KqsMpwghxt7naj1puhGV1ZDC88sxvpYN1HibCf8yQZdPsuhYmmvdK32Kf2Lb3rS1sV8UcZ1f84DJEiXuVfLCAj4bC85aEUCxh38m8i
7. Compute address of the public extended key (P2PKH).
1QGe5LaDMAmHeibJbZBmZqhQDZSp7QCqSs
8. As expected the address doesn't match the Bitcoin address from the last example 1C7f322izqMqLzZzfzkPAjxBzprxDi47Yf.
Verification operation will succeed only if we use identical documents to ones that have been used in the contract address generation.
==Compatibility==
This specification is not backward compatible with BIP32 specification, the proposed derivation scheme in this BIP is a BIP32 compliant.
Communication between payer and payee as well as hashing the contract and generating the path requires significant modification to the wallet.
==Reference implementations==
* Reference implementation to Hash to Partial Derivation Path Mapping in javascript ([[https://github.com/commerceblock/pay-to-contract-lib/blob/master/lib/contract.js|https://github.com/commerceblock/pay-to-contract-lib]])
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
* [[https://arxiv.org/abs/1212.3257|Homomorphic Payment Addresses and the Pay-to-Contract Protocol]]
==Copyright==
This BIP is licensed under the 2-clause BSD license.
================================================
FILE: bip-0176.mediawiki
================================================
BIP: 176
Title: Bits Denomination
Authors: Jimmy Song
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0176
Status: Draft
Type: Informational
Assigned: 2017-12-12
License: BSD-2-Clause
== Abstract ==
Bits is presented here as the standard term for 100 (one hundred) satoshis or 1/1,000,000 (one one-millionth) of a bitcoin.
== Motivation ==
The bitcoin price has grown over the years and once the price is past $10,000 USD or so, bitcoin amounts under $10 USD start having enough decimal places that it's difficult to tell whether the user is off by a factor of 10 or not. Switching the denomination to "bits" makes comprehension easier. For example, when BTC is $15,000 USD, $10.05 is a somewhat confusing 0.00067 BTC, versus 670 bits, which is a lot clearer.
Additionally, reverse comparisons are easier as 59 bits being $1 is easier to comprehend for most people than 0.000059 BTC being $1. Similar comparisons can be made to other currencies: 1 yen being 0.8 bits, 1 won being 0.07 bits and so on.
Potential benefits of utilizing "bits" include:
# Reduce user error on small bitcoin amounts.
# Reduce unit bias for users that want a "whole" bitcoin.
# Allow easier comparisons of prices for most users.
# Allow easier bi-directional comparisons to fiat currencies.
# Allows all UTXO amounts to need at most 2 decimal places, which can be easier to handle.
== Specification ==
Definition: 1 bit = 100 satoshis.
Plural of "bit" is "bits." The terms "bit" and "bits" are not proper nouns and thus should not be capitalized unless used at the start of a sentence, etc.
All bitcoin-denominated items are encouraged to also show the denomination in bits, either as the default or as an option.
== Rationale ==
As bitcoin grows in price versus fiat currencies, it's important to give users the ability to quickly and accurately calculate prices for transactions, savings and other economic activities. "Bits" have been used as a denomination within the Bitcoin ecosystem for some time. The idea of this BIP is to formalize this name. Additionally, "bits" is likely the only other denomination that will be needed for Bitcoin as 0.01 bit = 1 satoshi, meaning that two decimal places will be sufficient to describe any current utxo.
Existing terms used in bitcoin such as satoshi, milli-bitcoin (mBTC) and bitcoin (BTC) do not conflict as they operate at different orders of magnitude.
The term micro-bitcoin (µBTC) can continue to exist in tandem with the term "bits."
== Backwards Compatibility ==
Software such as the Bitcoin Core GUI currently use the µBTC denomination and can continue to do so. There is no obligation to switch to "bits."
The term "bit" has many different definitions, but the ones of particular note are these:
* 1 bit = 1/8 dollar (e.g., that candy cost me 2 bits {or 1/4 dollar})
* bit meaning some amount of data (e.g., the first bit of the version field is 0)
* bit meaning strength of a cryptographic algorithm (e.g., 256-bit ECDSA is used in Bitcoin)
The first is a bit dated and isn't likely to confuse people dealing with Bitcoin. The second and third are computer science terms and context should be sufficient to figure out what the user of the word means.
== Copyright ==
This BIP is licensed under the BSD 2-clause license.
== Credit ==
It's hard to ascertain exactly who invented the term "bits," but the term has been around for a while and the author of this BIP does not take any credit for inventing the term.
================================================
FILE: bip-0177.mediawiki
================================================
BIP: 177
Title: Redefine Bitcoin's Base Unit
Authors: John Carvalho
Status: Draft
Type: Informational
Assigned: 2025-04-23
License: CC0-1.0
==Introduction==
===Abstract===
This BIP proposes redefining the commonly recognized "bitcoin" unit so that the base unit becomes the primary reference unit. Under this proposal, one bitcoin is defined as that indivisible base unit, eliminating the convention of synthetic decimal places. By making the base unit the standard measure, this BIP aims to simplify user comprehension, reduce confusion, and align on-chain values directly with their displayed representation.
===Motivation===
The current convention defines one bitcoin as 100,000,000 base units. This representation requires dealing with eight simulated decimal places, which can be confusing and foster the misconception that bitcoin is inherently decimal-based. In reality, Bitcoin’s ledger represents values as integral base units. The decimal point is merely a human-imposed abstraction.
By redefining the base unit as "one bitcoin," this BIP aligns user perception with the protocol’s true nature. It reduces cognitive overhead, ensures users understand Bitcoin as counting discrete units, and ultimately improves educational clarity and user experience.
===Specification===
'''Redefinition of the Unit:'''
* Internally, the base units remain unchanged.
* Historically, 1 bitcoin = 100,000,000 base units. Under this proposal, "1 bitcoin" equals one base unit.
* What was previously referred to as "1 bitcoin" now corresponds to 100 million bitcoins under the new definition.
'''Terminology:'''
* The informal terms "satoshi" or "sat" are deprecated.
* All references, interfaces, and documentation SHOULD refer to the base unit simply as "bitcoin."
* The currency code "BTC" is unaffected by these changes, and continues to mean 100,000,000 base units.
'''Display and Formatting:'''
* Applications SHOULD allow users to toggle between the legacy BTC format (1 BTC = 100,000,000 base units) and the new integral format (1 bitcoin = 1 base unit).
* Use of the ₿ symbol MAY be used to represent base-unit bitcoins but is OPTIONAL.
Example 1:
* Old display: 0.00010000 bitcoin
* New display: ₿10,000 or 10,000 bitcoins or 0.00010000 BTC
Example 2:
* Old display: 10.23486 bitcoin
* New display: ₿1,023,486,000 or 1,023,486,000 bitcoins or 10.23486 BTC
Example 3:
* Old display: 0.345 BTC
* New display: No changes required or ₿34,500,000 or 34,500,000 bitcoins
NOTE: Traditional number display abbreviations, like 2.5M for millions, are also optional.
'''Conversion:'''
* Ledger and consensus rules remain unchanged.
* BTC as a currency code remains unchanged (1 BTC = 100,000,000 base units)
* Implementations adopting this standard MUST multiply previously displayed bitcoin amounts by 100,000,000 to determine the new integer representation.
===Rationale===
'''Usability:'''
Integer-only displays simplify mental arithmetic and reduce potential confusion or user error.
'''Protocol Alignment:'''
The Bitcoin protocol inherently counts discrete units. Removing the artificial decimal format aligns user perception with Bitcoin’s actual integral design.
'''Educational Clarity:'''
Presenting integers ensures newcomers do not mistakenly assume that Bitcoin’s nature is decimal-based. It conveys Bitcoin’s true design from the start.
'''Future-Proofing:'''
Adopting the base unit as the primary measure ensures a consistent standard that can scale smoothly as Bitcoin adoption grows.
'''Perception of Supply:'''
While the total count of base units is roughly 2.1 quadrillion, this proposal does not alter supply in any way. The change is purely representational. Comparisons can be drawn to other currencies like the Japanese yen or Indonesian rupiah, where high unit counts are standard and not perceived as inflationary.
===Addressing Alternative Approaches===
'''Refuting the "Bits" Proposal'''
([https://github.com/bitcoin/bips/blob/master/bip-0176.mediawiki BIP 176])
An alternative suggestion (BIP 176) proposes using "bits" to represent one-millionth of a bitcoin (100 satoshis). While this reduces the number of decimal places in certain contexts, it fails to fully address the core issues our BIP aims to solve:
1. '''Persistent Decimal Mindset:'''
Using "bits" still retains a layered decimal approach, requiring users to think in terms of multiple denominations (BTC and bits). This shifts complexity rather than eliminating it.
2. '''Inconsistent User Experience:'''
Users must learn to toggle between BTC for large amounts and bits for small amounts. Instead of providing a unified view of value, it fragments the user experience.
3. '''Incomplete Alignment with the Protocol’s Nature:'''
The "bits" proposal does not realign the displayed value with the integral nature of Bitcoin’s ledger. It continues to rely on fractional units, masking the fundamental integer-based accounting that Bitcoin employs.
4. '''Not Permanently Future-Proof:'''
Though "bits" may simplify certain price ranges, future circumstances could demand additional denominations or scaling adjustments. Our integral approach resolves this problem entirely by making the base unit the standard measure, avoiding future fragmentation.
In essence, while BIP 176 attempts to simplify small amount representations, it only replaces one decimal representation with another. By redefining "bitcoin" as the base unit, this BIP eliminates reliance on decimal fractions and separate denominations entirely, offering a clearer, more intuitive, and ultimately more durable solution.
===Handling the Terms “satoshi” and “sat”===
'''Background'''
“Satoshi” (or its shorthand “sat”) emerged organically some years ago, to honour Bitcoin’s creator and to give a friendly name to the 100-millionth "fraction" of a bitcoin.
Over time “stacking sats” became a meme, and the term now appears in podcasts, apparel, and some wallet UIs.
While culturally valuable, the term introduces an implicit second denomination layer that contradicts the goal of this BIP: a single base unit, called simply "bitcoin". Of course this BIP cannot stop anyone from using any colloquial term they prefer, but this document exists to specify how to display Bitcoin's only units as "bitcoin" correctly.
===Backward Compatibility===
No consensus rules are altered, and on-chain data remains unchanged. Differences arise solely in display formats:
* '''For Developers:''' Update GUIs, APIs, and documentation to present values as integers. Remove references to fractional Bitcoin. BTC units remain unchanged.
* '''For Users:''' The actual value of holdings does not change. Transitional measures, such as dual displays or explanatory tooltips, can ease the adjustment period.
===Security Considerations===
A short-term risk of confusion exists as users adapt to the new representation. Users accustomed to decimals may misinterpret initial displays. To mitigate this:
* Offer dual displays and tooltips during the transition.
* Provide clear educational materials and coordinated messaging.
* Use alerts or confirmations in applications if input values appear unexpectedly large or small.
* Highlight the unchanging 21M BTC supply cap and equivalence to avoid misinterpretation as inflationary.
===Reference Implementation===
Some wallets, such as Bitkit, have successfully adopted integer-only displays, demonstrating the feasibility of this approach, without incident. Transitional features — like showing both old and new formats side-by-side — can help smooth the transition.
===Test Vectors===
* Old: 1.00000000 Bitcoin → New: ₿100,000,000 (or 100,000,000 bitcoins)
* Old: 0.00010000 Bitcoin → New: ₿10,000 (or 10,000 bitcoins)
* Old: 0.00500000 Bitcoin → New: ₿500,000 (or 500,000 bitcoins)
* Old: 0.005 BTC → New: 0.005 BTC (or ₿500,000 or 500,000 bitcoins)
All formerly fractional representations now directly correspond to whole-number multiples of the base unit.
===Implementation Timeline===
'''Phase 1 (3-6 months):''' Introduce the concept, provide dual displays and educational materials. Begin pilot testing in willing wallet apps.
'''Phase 2 (6-12 months):''' Prominent services adopt integer-only displays by default. Community coordination and media campaigns ensure consistency.
'''Phase 3 (12+ months):''' Integer representation becomes standard. Documentation and user guides no longer reference decimal-based formats.
===Conclusion===
Redefining "bitcoin" as the smallest indivisible unit, and removing decimal-based representations, simplifies comprehension and aligns displayed values with the protocol’s integral accounting. While a transition period may be necessary, the long-term benefits include clearer communication, reduced confusion, and a more accurate understanding of Bitcoin’s fundamental design.
===Copyright===
This BIP is licensed under CC0-1.0.
================================================
FILE: bip-0178.mediawiki
================================================
== Abstract ==
An extension to the Wallet Import Format (WIF) to specify what kind of bitcoin address the private key corresponds to.
== Motivation ==
There are several types of bitcoin addresses which can all be associated with a given private key: P2PKH (legacy 1... format), P2SH-P2WPKH (SegWit public key inside P2SH), P2WPKH (bech32), etc.
While private keys have a 1-byte suffix indicating whether the corresponding public key is compressed (0x01) or not (through suffix absence), there is no way of knowing what kind of bitcoin address were associated with the private key. As a result, when importing a private key, the wallet has to assume all kinds, and keep track of each possible alternative.
By extending the suffix, we can specify what kind of bitcoin address was associated with a given private key.
== Specification ==
Currently, private keys are stored as a uint256 (private key data) followed by an optional uint8 (compressed flag). The latter is extended to specify the address types:
{|class="wikitable" style="text-align: center;"
|-
!Value
!Type
!Compr
!Clarification
|-
|No suffix||P2PKH_UNCOMPRESSED||No||Uncompressed legacy public key. Unknown public key format
|-
|0x01||P2PKH_COMPRESSED||Yes||Compressed legacy public key. Unknown public key format
|-
|0x10||P2PKH||Yes||Compressed legacy public key. Legacy public key format (1...)
|-
|0x11||P2WPKH||Yes||Bech32 format (native Segwit)
|-
|0x12||P2WPKH_P2SH||Yes||Segwit nested in BIP16 P2SH (3...)
|}
When a wallet imports a private key, it will have two outcomes:
* the key is using one of the legacy types, in which case all types must be accounted for
* the key is using one of the extended types, in which case the wallet need only track the specific corresponding address
Note: the difference between `0x01` and `0x10` is that the former can correspond to any of the types above, whereas the latter *only* corresponds to a P2PKH (legacy non-segwit).
== Compatibility ==
This proposal is not backwards compatible, in that software that does not recognize the new types will not understand the compressed flag. It would be trivial to change this, by keeping the 'uncompressed' state as it is (no suffix) and changing 'compressed' to be 'anything not 0', as opposed to 'the value 1'.
The proposal ''is'' backwards compatible in that new wallet software will always understand the old WIF format, however. It will, as it does today, assume that any kind of bitcoin address is possible, and will have to track all of them, as it has to today.
== Acknowledgements ==
This BIP is based on the initial proposal by Thomas Voegtlin (thomasv at electrum dot org) on the Bitcoin Dev mailing listhttps://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-September/015007.html and the Electrum 3.0 implementationhttps://github.com/spesmilo/electrum/blob/82e88cb89df35288b80dfdbe071da74247351251/RELEASE-NOTES#L95-L108
== Reference implementation ==
There is a partial implementation which adds, but does not use, the types described in this BIP here: https://github.com/bitcoin/bitcoin/pull/12869
== References ==
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
================================================
FILE: bip-0179.mediawiki
================================================
BIP: 179
Title: Name for payment recipient identifiers
Authors: Emil Engler
Luke Dashjr
Status: Draft
Type: Informational
Assigned: 2019-10-17
License: CC0-1.0
==Abstract==
This BIP proposes a new term for 'address'
==Specification==
The new term is:
''Bitcoin'' '''Invoice''' ''Address''
The ''Bitcoin'' and ''Address'' parts are optional.
The address suffix should only be used as a transitional step.
A ''Bitcoin'' Invoice ''Address'' is a string of characters that can be used to indicate the intended recipient and purpose of a transaction.
==Motivation==
Bitcoin addresses are intended to be only used '''once''' and you should generate a new one for every new incoming payment.
The term 'address' however indicates consistency because nearly everything on the internet or the offline world with the term 'address'
is something that rarely or even never changes (postal address, email address, IP addresses (depends heavily on the provider), etc.)
The motivation for this BIP is to change the term address to something that indicates that the address is connected to a single transaction.
==Rationale==
The reason why we use ''Bitcoin Invoice Address'' or just ''Invoice'' is to emphasize that it is single-use.
The terms ''Bitcoin'' and ''Address'' are optional for the following reasons:
For ''Bitcoin'':
* Useful for multicoin wallets to indicate that it belongs to Bitcoin
* Indicates a difference between a lightning and an on-chain invoice
For ''Address'':
* To not confuse users with a completely new term
* To show that it is where you send something to
* To not break backwards compatibility
This gives us the four following possibilities:
* Bitcoin Invoice Address
* Bitcoin Invoice
* Invoice Address
* Invoice
==Backwards Compatibility==
To avoid issues, the 'Address' suffix is permitted, but not recommended.
The suffix 'Address' remains so users should be immediately able to recognize it until the new term is widely known.
==Acknowledgements==
Thanks to Chris Belcher for the suggestion of the term 'Bitcoin Invoice Address'
==Copyright==
This BIP is released under CC0-1.0 and therefore Public Domain.
================================================
FILE: bip-0180.mediawiki
================================================
==Abstract==
A fraud proof that enables light clients to detect oversized (or overweight) blocks.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Definitions==
; full tx size proof : SHA2 midstate and tail data proving the size of the full transaction data being hashed.
; size component : Either a merkle link and height in the merkle tree thereof, or a full tx size proof.
; full-size proof : The set of size components proving the lower-bound size of the block.
; stripped-size proof : The set of size components proving the lower-bound size of the block when stripped of segwit witness data.
==Specification==
===Proof format===
* varint: ceil(log2(number of transactions in block))
* varint: number of size components in stripped-size proof
* foreach:
** varint: ceil(log2(number of transactions represented by this size-component)) + 1
** if zero:
*** (this indicates a full tx size proof)
*** 256-bit: SHA2 midstate up until just before the final SHA2 chunk
*** varint: total size of tx
*** uint8: size of final SHA2 chunk (0-55)
*** 0-55 bytes: final SHA2 chunk
** if one or more:
*** (this indicates default tx size counting)
*** 256-bit: SHA2 hash of merkle link
* varint: number of size components in full-size proof (zero in case of a size-exceeded proof; non-zero for a weight-exceeded proof)
* foreach: (same as with stripped-size proof)
===Proof verification===
To verify an individual size proof:
#Check that at least one size component is a full tx size proof. (At least one size component MUST be a full tx size proof.)
#Determine the lower-bound number of transactions in the block (lowTxCount). It is either pow(ceil(log2(txcount)) - 1, 2), or the position of the last full tx proof (plus one, if using 0-based positions). Note that the last full tx proof from *either* of the size proofs (stripped-size and full-size) should be used here.
#Calculate the lower-bound transaction-data size as the default size * lowTxCount.
#For each full tx size proof:
##Subtract the default size it was presumed to consume, and add the claimed total size of tx.
##Take the SHA2 midstate, and update it with the final SHA2 chunk (which needs to be padded, including with the total tx size). The final SHA2 hash is the transaction id (stripped-size proof) or hash (full-size proof).
#For the full-size proof, replace the 60 byte default with any larger sizes proven from the stripped-size proof.
#Build the merkle root, and compare it to the block header (stripped-size proof) or witness commitment (full-size proof). Ensure when building the merkle root, that there are no duplicate merkle links, and each merkle link claims to represent the correct number of represented transactions.
#Add 80 bytes, plus the size of the tx-count varint, to the calculated lower-bound size.
#The calculated size is returned as the lower-bound possible size of the block.
For the stripped-size proof, the default size of transactions is 60 bytes.
For the full-size proof, it is the size established by the stripped-size proof.
To verify the complete weight proof:
# Verify the stripped-size proof. Save the resulting lower-bound size (call it lowStrippedSize).
# Verify the full-size proof. Save the resulting lower-bound size (call it lowFullSize).
# Calculate minFullSize + (minStrippedSize * 3). This is the lower-bound block weight.
# Compare the lower-bound block weight to the applicable block weight limit.
===Network protocol===
If a light client detects that one or more of its peers do not consider the block it knows to have the most work as their best block, it should inquire with all those peers for a fraud proof by sending a new message getfraud, with a block locator (between the last common block, and the presumed best tip) as the sole parameter (extra parameters should be ignored).
Compatible nodes will respond with a (new) fraud message, which has 2-3 parameters:
* uint256: The hash of the most recent block in the locator (or a parent thereof) that it has checked. In the event of an invalid block, this should be the exact invalid block's hash (post-invalid blocks should be treated as unchecked, even if the node has independently checked them for some reason).
* varint: Fraud proof type code
** 0 = Block is valid
** 1 = No fraud proof available
** 2 = Size/weight exceeded
* (For type 2) the fraud proof
If none of the blocks in the locator are recognised, compatible nodes should send a fraud message with no parameters.
(To avoid this outcome, clients may include a known-common block in the locator.)
In the event that the peer claims a block earlier than the client's tip is valid, the light client should prepare a new locator between that block and its tip, and rerequest getfraud until it has determined which block the peer rejects and why.
Once a block is proven to be invalid, the light client should never consider any blockchain including it as a candidate for the best chain.
It should not recheck blocks known to be invalid, nor continue proving it from other nodes.
(To avoid doubt: the user MAY be given the opportunity to override any rejections, but should be warned of the implications of doing so.)
If an invalid fraud proof is provided, the client SHOULD CONSIDER disconnecting and possibly banning the node providing it.
However, if any change has been made to the size/weight limits, that should be taken into consideration (eg, if the limit increases, an innocent node may prove a size smaller than the limit).
==Information==
===Creation of proofs===
Proofs should ideally use the smallest amount of data required to prove excess of the limit.
The most obvious mechanism in doing so, would be to include full tx size proofs for the largest transactions until the limit is exceeded.
However, in some cases, a smaller size may be accomplished by collapsing more merkle links.
Because optimisation of proof size may be complicated, nodes are not required to implement it in any particular manner, so long as the proofs meet the requirements given above in [[#proof-verification|Proof verification]].
==Motivation==
Recently, there have been proposals for hardforks to increase the block size limit.
While no consensus has been reached, proponents of these ideas often threaten and attempt to have miners force them through anyway.
As things presently are, light clients cannot detect invalid blocks at all, and could be fooled into accepting an invalid chain created in such a manner.
By supporting block size fraud proofs, light clients can protect their users from this form of unconsensual "hardfork" attempt.
==Rationale==
Why must a full tx size proof be included?
* This is necessary to establish that the claimed block transaction count is not inflated. Otherwise, a prover could claim any number of represented transactions for merkle links, and rely on the default size alone to exceed the limit.
How does the full tx size proof actually prove the size?
* The first step of SHA2 hashing is to transform the input data into chunks (per [https://tools.ietf.org/html/rfc4634#section-4.1 RFC 4634]). The final chunk is required to include the absolute length of the input data at the end of the final chunk. Therefore, by committing to the midstate prior to the final chunk, and replaying only the final chunk, we can confirm that the claimed size matches the full transaction data being hashed.
How does this prove the block weight?
* The block weight defined by [[bip-0141.mediawiki|BIP 141]] is the size of the block stripped of its segwit signatures times 3, plus the full size of the block. By proving lower-bound sizes of both the stripped block and the full block, a lower-bound weight can also be calculated.
Why is the number of transactions in the block represented as a log2?
* To avoid attacks that rely on fooling clients by claiming an amount they cannot verify.
Why does it matter if a full tx size proof is on the right side of a duplicate merkle link?
* We assume full tx size proofs show the number of transactions in the block. This assumption doesn't hold if the proof is provided on the right-hand side of duplicate links.
Why a fraud proof only for oversized/overweight blocks?
* While it is currently believed to be impossible to prove all invalid (or rather, won't-be-part-of-the-main-chain) blocks, there are regularly active proposals of miners attacking with simply oversized blocks in an attempt to force a hardfork. This specific attack can be proven, and reliably so, since the proof cannot be broken without also breaking the attempted hardfork at the same time.
==Backwards compatibility==
These fraud proofs protect only clients which use them.
In non-attack scenarios, they are unnecessary and clients supporting them will otherwise behave as any other.
==Reference implementation==
TODO
================================================
FILE: bip-0197.mediawiki
================================================
BIP: 197
Layer: Applications
Title: Hashed Time-Locked Collateral Contract
Authors: Matthew Black
Tony Cai
Status: Draft
Type: Specification
Assigned: 2019-03-19
License: BSD-3-Clause OR CC0-1.0
==Abstract==
This BIP describes a script for generalized debt agreement contract based on Hashed Time-Lock Contract (BIP 199) transactions according to the Atomic Loans specification (https://arxiv.org/pdf/1901.05117.pdf). For more details visit https://atomicloans.io.
==Summary==
A Hashed Time-Locked Collateral Contract (HTLCC) consists of two scripts that permit a designated party (the "borrower") to lock funds on the Bitcoin chain for a specified amount of time as collateral in a debt agreement where the loan principal is denominated in a currency on another blockchain. We denote the blockchain on which the loan principal is issued the principal blockchain.
The purpose of each script is to enable the creation of a debt agreement between two parties (the "borrower" and the "lender"), where the collateral is locked in a P2SH, and can only be spent once the borrower repays the principal and interest in the debt agreement on the principal blockchain. In the case that the borrower does not repay, the borrower or lender can opt for liquidation of the collateral, which will involve the atomic swapping of collateral for the loan currency. In the case that at least one of the two parties don't opt for liquidation, then each party will be entitled to a percentage of the collateral, decided when the funds are initially locked in the P2SH.
These funds are locked into two scripts. Refundable Collateral and Seizable Collateral scripts. The funds sent to these scripts represent the percentage of collateral that each party is entitled to in the case that repayment fails, and the parties don't opt for liquidation.
The Refundable Collateral script takes the following form:
OP_IF
OP_SIZE OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
OP_ELSE
OP_IF
[TIMEOUTOP] OP_DROP OP_SIZE OP_PUSHDATA(1) OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_SIZE OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_2 OP_2 OP_CHECKMULTISIG
OP_ELSE
[TIMEOUTOP] OP_DROP OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
OP_ENDIF
OP_ENDIF
The Seizable Collateral script takes the following form:
OP_IF
OP_SIZE OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
OP_ELSE
OP_IF
[TIMEOUTOP] OP_DROP OP_SIZE OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_SIZE OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_2 OP_2 OP_CHECKMULTISIG
OP_ELSE
OP_IF
[TIMEOUTOP] OP_DROP OP_SIZE OP_EQUALVERIFY [HASHOP] OP_EQUALVERIFY OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
OP_ELSE
[TIMEOUTOP] OP_DROP OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
OP_ENDIF
OP_ENDIF
OP_ENDIF
[HASHOP] is either OP_SHA256 or OP_HASH160.
[TIMEOUTOP] is either OP_CHECKSEQUENCEVERIFY or OP_CHECKLOCKTIMEVERIFY.
===Interaction===
* Alice (the "borrower") and Bob (the "lender") exchange public keys as well as two secret hashes A1, A2 created by Alice and three hashes B1, B2, B3 created by Bob. They then mutually agree upon a timeout threshold for the Loan Period, Liquidation Period, and Seizure Period. Alice constructs the script and P2SH address for the Refundable Collateral Contract and Seizable Collateral Contract. Bob constructs the script for the blockchain on which the loan principal will be issued - the principal blockchain.
* Bob sends loan principal funds to the loan script on the principal blockchain
* Alice sends funds to the Refundable Collateral P2SH address and the Seizable Collateral P2SH address. The amount of funds she sends to the two addresses will be determined beforehand off-chain between Alice and Bob.
* Either
** Bob accepts locking of collateral by Alice and reveals B1, allowing Alice to withdraw the loan amount on the principal blockchain.
** Bob doesn't accept locking of collateral by Alice, and recovers the funds after the approve expiration while revealing B2, which allows Alice to refund the Refundable and Seizable collateral.
** If Bob accepts the locking of collateral by Alice
*** Either
**** Alice repays the loan by the end of the Loan Period and Bob reveals the secret to Alice by revealing it in the loan repayment acceptance transaction; OR
**** Alice defaults on the loan and Alice and Bob both opt for collateral liquidation, where any third-party is able to bid on the collateral. The winning bidder, Charlie, will subsequently receive the liquidated collateral by way of an Atomic Swap between the collateral funds (ie. BTC locked in both the Refundable Collateral P2SH and the Seizable Collateral P2SH) and the bid funds (ie. funds denominated in the loan currency, put forth by Charlie as part of his bid). This is done by both Alice and Bob signing a multisig and revealing A2 and B2; OR
**** Alice defaults on the loan and at least one of Alice or Bob opts out of collateral liquidation, then Alice recovers the Refundable Collateral funds and Bob spends the Seizable Collateral funds.
**** Alice defaults on the loan and at least one of Alice or Bob opts out of collateral liquidation. But Bob doesn't spend the Seizable Collateral funds, so Alice recovers both the Refundable Collateral funds and the Seizable Collateral funds.
==Compatibility==
BIP 197 is compatible with [https://github.com/ethereum/EIPs/pull/1850 ERC 1850] for [https://arxiv.org/pdf/1901.05117.pdf atomic loans] with Ethereum. Can be extended in the future to be compatible with other HTLC and smart contract compatible chains.
==Motivation==
In many different protocols, the revealing of secrets is used as a settlement mechanism. HTLCC transactions are a safe way of exchanging secrets to advance the state of a debt agreement, due to the ability to recover a percentage of collateral funds from an uncooperative counterparty, and ensure principal + interest + liquidation fee is paid with a cooperative party.
==Definitions==
borrower: entity that locks collateral on the Bitcoin chain and receives loan amount on principal blockchain from lender following the approval of the borrower’s borrow request
lender: entity that contributes funds to the Hashed Time-Locked Principal Contract (HTLPC) on the principal blockchain, to be borrowed by the borrower upon the locking of collateral on the Bitcoin chain and the lender’s approval
repay: when the borrower pays back the principal + interest before loanExpiration
default: when the borrower fails to pay back the principal + interest before the loanExpiration
secret: random number chosen by the borrower or lender, revealed to allow the parties to change the state of the debt agreement
secretHash: hash of the secret, used in the construction of HTLCC
SecretA1: secret generated by the borrower, used to prove that the borrower has withdrawn the loan
SecretA2: secret generated by the borrower, used to allow the bidder to withdraw the liquidated collateral funds
SecretB1: secret generated by the lender, used to accept the locking of collateral by borrower, enabling borrower to withdraw the loan amount
SecretB2: secret generated by the lender, used to refund themselves in the event they aren't satisfied with borrower’slocking of collateral. Also used to accept borrower’s repayment of principal plus interest
SecretB3: secret generated by the lender, used to allow the bidder to withdraw the liquidated collateral funds
SecretC: secret generated by the bidder, used to accept the signatures of the borrower and lender for authorizing the liquidation of collateral
loan expiration num: timestamp before which the borrower must repay the loan; or otherwise risk the liquidation or seizure of their collateral
bidding expiration num: timestamp that determines the amount of time allocated to bidding before seizure period occurs
seizure expiration num: timestamp that determines the amount of time during which the lender can seize funds within the Seizable Collateral P2SH, after which the borrower can refund their corresponding amount of the collateral they are entitled to (ie. either just the funds within the Refundable Collateral P2SH, or both the Refundable Collateral and Seizable Collateral in the event where the lender failed to seize).
===Approve Period===
During this time, the lender deploys the HTLPC on the principal blockchain. Following this, the borrower locks their collateral on the Bitcoin blockchain in a HTLCC. The lender then either reveals secretB1 to signify that they are satisfied with the collateral, and the borrower can withdraw the loan by revealing secretA1. If the lender is not satisfied with the collateral locked by the borrower, the lender can refunds their loan amount by revealing secretB2, which will subsequently allow the borrower to refund the collateral amount they deposited.
===Loan Period===
Once the borrower has withdrawn the loan amount, the Loan Period begins. Once the Loan Period is finished, the borrower is expected to repay the loan. If they do, the lender can then accept the repayment by revealing secretB2, enabling the borrower to refund their collateral amount. In the case that the borrower defaults or does not repay the full principal plus interest amount, the lender can choose to not accept the loan repayment, and the parties can opt for liquidation of the collateral in the Bidding Period.
===Bidding Period===
In the case of a default or the lender not accepting the borrower repayment, the lender and borrower can opt for liquidation of the collateral through the process of third party bidders bidding on the collateral. The Bidding Period can be initiated by either the lender or the borrower. Once the bidding timeout occurs, the lender and borrower must each provide a signature, followed by secretC revealed by the winning bidder once they have checked that the signature is proper. Finally, the lender and borrower must each reveal secretA2 and secretB3 to allow the collateral to be withdrawn by the winning bidder.
===Seizure Period===
In the case that either the lender or borrower don’t accept the bid, the lender can seize a percentage of the collateral. The amount is dependent on the amount of collateral locked in the Seizable Collateral and Refundable Collateral script as described in this BIP. During this period, the borrower can also refund the funds locked in the Refundable Collateral script.
===Refund Period===
In the case that the lender does not seize the collateral locked in the Seizable Collateral script, then the borrower can refund the funds locked in the Seizable Collateral script.
==Rationale==
The rational for the following script checking the length of secrets pushed to the stack that are used with OP_SHA256 in the following script
OP_SIZE OP_EQUALVERIFY
is to ensure that the secret size is exactly a certain number of bytes long.
This is especially important when this script is used alongside the HTLPC on other chains like Ethereum where the sha256 opcode only takes up 32 bytes and disregards the rest, there is a need to ensure that the length on the Bitcoin side is 32 bytes.
==Backwards Compatibility==
As this is a new standard for collateralized debt, there is no need for backward compatibility. Once this is accepted as a standard there are certain aspects of the contract that can be modified while still retaining backwards compatibility, such as removing the need to verify the size of the hash if being used with two blockchains with the same maximum block size, which would be backward compatible with the current script.
==Implementation==
https://github.com/AtomicLoans/chainabstractionlayer/blob/dev/packages/bitcoin-collateral-provider/lib/BitcoinCollateralProvider.js
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0199.mediawiki
================================================
BIP: 199
Layer: Applications
Title: Hashed Time-Locked Contract transactions
Authors: Sean Bowe
Daira Hopwood
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0199
Status: Closed
Type: Specification
Assigned: 2017-03-27
License: BSD-3-Clause OR CC0-1.0
==Abstract==
This BIP describes a script for generalized off-chain contract negotiation.
==Summary==
A Hashed Time-Locked Contract (HTLC) is a script that permits a designated party (the "seller") to spend funds by disclosing the preimage of a hash. It also permits
a second party (the "buyer") to spend the funds after a timeout is reached, in a refund situation.
The script takes the following form:
OP_IF
[HASHOP] OP_EQUALVERIFY OP_DUP OP_HASH160
OP_ELSE
[TIMEOUTOP] OP_DROP OP_DUP OP_HASH160
OP_ENDIF
OP_EQUALVERIFY
OP_CHECKSIG
[HASHOP] is either OP_SHA256 or OP_HASH160.
[TIMEOUTOP] is either OP_CHECKSEQUENCEVERIFY or OP_CHECKLOCKTIMEVERIFY.
===Interaction===
* Victor (the "buyer") and Peggy (the "seller") exchange public keys and mutually agree upon a timeout threshold. Peggy provides a hash digest. Both parties can now construct the script and P2SH address for the HTLC.
* Victor sends funds to the P2SH address.
* Either:
** Peggy spends the funds, and in doing so, reveals the preimage to Victor in the transaction; OR
** Victor recovers the funds after the timeout threshold.
Victor is interested in a lower timeout to reduce the amount of time that his funds are encumbered in the event that Peggy does not reveal the preimage. Peggy is
interested in a higher timeout to reduce the risk that she is unable to spend the funds before the threshold, or worse, that her transaction spending the funds does
not enter the blockchain before Victor's but does reveal the preimage to Victor anyway.
==Motivation==
In many off-chain protocols, secret disclosure is used as part of a settlement mechanism. In some others, the secrets themselves are valuable. HTLC transactions are
a safe and cheap method of exchanging secrets for money over the blockchain, due to the ability to recover funds from an uncooperative counterparty, and the
opportunity that the possessor of a secret has to receive the funds before such a refund can occur.
===Lightning network===
In the lightning network, HTLC scripts are used to perform atomic swaps between payment channels.
Alice constructs K and hashes it to produce L. She sends an HTLC payment to Bob for the preimage of L. Bob sends an HTLC payment to Carol for the same preimage and
amount. Only when Alice releases the preimage K does any exchange of value occur, and because the secret is divulged for each hop, all parties are compensated. If
at any point some parties become uncooperative, the process can be aborted via the refund conditions.
===Zero-knowledge contingent payments===
Various practical zero-knowledge proving systems exist which can be used to guarantee that a hash preimage derives valuable information. As an example, a
zero-knowledge proof can be used to prove that a hash preimage acts as a decryption key for an encrypted sudoku puzzle solution. (See
[https://github.com/zcash/pay-to-sudoku pay-to-sudoku] for a concrete example of such a protocol.)
HTLC transactions can be used to exchange such decryption keys for money without risk, and they do not require large or expensive-to-validate transactions.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/7601
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0300/images.txt
================================================
Images used as reference in the documentation.
================================================
FILE: bip-0300.mediawiki
================================================
==Abstract==
BIP-300 enables a new type of L2, where "withdrawals" (the L2-to-L1 txns) are governed by proof-of-work -- instead of a federation or fixed set of pubkeys.
BIP-300 emphasizes slow, transparent, and auditable withdrawals that are easy for honest users to get right and hard for dishonest miners to abuse. The main design goal for BIP-300 is ''partitioning'' -- users can ignore BIP-300 txns if they wish; it makes no difference to L1 if the user validates all, some, or none of them. The second design goal is ''security'' -- users of the L2 should feel confident that, [https://www.drivechain.info/blog/fees/ if the L2 network is paying a lot of fees], then miners will want to keep it around, and the withdrawals will therefore be processed accurately.
Once BIP-300 has established a "bridge" between L1 and these L2s, users can swap coins in and out instantly, only using BIP-300 for final settlement. This setup allows Bitcoin to process all the transactions in the world, of any shape or size, regardless of blocksize, node software, tech stack, or decentralization level -- all without altering L1 at all.
==Motivation==
BIP-300 allows us to achieve [https://www.truthcoin.info/blog/zside-meltcast/ strong privacy], [https://www.truthcoin.info/blog/thunder/ planetary scale], and [https://www.truthcoin.info/blog/all-world-txns/ hundreds of billions of dollars in annual mining revenues], all with a [https://www.drivechain.info/blog/fees/ security model] that is [https://x.com/Truthcoin/status/1701959339508965405 much stronger than] that of the [https://www.truthcoin.info/blog/ln-blackpill/ Lightning Network].
The original motivation stretches back to Reid Hoffman, who [https://blockstream.com/2015/01/13/en-reid-hoffman-on-the-future-of-the-bitcoin-ecosystem/ wrote in 2014]: "Sidechains allow developers to add features and functionality to the Bitcoin universe without actually modifying the Bitcoin Core code...Consequently, innovation can occur faster, in more flexible and distributed ways, without losing the synergies of a common platform with a single currency."
See [http://www.drivechain.info/ drivechain.info] for more information.
==Specification==
===Overview===
BIP-300 consists of six new blockchain messages:
* M1. "Propose New Sidechain"
* M2. "ACK Proposal"
* M3. "Propose Bundle"
* M4. "ACK Bundle"
* M5. Deposit -- a transfer of BTC from-main-to-side
* M6. Withdrawal -- a transfer of BTC from-side-to-main
Nodes organize this data into [https://github.com/LayerTwo-Labs/bip300301_enforcer/blob/13a4353c39a26d9d40180ea361b7580fd682e5b5/src/bip300.rs#L79-L96 a few caches], mainly these two:
* D1. "The Sidechain List"
* D2. "The Withdrawal List"
==== D1 (The Sidechain List) ====
D1 is a list of active sidechains. D1 is populated via M1 and M2. Fields #9 and #10 are updated via M5 and M6.
{| class="wikitable"
|- style="font-weight:bold; text-align:center; vertical-align:middle;"
! Field No.
! Label
! Type
! Description / Purpose
|- style="vertical-align:middle;"
| 1
| Escrow Number
| uint8_t
| The escrow's ID number. Used to uniquely refer to each sidechain.
|-
| 2
| Version
| int32_t
| Version number.
|-
| 3
| Sidechain Name
| string
| A human-readable name of the sidechain.
|- style="vertical-align:middle;"
| 4
| Sidechain Description
| string
| A human-readable name description of the sidechain.
|- style="vertical-align:middle;"
| 5
| Hash1 - tarball hash
| uint256
| Intended as the sha256 hash of the tar.gz of the canonical sidechain software. (This is not enforced by BIP-300, and is for human purposes only.)
|- style="vertical-align:middle;"
| 6
| Hash2 - git commit hash
| uint160
| Intended as the git commit hash of the canonical sidechain node software. (This is not enforced by BIP-300, and is for human purposes only.)
|-
| 7
| Active
| bool
| Does this sidechain slot contain an active sidechain?
|- style="vertical-align:middle;"
| 8
| Activation Status
| int , int
| The age of the proposal (in blocks); and the number of "fails" (a block that does NOT ack the sidechain). This is discarded after the sidechain activates.
|- style="vertical-align:middle;"
| 9
| "CTIP" -- "TxID"
| uint256
| A UTXO that holds the sidechain's money. (Part 1 of 2).
|- style="vertical-align:middle;"
| 10
| "CTIP" -- "vout"
| int32_t
| A UTXO that holds the sidechain's money. (Part 2 of 2).
|}
==== D2 (The Withdrawal List) ====
Withdrawals are transactions that remove coins "from" L2 (i.e., from the BIP-300 locked UTXO), and place them back on L1. Each BIP-300 withdrawal can pay out up to 6,000 withdrawals, and only one withdrawal can succeed at a time (per L2). Therefore, since all L2 users share the same large withdrawal-event, on L1 we call these withdrawals "bundles".
D2 is driven by M3, M4, M5, and M6. Those messages enforce the following principles:
# The database has a canonical order (first come first serve).
# From one block to the next, every "Blocks Remaining" field decreases by 1.
# When "Blocks Remaining" reaches zero, the bundle is removed.
# From one block to the next, the value in "ACKs" may either increase or decrease, by a maximum of 1 (see M4).
# If a bundle's "ACKs" reach 13150 or greater, it "succeeds" and its corresponding M6 message can be included in a block.
# If the M6 of a bundle is paid out, it is also removed.
# If a bundle cannot possibly succeed ( 13150 - "ACKs" > "Blocks Remaining" ), it is removed immediately.
{| class="wikitable"
! Field No.
! Label
! Type
! Description / Purpose
|-
| 1
| Sidechain Number
| uint8_t
| Links the withdrawal-request to a specific hashrate escrow.
|-
| 2
| Bundle Hash
| uint256
| A withdrawal attempt. Specifically, it is a "blinded transaction id" (i.e., the double-Sha256 of a txn that has had two fields zeroed out, see M6) of a txn which could withdraw funds from a sidechain.
|-
| 3
| Work Score (ACKs)
| uint16_t
| How many miner upvotes a withdrawal has. Starts at 0. Fastest possible rate of increase is 1 per block.
|-
| 4
| Blocks Remaining
| uint16_t
| How long this bundle has left to live (measured in blocks). Starts at 26,300 and counts down.
|}
=== M1 -- Propose Sidechain ===
New sidechains are proposed with M1, and ACKed with M2.
M1 is a coinbase OP Return output containing the following:
1-byte - OP_RETURN (0x6a)
4-byte - Message header (0xD5E0C4AF)
N-byte - The serialization of the sidechain.
1-byte nSidechain
4-byte nVersion
x-byte title
x-byte description
32-byte hashID1
20-byte hashID2
M1 is invalid if:
* It would add a duplicate entry to D1.
* There is already an M1 in this block.
* The sidechain serialization does not parse.
Otherwise:
* A new entry is added to D1, whose initial Activation Status is (age=0, fails=0).
=== M2 -- ACK Sidechain Proposal ===
M2 is a coinbase OP Return output containing the following:
1-byte - OP_RETURN (0x6a)
4-byte - Message header (0xD6E1C5BF)
32-byte - the sha256D hash of sidechain's serialization
M2 is ignored if it doesn't parse, or if it is for a sidechain that doesn't exist.
M2 is invalid if:
* An M2 is already in this block.
* It tries to ACK two different M1s for the same slot.
Otherwise:
* The sidechain is "ACK"ed and does NOT get a "fail" for this block. (As it otherwise would.)
A sidechain fails to activate if:
* If the slot is unused: during the next 2016 blocks, it accumulates 1008 fails (i.e., 50% hashrate threshold).
* If the slot is in use: during the next 26,300 blocks, it accumulates 13,150 fails (i.e., 50% hashrate threshold).
( Thus we can overwrite a used sidechain slot. BIP-300 sidechains are already vulnerable to one catastrophe per 13150 blocks (the invalid withdrawal), so this slot-overwrite option does not change the security assumptions. )
Otherwise, the sidechain activates (Active is set to TRUE).
=== Withdrawing in Bundles ===
Sidechain withdrawals take the form of "bundles" -- named because they "bundle up" many individual withdrawal-requests into a single rare L1 transaction.
On the L2 side, individual withdrawal requests are periodically combined into a single CoinJoin-like withdrawal bundle. This bundle is hashed [https://github.com/LayerTwo-Labs/bip300301_messages/blob/398b224981c7c236c8354704e655996d33685149/src/lib.rs#L374C1-L419C2 in a particular way] (on both L2 and L1) -- this "blinded hash" commits to its own L1 fee, but (notably) it does not commit to its first tx-input (in that way, it is like [https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki BIP-118]).
This hash is what L1 miners will slowly ACK over 3-6 months, not the M6 itself (nor any sidechain data, of course).
A bundle will either pay all its withdrawals out (via M6), or fail (and pay nothing out for anyone).
=== M3 -- Propose Bundle ===
M3 is a coinbase OP Return output containing the following:
1-byte - OP_RETURN (0x6a)
4-byte - Commitment header (0xD45AA943)
32-byte - The bundle hash, to populate a new D2 entry
1-byte - nSidechain (the slot number)
M3 is ignored if it does not parse, or if it is for a sidechain that doesn't exist.
M3 is invalid if:
* This block already has an M3 for that nSidechain.
* A bundle with this hash is already in D2.
* A bundle with this hash already paid out.
* A bundle with this hash was rejected in the past.
Otherwise: M3 adds an entry to D2, with initial ACK score = 1 and initial Blocks Remaining = 26,299. (Merely being added to D2, does count as your first upvote.)
=== M4 -- ACK Bundle(s) ===
Once a bundle is in D2, how can we give it enough ACKs to make it valid?
M4 is a coinbase OP Return output containing the following:
1-byte - OP_RETURN (0x6a)
4-byte - Commitment header (0xD77D1776)
1-byte - Version
n-byte - The "upvote vector" -- describes which bundle-choice is "upvoted", for each sidechain.
The M4 message will be invalid (and invalidate the block), if:
* It tries to upvote a bundle that doesn't exist. (For example, trying to upvote the 7th bundle on sidechain #2, when sidechain #2 has only three bundles.)
* There are no bundles at all, from any sidechain.
If M4 is NOT present in a block, then it is treated as an "abstain" for all sidechains.
If M4 is present and valid: each withdrawal-bundle that is ACKed, will gain one upvote.
Each sidechain always has two "virtual bundles" -- an "abstain" bundle (0xFF), and an "alarm" bundle (0xFE). Abstain leaves the ACK count unchanged, and alarm reduces all ACK counts of all bundles by 1.
Any bundle which fails to receive a vote, is downvoted (and loses 1 ACK). If a sidechain has no pending bundles, then it is skipped over when M4 is created and parsed.
==== Examples ====
To upvote the 7th bundle on sidechain #1, and upvote the 4th bundle on sidechain #2, the upvote vector would be { 07, 04 }. And M4 would be [0x6A,D77D1776,00,0006,0003].
If block 900,000 has D2 of...
{| class="wikitable"
|-
! SC#
! Bundle Hash
! ACKs
! Blocks Remaining
|-
| 1
| h1
| 45
| 22,109
|-
| 1
| h2
| 12
| 22,008
|-
| 2
| h3
| 13
| 22,999
|-
| 2
| h4
| 8
| 23,550
|-
| 2
| h5
| 2
| 22,560
|}
...and then D2 wants to become:
{| class="wikitable"
|-
! SC#
! Bundle Hash
! ACKs
! Blocks Remaining
|-
| 1
| h1
| 46
| 22,108
|-
| 1
| h2
| 11
| 22,007
|-
| 2
| h3
| 12
| 22,998
|-
| 2
| h4
| 9
| 23,549
|-
| 2
| h5
| 1
| 22,559
|}
... then M4 would have been [0x6A,D77D1776,00,0000,0001].
==== Saving Space ====
The version number allows us to shrink the upvote vector in many cases.
Version 0x00 omits the upvote vector entirely (i.e., 6 bytes for the whole M4) and sets this block's M4 equal to the previous block's M4.
Version 0x01 uses 1 byte per sidechain, and can be used while all ACKed withdrawals have an index <256 (i.e., 99.99%+ of the time).
Version 0x02 uses 2 bytes per sidechain, but it always works, even in astronomically unlikely cases (such as when >1 sidechains have >256 bundle candidates).
Version 0x03 omits the upvote vector, and instead upvotes only those withdrawals that are leading their rivals by at least 50 votes.
For example, an upvote vector of { 2 , N/A, 1 } would be represented as [0x6A,D77D1776,01,01,00]. It means: "upvote the second bundle in sidechain #1; and the first bundle in sidechain #3" (iff sidechains #2 has no bundles proposed).
An upvote vector of { N/A, N/A, 4 } would be [0x6A,D77D1776,01,03].
=== M5 -- Deposit BTC (from L1 to L2) ===
Finally, we describe Deposits (M5) and Withdrawals (M6). These are not coinbase outputs, they are txns on L1.
We call a transaction "M5" if it spends from the escrow output and '''increases''' the quantity of coins. Conversely, we call a transaction "M6" if it spends from the escrow output and '''decreases''' the quantity of coins. See [https://github.com/LayerTwo-Labs/bip300301_enforcer/blob/13a4353c39a26d9d40180ea361b7580fd682e5b5/src/bip300.rs#L462C1-L462C47 here].
Every time a deposit/withdrawal is made, the old UTXO is spent and a single new UTXO is created. (Deposits/Withdrawals never cause UTXO bloat.) At all times, the specific treasury UTXO ("CTIP") of each sidechain is cached in D1 (above).
Every M5 is valid, as long as:
* It has exactly one OP_DRIVECHAIN output -- this becomes the new CTIP.
* The new CTIP has '''more''' coins in it, than before.
=== M6 -- Withdraw BTC (from L2 to L1) ===
M6 is invalid if:
* The blinded hash of M6 does NOT match one of the approved bundle-hashes. (In other words: M6 must first be approved by 13,150 upvotes.)
* The first output of M6 is NOT an OP_DRIVECHAIN. (This OP_DRIVECHAIN becomes the new CTIP. In other words: all non-withdrawn coins are paid back to the sidechain.)
* The second output is NOT a zero-value OP_RETURN script of exactly 10 bytes, of which 8 bytes are a serialized Bitcoin amount.
* The txn fee of M6 is NOT exactly equal to the amount of the previous bullet point.
* There are additional OP_DRIVECHAIN outputs after the first one.
Else, M6 is valid -- and the funds are withdrawn.
(The point of the latter two bullet points, is to allow the bundle hash to cover the L1 transaction fee.)
===OP_DRIVECHAIN===
This proposal adds a single new opcode, OP_DRIVECHAIN, which has strict semantics for usage.
OP_NOP5 (0xb4) is redefined as OP_DRIVECHAIN if and only if the entire script is OP_DRIVECHAIN followed by a single-byte push and OP_TRUE (exactly 4 bytes).
The single-byte push contains the sidechain number.
Note that this is not a "script number", and cannot be OP_1..OP_16 or any other kind of push; it is also unsigned, and must not be padded even if over sidechain number 127.
The final OP_TRUE is to ensure this change remains a softfork:
without it, sidechain numbers 0 and 128 would cause the legacy script interpreter to fail.
If an OP_DRIVECHAIN input is spent, the additional rules for M5 or M6 (see above) must be enforced.
==Backward compatibility==
This soft fork can be deployed without modifying Bitcoin Core at all (i.e., via [https://bip300cusf.com/ CUSF]).
==Deployment==
This BIP deploys when/if >51% hashrate runs [https://github.com/LayerTwo-Labs/bip300301_enforcer/ the enforcer client].
Ideally, a critical mass of users would also run the enforcer client -- this would strongly dissuade miners from ever de-activating it.
==Reference Implementation==
The enforcer is [https://github.com/LayerTwo-Labs/bip300301_enforcer/ here].
Also, several example L2s are [https://releases.drivechain.info/ here].
==Copyright==
This BIP is licensed under the BSD 2-clause license.
================================================
FILE: bip-0301.mediawiki
================================================
==Abstract==
Blind Merged Mining (BMM) allows SHA-256d miners to collect transaction fee revenue from other blockchains, without running any new software (i.e., without "looking" at those alt-chains, hence "blind").
Instead, this block-assembly work is done by alt-chain users. They choose the alt-chain block, and what txns go in it, the fees etc. Simultaneously, these users "bid" on L1 to win the right to be the sole creator of the alt-chain block. BIP-301 ensures that L1 miners only accept one bid (per 10 minutes, per L2 category), instead of taking all of them (which is what they would ordinarily do).
==Motivation==
"Merged-Mining" (MM) allows miners to reuse their hashing work to secure other chains (for example, as in Namecoin).
However, traditional MM has two drawbacks:
# Miners must run a full node of the other chain(s). (Thus, they must run "non-Bitcoin" software which may be buggy.)
# Miners are paid on the other chain, in Alt-currency. (Miners who MM Namecoin, will earn NMC.)
==Notation and Example==
We use notation side:\* and main:\* in front of otherwise ambiguous words (such as "block", "node", or "chain"), to distinguish the mainchain version from its sidechain/alt-chain counterpart. We name all sidechain users "Simon", and name all mainchain miners "Mary".
Furthermore, here is an example of BIP-301 in use. Imagine that a side:block contains 20,000 txns, each paying a $0.10 fee; therefore, the side:block is worth $2000 of fee revenue. In BIP-301, the sidechain's coinbase txn will pay this $2000 to "Simon". Simon does no hashing, but instead makes one L1 txn paying $1999 to the L1 miners ("Mary"). Thus, Mary ends up with all of the fee revenue, even though she didn't do anything on the sidechain.
{| class="wikitable"
|-
! colspan="3" | Upon finding a sidechain block worth $2000...
|- style="font-weight:bold; text-decoration:underline;"
| Item
| Layer1 Miner ("Mary")
| Sidechain User ("Simon")
|-
| Runs a sidechain node?
| No
| Yes
|-
| How much hashing?
| 100%
| 0%
|-
| Coins collected, on Layer2
| $0
| $2000
|-
| Coins paid out, on Layer1
| $0
| $1999
|-
| Coins rec'd, on Layer1
| $1999
| $0
|-
| d(Net Worth)
| +$1999
| +$1
|}
BIP-301 makes this specialization-of-labor trustless on L1. If Mary takes Simon's money, then she must let Simon control the side:block.
==Specification==
Each candidate for next side:block is defined by its unique side:blockhash "h*". (Even if the entire rest of the L2 block is identical, different Simons will have different side:coinbases and therefore different h*.)
BIP-301 consists of two messages: "BMM Accept" and "BMM Request".
# "BMM Accept" -- A coinbase output in L1, which contains h*. Mary can only choose one h* to endorse.
# "BMM Request" -- A transaction where Simon offers to pay Mary, if (and only if) Mary's L1 block contains Simon's h*.
As a miner, Mary controls the main:coinbase, so she may select any h*. Her selection determines which side:block is "found" -- and which associated BMM Request she can collect.
=== BMM Accept ===
To "Accept" a BMM proposal (endorsing Simon's side:block, and allowing Mary to accept Simon's money later in the block), Mary places an OP_RETURN output into the main:coinbase as follows:
1-byte - OP_RETURN (0x6a)
4-bytes - Message header (0xD1617368)
1-byte - Sidechain number (0-255)
32-bytes - h* (obtained from Simon)
[https://github.com/LayerTwo-Labs/bip300301_messages/blob/dd26518ff9505ea9088436797171799f359d0076/src/lib.rs#L256-L268 Code details here].
If these OP_RETURN outputs are not present, then no Requests were accepted. (And, Mary would get no money from Requests.)
It is possible for Mary and Simon to be the same person. They would trust each other completely, so the BMM process would stop here. There would only be Accepts; Requests would be unnecessary.
When Simon and Mary are different people, Simon will need to use BMM Requests.
=== BMM Request ===
Simon will use BMM Requests to buy the "right" to find a sidechain block, from Mary.
For each side:block that Simon wants to attempt, he broadcasts a txn containing the following as an OP_RETURN:
1-byte - OP_RETURN (0x6a)
3-bytes - Message header (0x00bf00)
1-byte - Sidechain number (0-255)
32-bytes - h* (obtained from L2 node)
32-bytes - prevMainBlock (the blockhash of the previous main:block)
h* is chosen by Simon to correspond to the side:block he wants to mine on the alt-chain. nSidechain is the number assigned to the sidechain/alt-chain when it was created.
This txn is invalid if it fails any of the following checks:
# Each "BMM Request", must match one corresponding "BMM Accept" (previous section).
# Only one BMM Request is allowed in each main:block, per nSidechain. In other words, if 700 users broadcast BMM Requests for sidechain #4, then the main:miner must single out one BMM_Request_4 to include in this L1 block.
# The 32-bytes of prevMainBlock must match the previous main:blockhash. Thus, Simon's txns are only valid for the current block, in the block history that he knows about.
Most BMM Request txns will never make it into a block. Simon will make many BMM Requests, but only one will be accepted. Since only one BMM Request can enter the L1 block, Simon may feel comfortable making multiple offers all day long. This means Mary has many offers to choose from, and can choose the one that pays her the most.
This BIP allows BMM Requests to take place over Lightning. One method is [https://www.drivechain.info/media/bmm-note/bmm-lightning/ here]. (BMM Accepts cannot be over LN, since they reside in main:coinbase txns.)
==Backward compatibility==
This soft fork can be deployed without modifying Bitcoin Core at all (ie, via [https://bip300cusf.com/ CUSF]).
==Deployment==
This BIP deploys when/if >51% hashrate runs [https://github.com/LayerTwo-Labs/bip300301_enforcer/ the enforcer client].
Ideally, a critical mass of users would also run the enforcer client -- this would strongly dissuade miners from ever de-activating it.
==Reference Implementation==
The enforcer is [https://github.com/LayerTwo-Labs/bip300301_enforcer/ here].
Also, several example L2s using BIP-301 are [https://releases.drivechain.info/ here].
==Copyright==
This BIP is licensed under the BSD 2-clause license.
================================================
FILE: bip-0310.mediawiki
================================================
BIP: 310
Layer: Applications
Title: Stratum protocol extensions
Authors: Pavel Moravec
Jan Čapek
Status: Draft
Type: Informational
Assigned: 2018-03-10
License: BSD-3-Clause OR CC0-1.0
==Abstract==
This BIP provides a generic mechanism for specifying stratum protocol
extensions. At the same time, one of the important extensions that is
specified by this BIP is configuration of bits for "version rolling"
in nVersion field of bitcoin block header.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119.
==Motivation==
The initial motivation for specifying some general support for stratum
protocol extensions was a need to allow miners to do so called
"version rolling", changing value in the first field of the Bitcoin
block header.
Version rolling is backwards incompatible change to the stratum protocol
because the miner couldn't communicate different block version value to
the server in the original version of the stratum protocol. Similarly,
a server couldn't communicate safe bits for rolling to a miner. So
both miners and pools need to implement some protocol extension to
support version rolling.
Typically, if a miner sends an unknown message to a server, the server
closes the connection (not all implementations do that but some
do). So it is not very safe to try to send unknown messages to
servers.
We can use this opportunity to make one backwards incompatible
change to the protocol to support multiple extensions in the
future. In a way that a miner can advertise its capabilities and at
the same time it can request some needed features from the server.
It is preferable that the same mechanism for feature negotiation can
be used for not yet known features. It SHOULD be easy to implement in
the mining software too.
We introduce one new message to the stratum protocol ('''"mining.configure"''') which handles the initial configuration/negotiation of features in a generic way. So that adding features in the future can be done without a necessity to add new messages to stratum protocol.
Each extension has its unique string name, so called '''extension code'''.
==Specification==
Currently, the following extensions are defined:
* '''"version-rolling"'''
* '''"minimum-difficulty"'''
* '''"subscribe-extranonce"'''
===Additional data types===
The following names are used as type aliases, making the message
description easier.
* '''TMask''' - case independent hexadecimal string of length 8, encoding an unsigned 32-bit integer (~[0-9a-fA-F]{8})
* '''TExtensionCode''' - non-empty string with a value equal to the name of some protocol extension.
* '''TExtensionResult''' - true / false / ''String''.
** true = The requested feature is supported and its configuration understood and applied.
** false = The feature is not supported or unknown.
** ''String'' = Error message containing information about what went wrong.
===Request "mining.configure"===
This message (JSON RPC Request) SHOULD be the '''first message''' sent
by the miner after the connection with the server is established. The client
uses the message to advertise its features and to request/allow some
protocol extensions.
The reason for it being the first is that we want the implementation and
possible interactions to be as easy and simple as possible. An extension
can define explicitly what does a repeated configuration of that
extension mean.
Each extension code provides a namespace for its extension parameters
and extension return values. By convention, the names are formed from
extension codes by adding "." and a parameter name. The same applies
for the return values, which are transferred in a result map
too. E.g. "version-rolling.mask" is the name of the parameter "mask" of
extension "version-rolling".
'''Parameters''':
* '''extensions''' (REQUIRED, List of ''TExtensionCode'')
::- Each string in the list MUST be a valid extension code. The meaning of each code is described independently as part of the extension definition. A miner SHOULD advertise all its available features.
* '''extension-parameters''' (REQUIRED, ''Map of (String -> Any)'')
::- Parameters of the requested/allowed extensions from the first parameter.
'''Return value''':
* ''Map of (String -> Any)''
::- Each code from the '''extensions''' list MUST have a defined return value (''TExtensionCode'' -> ''TExtensionResult''). This way the miner knows if the extension is activated or not. E.g. {"version-rolling":false} for unsupported version rolling.
::- Some extensions need additional information to be delivered to the miner. The return value map is used for this purpose.
Example request (new-lines added):
(The miner requests extensions "version-rolling" and
"minimum-difficulty". It sets the parameters according to the extensions'
definitions.)
Example result (new-lines added):
=Defined extensions=
==Extension "version-rolling"==
This extension allows the miner to change the value of some bits in the
version field in the block header. Currently there are no standard bits
used for version rolling so they need to be negotiated between a
miner and a server.
A miner sends the server a mask describing bits which the miner is
capable of changing. 1 = changeable bit, 0 = not changeable (miner_mask)
and a minimum number of bits that it needs for efficient version rolling.
A server typically allows you to change only some of the version bits
(server_mask) and the rest of the version bits are
fixed. E.g. because the block needs to be valid or some signaling is
in place.
The server responds to the configuration message by sending a mask
with common bits intersection of the miner's mask and its a mask
(response = server_mask & miner_mask)
Example request (a miner capable of changing any 2 bits from a 16-bit mask):
{"method": "mining.configure", "id": 1, "params": [["version-rolling"], {"version-rolling.mask": "1fffe000", "version-rolling.min-bit-count": 2}]}
Example result (success):
{"error": null, "id": 1, "result": {"version-rolling": true, "version-rolling.mask": "18000000"}}
Example result (unknown extension):
{"error": null, "id": 1, "result": {"version-rolling": false}}
'''Extension parameters''':
* '''"version-rolling.mask"''' (OPTIONAL, ''TMask'', default value "ffffffff")
::- Bits set to 1 can be changed by the miner. This value is expected
to be stable for the whole mining session. A miner doesn't have to
send the mask, in this case a default full mask is used.
* '''"version-rolling.min-bit-count"''' (REQUIRED, ''Integer'', >= 0)
::- The miner also provides a minimum number of bits that it needs for efficient version rolling in hardware. Note that this parameter provides important diagnostic information to the pool server. If the requested bit count exceeds the limit of the pool server, the miner always has the chance to operate in a degraded mode without using full hashing power. The pool server SHOULD NOT terminate miner connection if this rare mismatch case occurs.
'''Extension return values''':
* '''"version-rolling"''' (REQUIRED, ''TExtensionResult'')
::- When responded with true, the server will accept new parameter of '''"mining.submit"''', see later.
* '''"version-rolling.mask"''' (REQUIRED, ''TMask'')
::- Bits set to 1 are allowed to be changed by the miner. If a miner changes bits with mask value 0, the server will reject the submit.
::- The server SHOULD return the largest mask possible (as many bits set to 1 as possible). This can be useful in a mining proxy setup when a proxy needs to negotiate the best mask for its future clients. There is a [https://github.com/bitcoin/bips/pull/661/files Draft BIP] describing available nVersion bits. The server SHOULD pick a mask that preferably covers all bits specified in the BIP.
===Notification '''"mining.set_version_mask"'''===
Server notifies the miner about a new mask valid for the
connection. This message can be sent at any time after the successful
setup of the version rolling extension by the "mining.configure"
message. The new mask is valid '''immediately''', so that the server
doesn't wait for the next job.
'''Parameters''':
* ''mask'' (REQUIRED, ''TMask''): The meaning is the same as the '''"version-rolling.mask"''' return parameter.
Example:
{"params":["00003000"], "id":null, "method": "mining.set_version_mask"}
===Changes in request '''"mining.submit"'''===
Immediately after successful activation of the version-rolling extension
(result to '''"mining.configure"''' sent by server), the server MUST accept
an additional parameter of the message '''"mining.submit"'''. The client MUST
send one additional parameter, '''version_bits''' (6th parameter, after
''worker_name'', ''job_id'', ''extranonce2'', ''ntime'' and ''nonce'').
'''Additional parameters''':
* ''version_bits'' (REQUIRED, ''TMask'') - Version bits set by miner.
::- Miner can set only bits corresponding to the set bits in the last received mask from the server either as response to "mining.configure" or "mining.set_version_mask" notification (last_mask). This must hold:
version_bits & ~last_mask == 0
::- The server computes ''nVersion'' for the submit as follows:
nVersion = (job_version & ~last_mask) | (version_bits & last_mask)
where job_version is the block version sent to miner as part of job with id job_id.
==Extension "minimum-difficulty"==
This extension allows miner to request a minimum difficulty for the
connected machine. It solves a problem in the original stratum
protocol where there is no way how to communicate hard limit of the
connected device.
'''Extension parameters''':
* '''"minimum-difficulty.value"''' (REQUIRED, ''Integer/Float'', >= 0)
::- The minimum difficulty value acceptable for the miner/connection. The value can be 0 for essentially disabling the feature.
'''Extension return values''':
* '''"minimum-difficulty"''' (REQUIRED, ''TExtensionResult'')
::- Whether the minimum difficulty was accepted or not.
::- This extension can be configured multiple times by calling "mining.configure" with "minimum-difficulty" code again.
==Extension "subscribe-extranonce"==
Parameter-less extension. Miner advertises its capability of receiving
message '''"mining.set_extranonce"''' message (useful for hash rate
routing scenarios).
==Extension "info"==
Miner provides additional text-based information.
'''Extension parameters''':
* '''"info.connection-url"''' (OPTIONAL, ''String'')
::- Exact URL used by the mining software to connect to the stratum server.
* '''"info.hw-version"''' (OPTIONAL, ''String'')
::- Manufacturer specific hardware revision string.
* '''"info.sw-version"''' (OPTIONAL, ''String'')
::- Manufacturer specific software version
* '''"info.hw-id"''' (OPTIONAL, ''String'')
::- Unique identifier of the mining device
==Compatibility==
Currently, there is a similar protocol feature '''mining.capabilities''' that
was intended for various protocol extensions. However, '''mining.configure'''
is incompatible with this feature as it requires a server response confirming
all accepted/negotiated extensions. The reason why we made it incompatible is
that '''mining.capabilities''' request has no associated response.
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0320.mediawiki
================================================
BIP: 320
Title: nVersion bits for general purpose use
Authors: BtcDrak
Status: Draft
Type: Specification
Assigned: 2018-03-01
License: BSD-3-Clause OR CC0-1.0
==Abstract==
This BIP reserves 16 bits of the block header nVersion field for general purpose use and removes their meaning for the purpose of version bits soft-fork signalling.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
==Motivation==
There are a variety of things that miners may desire to use some of the nVersion field bits for. However, due to their use to coordinate miner activated soft-forks, full node software will generate false warnings about unknown soft forks if those bits are used for non soft fork signalling purposes. By reserving bits from the nVersion field for general use, node software can be updated to ignore those bits and therefore will not emit false warnings. Reserving 16 bits for general use leaves enough for 13 parallel soft-forks using version bits.
===Example Uses===
The following are example cases that would benefit from using some of the bits from the nVersion field. This list is not exhaustive.
Bitcoin mining hardware currently can exhaust the 32 bit nonce field in less than 200ms requiring the controller to distribute new jobs very frequently to each mining chip consuming a lot of bandwidth and CPU time. This can be greatly reduced by rolling more bits. Rolling too many bits from nTime is not ideal because it may distort the timestamps over a longer period.
Version-rolling AsicBoost requires two bits from the nVersion field to calculate 4-way collisions. Any two bits can be used and mining equipment can negotiate which bits are to be used with mining pools via the Stratum "version-rolling" extension.
==Specification==
Sixteen bits from the block header nVersion field, starting from 13 and ending at 28 inclusive (0x1fffe000), are reserved for general use and removed from BIP8 and BIP9 specifications. A mask of 0xe0001fff should be applied to nVersion bits so bits 13-28 inclusive will be ignored for soft-fork signalling and unknown soft-fork warnings.
This specification does not reserve specific bits for specific purposes.
==Reference Implementation==
https://github.com/btcdrak/bitcoin/commit/d12516e136d4a8952904a13eedc9f4225f35dc3b
==Backwards Compatibility==
Non-upgraded nodes will interpret the reserved bits of this proposal as signals for soft forks, and may additionally activate the warning system for unknown soft forks.
This proposal does not require a soft fork to implement.
At the time of writing no known soft forks are pending using any of 16 bits reserved in this BIP, and given that a non-trivial percentage of the hashrate is already making uses of those bits, future soft forks SHOULD NOT utilise those bits for activation signalling.
==Acknowledgements==
Timo Hanke and Sergio Lerner for originally proposing 15-bit extra nNonce2.
==References==
[[bip-0008.mediawiki|BIP8]]
[[bip-0009.mediawiki|BIP9]]
[https://arxiv.org/pdf/1604.00575.pdf AsicBoost white paper]
[https://github.com/BlockheaderNonce2/bitcoin/wiki Blockheader Extra nNonce2 proposal]
[https://github.com/slushpool/stratumprotocol/blob/master/stratum-extensions.mediawiki Stratum protocol extension BIP for version-rolling]
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0321.mediawiki
================================================
BIP: 321
Layer: Applications
Title: URI Scheme
Authors: Matt Corallo
Status: Complete
Type: Specification
Assigned: 2024-11-15
License: BSD-2-Clause
Replaces: 21
== Copyright ==
This BIP is licensed under the BSD 2-clause license.
== Abstract ==
This BIP proposes a URI scheme for describing Bitcoin payment instructions.
== Motivation ==
The purpose of this URI scheme is to enable users to easily make payments by simply clicking links on webpages or scanning QR Codes.
This BIP is a modification and intended replacement of [[bip-0021.mediawiki|BIP 0021]] to add information about the modern usage of bitcoin: URIs (including standard query parameters and modern address types) as well as provide forward-looking guidance on how to incorporate new payment instructions. It further adds an optional extension to provide the payment initiator with proof of payment. BIP 21 was based on BIP 20, which was, in turn based on an earlier document by Nils Schneider.
== Specification ==
=== General rules for handling (important!) ===
Bitcoin clients MUST NOT act on URIs without getting the user's authorization.
They SHOULD require the user to manually approve each payment individually, though in some cases they MAY allow the user to automatically make this decision.
=== Operating system integration ===
Graphical bitcoin clients SHOULD register themselves as the handler for the "bitcoin:" URI scheme by default, if no other handler is already registered. If there is already a registered handler, they MAY prompt the user to change it once when they first run the client.
=== General Format ===
Bitcoin URIs follow the general format for URIs as set forth in RFC 3986. The path component consists of a bitcoin address, and the query component provides additional payment options.
Elements of the query component may contain characters outside the valid range. These must first be encoded according to UTF-8, and then each octet of the corresponding UTF-8 sequence must be percent-encoded as described in RFC 3986.
=== ABNF grammar ===
bitcoinurn = "bitcoin:" [ bitcoinaddress ] [ "?" bitcoinparams ]
bitcoinaddress = *base58 / *bech32 / *bech32m
bitcoinparams = bitcoinparam [ "&" bitcoinparams ]
bitcoinparam = [ amountparam / labelparam / messageparam / responseparam / otherparam / reqparam ]
amountparam = "amount=" *digit [ "." *digit ]
labelparam = "label=" *qchar
messageparam = "message=" *qchar
responseparam = [ "req-" ] "pop=" *qchar
otherparam = qchar *qchar [ "=" *qchar ]
reqparam = "req-" qchar *qchar [ "=" *qchar ]
Here, "qchar" corresponds to valid characters of an RFC 3986 URI query component, excluding the "=" and "&" characters, which this BIP takes as separators.
The scheme component ("bitcoin:") is case-insensitive, and implementations must accept any combination of uppercase and lowercase letters. The query parameter keys are also case-insensitive. Query parameter values and bitcoin address fields may be case-sensitive depending on their content.
Multiple query parameters with the same key MAY be included for query parameters representing payment instructions. Multiple query parameters with the same key MUST NOT be included for keys "label", "message", or "pop". Multiple query parameters with the same key for other keys MUST be allowed for unknown query parameters. Future query parameter keys may or may not allow for duplicate parameters.
=== Bitcoin Address ===
The bitcoinaddress body MUST be either a base58 P2SH or P2PKH address, bech32 Segwit version 0 address, bech32m Segwit address, or empty. Future address formats SHOULD instead be placed in query keys as optional payment instructions to provide backwards compatibility during upgrade cycles. The bitcoinaddress part of the URI MAY be left empty if there is at least one payment instruction provided in a query parameter, allowing for recipients wishing to avoid a standard on-chain fallback.
=== Query Keys ===
The following keys are defined generally and apply to any URI regardless of payment instructions:
*label: Label for the recipient (e.g. name of receiver)
*message: message that describes the transaction to the user ([[#Examples|see examples below]])
*pop: a URI which the Bitcoin Wallet may return to in order to provide the application which initiated the payment with proof that a payment was completed.
The following keys are currently defined for payment instructions of various forms:
*lightning: Lightning BOLT 11 invoices
*lno: Lightning BOLT12 offers
*pay: [[bip-0351.mediawiki|BIP 351 Private Payment addresses]]
*sp: [[bip-0352.mediawiki|BIP 352 Silent Payment addresses]]
New payment instructions using bech32 or bech32m encodings SHOULD reuse their address format's Human Readable Part as the parameter key.
==== Transfer amount ====
If an amount is provided, it MUST be specified in decimal BTC.
All amounts MUST contain no commas and use a period (.) as the separating character to separate whole numbers and decimal fractions.
I.e. amount=50.00 or amount=50 is treated as 50 BTC, and amount=50,000.00 is invalid.
=== Proof of Payment ===
The URI MAY include a "pop" (or "req-pop") parameter whose value can be used to build a URI which the wallet application can, after payment completes, "open" to provide proof the payment was completed or other information about the payment.
The value of a "pop" (or "req-pop") parameter shall be a percent-encoded (per RFC 3986 section 2.1) URI prefix. The wallet application, if it supports providing payment information SHOULD percent-decode the provided URI once, append the query parameter key from which the payment instructions used were read, append a single =, and finally append the Payment Information to the resulting URI and open it with the default system handler for the URI. For payment instructions read from the body of the URI, "onchain" SHALL be used in place of the key.
A wallet MUST validate that the provided URI's scheme is not (case-insensitive) "http", "https", "file", "javascript", "mailto" or any other scheme which will open in a web browser prior to opening it.
If a wallet will not open the pop scheme (either because it does not support returning payment information for the selected payment method or because it uses a URI scheme which should not be opened) and the parameter was passed as a "req-pop" parameter, the wallet MUST NOT initiate payment.
For payments made using an on-chain transaction, the Payment Information shall be the full (including witness data) Bitcoin transaction as it was broadcasted to the Bitcoin network, encoded in hex.
For payments made using a BOLT 11 invoice (communicated via the `lightning` parameter), the Payment Information shall be the hex-encoded payment preimage.
Other payment schemes will define their own Payment Information format. This BIP may be updated from time to time with Payment Information formats for other payment schemes.
== Rationale ==
=== Payment identifiers, not person identifiers ===
Best practices are that a unique address should be used for every transaction on-chain.
Therefore, a URI which contains an on-chain payment address MUST NOT represent an exchange of personal information, but a one-time payment instruction. URIs which represent only reusable non-address-reusing payment instructions (like Lightning BOLT12 offers or Silent Payments) MAY be reused as a wallet sees fit.
=== Proof of Payment ===
On many mobile operating systems (especially, or any operating system more generally), applications may "open" a bitcoin: URI in order to initiate a payment with the user's default wallet application. These payment-initiating applications may wish to learn about the completed payment.
For payments completed on-chain, this is largely addressed by having the payment-initiating application monitor the blockchain for payment completion, however for other payment schemes (e.g. lightning), no such global ledger of transactions exists. In that case, proof of payment must be provided via some other mechanism.
In order to avoid inadvertently revealing the sender's IP address or other information to the recipient, proof URIs must only be opened when they will simply switch to another locally-installed application (i.e. the application which initiated the payment). When clicking a URI from a website, the website should already have plenty of logic on its backend to process payment completion and a proof-of-payment callback is unnecessary.
== Reference Implementation ==
Documentation: https://docs.rs/bitcoin-payment-instructions
Code repository: https://github.com/rust-bitcoin/bitcoin-payment-instructions
== Forward compatibility ==
Query parameter keys which are prefixed with a req- are considered required. If a client does not implement handling a query parameter which has a key prefixed with req-, it MUST consider the entire URI invalid. Any other query parameters which are not implemented, but which are not prefixed with a req-, can be safely ignored.
As future new address types should be added using query parameters rather than the `bitcoinaddress` field, URIs seamlessly support various payment instructions while senders only need to support legacy instructions. This allows old senders to pay newer recipients which offer more modern payment instruction formats.
== Backward compatibility ==
Compared to BIP 21, this document describes standard query parameters containing payment instructions, makes query parameters case-insensitive, allows bech32 and bech32m addresses in the `bitcoinaddress` field, and allows for URIs with an empty `bitcoinaddress` field. Use of bech32 and bech32m `bitcoinaddress` fields were long-since common practice in 2024, and the `lightning` query parameter storing BOLT 11 payment instructions became common practice in the year or three leading up to 2024. Inclusion of standard query parameters was added to provide guidance on query parameter usage going forward.
Additionally, this BIP describes the "pop" query parameter, which was unused and will be ignored by BIP 21 implementations.
Any existing BIP 21 implementation should automatically be fully compliant with this BIP, as the changes only describe existing practice or impact future address format inclusion, with the one possible exception of query parameters being made case-insensitive. Note, however, that treating query parameters as case-insensitive is already common practice due to the use of mostly-uppercase URIs in QR codes.
== Appendix ==
=== Examples ===
==== URIs ====
Just the address:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W
Address with recipient's name as label:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Luke-Jr
Request 20.30 BTC to "Luke-Jr":
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=20.3&label=Luke-Jr
Request 50 BTC with message:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=50&label=Luke-Jr&message=Donation%20for%20project%20xyz
Request funds to be paid over lightning to a BOLT 11 invoice with a fallback to on-chain payments:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?lightning=lnbc420bogusinvoice
Request funds to be paid over lightning to a BOLT 11 invoice with no fallback:
bitcoin:?lightning=lnbc420bogusinvoice
Request funds to be paid over lightning to a BOLT 12 offer with no fallback:
bitcoin:?lno=lno1bogusoffer
Request funds to be paid over lightning to a BOLT 12 offer or silent payments address with no fallback:
bitcoin:?lno=lno1bogusoffer&sp=sp1qsilentpayment
Request funds to be paid to a silent payments address with no fallback:
bitcoin:?sp=sp1qsilentpayment
Request funds to be paid to a silent payments address with a fallback:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?sp=sp1qsilentpayment
Some future version that has variables which are (currently) not understood and required and thus invalid:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-somethingyoudontunderstand=50&req-somethingelseyoudontget=999
Some future version that has variables which are (currently) not understood but not required and thus valid:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?somethingyoudontunderstand=50&somethingelseyoudontget=999
Multiple segwit addresses may be included for various versions of segwit, note that the human-readable part for all of them is `bc`
bitcoin:?bc=bc1qufgy354j3kmvuch987xe4s40836x3h0lg8f5n2&bc=bc1p5swkugezn97763tl0yty6556856uug0q6jflljvep9m4p7339x5qzyrh4g
Many QR codes utilize all-uppercase URIs, which should be handled fine
BITCOIN:BC1QUFGY354J3KMVUCH987XE4S40836X3H0LG8F5N2?BC=BC1P5SWKUGEZN97763TL0YTY6556856UUG0Q6JFLLJVEP9M4P7339X5QZYRH4G
BITCOIN:?BC=BC1QUFGY354J3KMVUCH987XE4S40836X3H0LG8F5N2&BC=BC1P5SWKUGEZN97763TL0YTY6556856UUG0Q6JFLLJVEP9M4P7339X5QZYRH4G
A testnet segwit addresses must be included in the `tb` parameter
bitcoin:?tb=tb1qghfhmd4zh7ncpmxl3qzhmq566jk8ckq4gafnmg
Characters must be URI encoded properly.
==== Invalid URIs ====
Labels must not appear twice:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?label=Luke-Jr&label=Matt
Amounts must not appear twice:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=42&amount=10
Amounts must not appear twice even if they are the same:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?amount=42&amount=42
Multiple proof of payment URIs must not appear, even if they are sometimes prefixed with req-:
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?pop=callback%3a&req-pop=callback%3a
A testnet segwit addresses must be included in the `tb` parameter, not the `bc` parameter.
bitcoin:?bc=tb1qghfhmd4zh7ncpmxl3qzhmq566jk8ckq4gafnmg
==== Proof of Payment ====
If the original URI is
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?pop=initiatingapp%3a
the wallet should perform the payment information callback by opening
initiatingapp:onchain=$HEX_ENCODED_TRANSACTION
If the original URI is
bitcoin:?lightning=lnbc420bogusinvoice&pop=callbackuri%3abody%3fpop=
the wallet should perform the proof-of-payment callback by opening
callbackuri:body?pop=lightning=$HEX_ENCODED_PAYMENT_PREIMAGE
If the original URI is
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?lightning=lnbc420bogusinvoice&pop=app%3a%3f
and the wallet pays on-chain, it should perform the payment information callback by opening
app:?onchain=$HEX_ENCODED_TRANSACTION
but if the app pays using lightning, it should perform the proof-of-payment callback by opening
app:?lightning=$HEX_ENCODED_PAYMENT_PREIMAGE
If the original URI is
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?pop=https%3aiwantyouripaddress.com
the wallet should make a payment as it normally would but MUST NOT interact with iwantyouripaddress.com
If the original URI is
bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?req-pop=https%3aevilwebsite.com
the wallet MUST NOT make a payment
================================================
FILE: bip-0322.mediawiki
================================================
BIP: 322
Layer: Applications
Title: Generic Signed Message Format
Authors: Karl-Johan Alm
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0322
Status: Draft
Type: Specification
Assigned: 2018-09-10
License: CC0-1.0
== Abstract ==
A standard for interoperable signed messages based on the Bitcoin Script format, either for proving fund availability, or committing to a message as the intended recipient of funds sent to the invoice address.
== Motivation ==
The current message signing standard only works for P2PKH (1...) invoice addresses. We propose to extend and generalize the standard by using a Bitcoin Script based approach. This ensures that any coins, no matter what script they are controlled by, can in-principle be signed for. For easy interoperability with existing signing hardware, we also define a signature message format which resembles a Bitcoin transaction (except that it contains an invalid input, so it cannot be spent on any real network).
Additionally, the current message signature format uses ECDSA signatures which do not commit to the public key, meaning that they do not actually prove knowledge of any secret keys. (Indeed, valid signatures can be tweaked by 3rd parties to become valid signatures on certain related keys.)
Ultimately no message signing protocol can actually prove control of funds, both because a signature is obsolete as soon as it is created, and because the possessor of a secret key may be willing to sign messages on others' behalf even if it would not sign actual transactions. No signmessage protocol can fix these limitations.
== Types of Signatures ==
This BIP specifies three formats for signing messages: ''legacy'', ''simple'' and ''full''. Additionally, a variant of the ''full'' format can be used to demonstrate control over a set of UTXOs.
=== Legacy ===
New proofs should use the new format for all invoice address formats, including P2PKH.
The legacy format MAY be used, but must be restricted to the legacy P2PKH invoice address format.
=== Simple ===
A ''simple'' signature consists of a witness stack, consensus encoded as a vector of vectors of bytes, and base64-encoded. Validators should construct to_spend and to_sign as defined below, with default values for all fields except that
* message_hash is a BIP340-tagged hash of the message, as specified below
* message_challenge in to_spend is set to the scriptPubKey being signed with
* message_signature in to_sign is set to the provided simple signature.
and then proceed as they would for a full signature.
=== Full ===
Full signatures follow an analogous specification to the BIP-325 challenges and solutions used by Signet.
Let there be two virtual transactions to_spend and to_sign.
The to_spend transaction is:
nVersion = 0
nLockTime = 0
vin[0].prevout.hash = 0000...000
vin[0].prevout.n = 0xFFFFFFFF
vin[0].nSequence = 0
vin[0].scriptSig = OP_0 PUSH32[ message_hash ]
vin[0].scriptWitness = []
vout[0].nValue = 0
vout[0].scriptPubKey = message_challenge
where message_hash is a BIP340-tagged hash of the message, i.e. sha256_tag(m), where tag = BIP0322-signed-message and m is the message as is without length prefix or null terminator, and message_challenge is the to be proven (public) key script.
The to_sign transaction is:
nVersion = 0 or (FULL format only) as appropriate (e.g. 2, for time locks)
nLockTime = 0 or (FULL format only) as appropriate (for time locks)
vin[0].prevout.hash = to_spend.txid
vin[0].prevout.n = 0
vin[0].nSequence = 0 or (FULL format only) as appropriate (for time locks)
vin[0].scriptWitness = message_signature
vout[0].nValue = 0
vout[0].scriptPubKey = OP_RETURN
A full signature consists of the base64-encoding of the to_sign transaction in standard network serialisation once it has been signed.
=== Full (Proof of Funds) ===
A signer may construct a proof of funds, demonstrating control of a set of UTXOs, by constructing a full signature as above, with the following modifications.
* All outputs that the signer wishes to demonstrate control of are included as additional inputs of to_sign, and their witness and scriptSig data should be set as though these outputs were actually being spent.
Unlike an ordinary signature, validators of a proof of funds need access to the current UTXO set, to learn that the claimed inputs exist on the blockchain, and to learn their scriptPubKeys.
== Detailed Specification ==
For all signature types, except legacy, the to_spend and to_sign transactions must be valid transactions which pass all consensus checks, except of course that the output with prevout 000...000:FFFFFFFF does not exist.
=== Verification ===
A validator is given as input an address ''A'' (which may be omitted in a proof-of-funds), signature ''s'' and message ''m'', and outputs one of three states
* ''valid at time T and age S'' indicates that the signature has set timelocks but is otherwise valid
* ''inconclusive'' means the validator was unable to check the scripts
* ''invalid'' means that some check failed
==== Verification Process ====
Validation consists of the following steps:
# Basic validation
## Compute the transaction to_spend from ''m'' and ''A''
## Decode ''s'' as the transaction to_sign
## If ''s'' was a full transaction, confirm all fields are set as specified above; in particular that
##* to_sign has at least one input and its first input spends the output of to_spend
##* to_sign has exactly one output, as specified above
## Confirm that the two transactions together satisfy all consensus rules, except for to_spend's missing input, and except that ''nSequence'' of to_sign's first input and ''nLockTime'' of to_sign are not checked.
# (Optional) If the validator does not have a full script interpreter, it should check that it understands all scripts being satisfied. If not, it should stop here and output ''inconclusive''.
# Check the **required rules**:
## All signatures must use the SIGHASH_ALL flag.
## The use of CODESEPARATOR or FindAndDelete is forbidden.
## LOW_S, STRICTENC and NULLFAIL: valid ECDSA signatures must be strictly DER-encoded and have a low-S value; invalid ECDSA signature must be the empty push
## MINIMALDATA: all pushes must be minimally encoded
## CLEANSTACK: require that only a single stack element remains after evaluation
## MINIMALIF: the argument of IF/NOTIF must be exactly 0x01 or empty push
## If any of the above steps failed, the validator should stop and output the ''invalid'' state.
# Check the **upgradeable rules**
## The version of to_sign must be 0 or 2.
## The use of NOPs reserved for upgrades is forbidden.
## The use of segwit versions greater than 1 are forbidden.
## If any of the above steps failed, the validator should stop and output the ''inconclusive'' state.
# Let ''T'' by the nLockTime of to_sign and ''S'' be the nSequence of the first input of to_sign. Output the state ''valid at time T and age S''.
=== Signing ===
Signers who control an address ''A'' who wish to sign a message ''m'' act as follows:
# They construct to_spend and to_sign as specified above, using the scriptPubKey of ''A'' for message_challenge and tagged hash of ''m'' as message_hash.
# Optionally, they may set nLockTime of to_sign or nSequence of its first input.
# Optionally, they may add any additional inputs to to_sign that they wish to prove control of.
# They satisfy to_sign as they would any other transaction.
They then encode their signature, choosing either ''simple'' or ''full'' as follows:
* If they added no inputs to to_sign, left nSequence and nLockTime at 0, and ''A'' is a Segwit address (either pure or P2SH-wrapped), then they may base64-encode message_signature
* Otherwise they must base64-encode to_sign.
== Compatibility ==
This specification is backwards compatible with the legacy signmessage/verifymessage specification through the special case as described above.
== Reference implementation ==
* Bitcoin Core pull request (basic support) at: https://github.com/bitcoin/bitcoin/pull/24058
== Acknowledgements ==
Thanks to David Harding, Jim Posen, Kalle Rosenbaum, Pieter Wuille, Andrew Poelstra, and many others for their feedback on the specification.
== References ==
# Original mailing list thread: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-March/015818.html
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
== Test vectors ==
=== Message hashing ===
Message hashes are BIP340-tagged hashes of a message, i.e. sha256_tag(m), where tag = BIP0322-signed-message, and m is the message as is without length prefix or null terminator:
* Message = "" (empty string): c90c269c4f8fcbe6880f72a721ddfbf1914268a794cbb21cfafee13770ae19f1
* Message = "Hello World": f0eb03b1a75ac6d9847f55c624a99169b5dccba2a31f5b23bea77ba270de0a7a
=== Message signing ===
Given below parameters:
* private key L3VFeEujGtevx9w18HD1fhRbCH67Az2dpCymeRE1SoPK6XQtaN2k
* corresponding address bc1q9vza2e8x573nczrlzms0wvx3gsqjx7vavgkx0l
Produce signatures:
* Message = "" (empty string): AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI= or AkgwRQIhAPkJ1Q4oYS0htvyuSFHLxRQpFAY56b70UvE7Dxazen0ZAiAtZfFz1S6T6I23MWI2lK/pcNTWncuyL8UL+oMdydVgzAEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy
* Message = "Hello World": AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI= or AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy
=== Transaction Hashes ===
to_spend:
* Message = "" (empty string): c5680aa69bb8d860bf82d4e9cd3504b55dde018de765a91bb566283c545a99a7
* Message = "Hello World": b79d196740ad5217771c1098fc4a4b51e0535c32236c71f1ea4d61a2d603352b
to_sign:
* Message = "" (empty string): 1e9654e951a5ba44c8604c4de6c67fd78a27e81dcadcfe1edf638ba3aaebaed6
* Message = "Hello World": 88737ae86f2077145f93cc4b153ae9a1cb8d56afa511988c149c5c8c9d93bddf
================================================
FILE: bip-0324/ellswift_decode_test_vectors.csv
================================================
ellswift,x,comment
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c,u%p=0;t%p=0;valid_x(x2)
000000000000000000000000000000000000000000000000000000000000000001d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771,b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c,u%p=0;valid_x(x1)
000000000000000000000000000000000000000000000000000000000000000082277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f,f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2,u%p=0;valid_x(x3);valid_x(x2);valid_x(x1)
00000000000000000000000000000000000000000000000000000000000000008421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0,9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0,u%p=0;valid_x(x2)
0000000000000000000000000000000000000000000000000000000000000000bde70df51939b94c9c24979fa7dd04ebd9b3572da7802290438af2a681895441,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b,u%p=0;(u'^3-t'^2+7)%p=0;valid_x(x3)
0000000000000000000000000000000000000000000000000000000000000000d19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42,70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff,u%p=0;valid_x(x3)
0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c,u%p=0;t%p=0;valid_x(x2);t>=p
0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5,50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b,u%p=0;valid_x(x3);valid_x(x2);valid_x(x1);t>=p
0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d,1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e,u%p=0;valid_x(x2);t>=p
0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7,12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e,u%p=0;valid_x(x1);t>=p
0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9,7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783,u%p=0;valid_x(x3);t>=p
0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f8530000000000000000000000000000000000000000000000000000000000000000,532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688,t%p=0;(u'^3+t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1)
0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f853fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688,t%p=0;(u'^3+t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1);t>=p
0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646,74e880b3ffd18fe3cddf7902522551ddf97fa4a35a3cfda8197f947081a57b8f,valid_x(x3)
0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896,377b643fce2271f64e5c8101566107c1be4980745091783804f654781ac9217c,valid_x(x2);t>=p
123658444f32be8f02ea2034afa7ef4bbe8adc918ceb49b12773b625f490b368ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8dc5fe11,ed16d65cf3a9538fcb2c139f1ecbc143ee14827120cbc2659e667256800b8142,(u'^3-t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1);t>=p
146f92464d15d36e35382bd3ca5b0f976c95cb08acdcf2d5b3570617990839d7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3145e93b,0d5cd840427f941f65193079ab8e2e83024ef2ee7ca558d88879ffd879fb6657,(u'^3+t'^2+7)%p=0;valid_x(x3);t>=p
15fdf5cf09c90759add2272d574d2bb5fe1429f9f3c14c65e3194bf61b82aa73ffffffffffffffffffffffffffffffffffffffffffffffffffffffff04cfd906,16d0e43946aec93f62d57eb8cde68951af136cf4b307938dd1447411e07bffe1,(u'^3+t'^2+7)%p=0;valid_x(x2);t>=p
1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d50000000000000000000000000000000000000000000000000000000000000000,025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c,t%p=0;valid_x(x2)
1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d5fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c,t%p=0;valid_x(x2);t>=p
1fe1e5ef3fceb5c135ab7741333ce5a6e80d68167653f6b2b24bcbcfaaaff507fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,98bec3b2a351fa96cfd191c1778351931b9e9ba9ad1149f6d9eadca80981b801,t%p=0;(u'^3-t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1);t>=p
4056a34a210eec7892e8820675c860099f857b26aad85470ee6d3cf1304a9dcf375e70374271f20b13c9986ed7d3c17799698cfc435dbed3a9f34b38c823c2b4,868aac2003b29dbcad1a3e803855e078a89d16543ac64392d122417298cec76e,(u'^3-t'^2+7)%p=0;valid_x(x3)
4197ec3723c654cfdd32ab075506648b2ff5070362d01a4fff14b336b78f963fffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3ab1e95,ba5a6314502a8952b8f456e085928105f665377a8ce27726a5b0eb7ec1ac0286,(u'^3+t'^2+7)%p=0;valid_x(x1);t>=p
47eb3e208fedcdf8234c9421e9cd9a7ae873bfbdbc393723d1ba1e1e6a8e6b24ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cd12cb1,d192d52007e541c9807006ed0468df77fd214af0a795fe119359666fdcf08f7c,(u'^3+t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1);t>=p
5eb9696a2336fe2c3c666b02c755db4c0cfd62825c7b589a7b7bb442e141c1d693413f0052d49e64abec6d5831d66c43612830a17df1fe4383db896468100221,ef6e1da6d6c7627e80f7a7234cb08a022c1ee1cf29e4d0f9642ae924cef9eb38,(u'^3+t'^2+7)%p=0;valid_x(x1)
7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0e0000000000000000000000000000000000000000000000000000000000000000,50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff,t%p=0;valid_x(x1)
7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff,t%p=0;valid_x(x1);t>=p
851b1ca94549371c4f1f7187321d39bf51c6b7fb61f7cbf027c9da62021b7a65fc54c96837fb22b362eda63ec52ec83d81bedd160c11b22d965d9f4a6d64d251,3e731051e12d33237eb324f2aa5b16bb868eb49a1aa1fadc19b6e8761b5a5f7b,(u'^3+t'^2+7)%p=0;valid_x(x2)
943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f91250000000000000000000000000000000000000000000000000000000000000000,311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942,t%p=0;valid_x(x3);valid_x(x2);valid_x(x1)
943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f9125fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942,t%p=0;valid_x(x3);valid_x(x2);valid_x(x1);t>=p
a0f18492183e61e8063e573606591421b06bc3513631578a73a39c1c3306239f2f32904f0d2a33ecca8a5451705bb537d3bf44e071226025cdbfd249fe0f7ad6,97a09cf1a2eae7c494df3c6f8a9445bfb8c09d60832f9b0b9d5eabe25fbd14b9,valid_x(x1)
a1ed0a0bd79d8a23cfe4ec5fef5ba5cccfd844e4ff5cb4b0f2e71627341f1c5b17c499249e0ac08d5d11ea1c2c8ca7001616559a7994eadec9ca10fb4b8516dc,65a89640744192cdac64b2d21ddf989cdac7500725b645bef8e2200ae39691f2,valid_x(x2)
ba94594a432721aa3580b84c161d0d134bc354b690404d7cd4ec57c16d3fbe98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffea507dd7,5e0d76564aae92cb347e01a62afd389a9aa401c76c8dd227543dc9cd0efe685a,valid_x(x1);t>=p
bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a,2d97f96cac882dfe73dc44db6ce0f1d31d6241358dd5d74eb3d3b50003d24c2b,valid_x(x3);valid_x(x2);valid_x(x1)
bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff6507d09a,e7008afe6e8cbd5055df120bd748757c686dadb41cce75e4addcc5e02ec02b44,valid_x(x3);valid_x(x2);valid_x(x1);t>=p
c5981bae27fd84401c72a155e5707fbb811b2b620645d1028ea270cbe0ee225d4b62aa4dca6506c1acdbecc0552569b4b21436a5692e25d90d3bc2eb7ce24078,948b40e7181713bc018ec1702d3d054d15746c59a7020730dd13ecf985a010d7,(u'^3+t'^2+7)%p=0;valid_x(x3)
c894ce48bfec433014b931a6ad4226d7dbd8eaa7b6e3faa8d0ef94052bcf8cff336eeb3919e2b4efb746c7f71bbca7e9383230fbbc48ffafe77e8bcc69542471,f1c91acdc2525330f9b53158434a4d43a1c547cff29f15506f5da4eb4fe8fa5a,(u'^3-t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1)
cbb0deab125754f1fdb2038b0434ed9cb3fb53ab735391129994a535d925f6730000000000000000000000000000000000000000000000000000000000000000,872d81ed8831d9998b67cb7105243edbf86c10edfebb786c110b02d07b2e67cd,t%p=0;(u'^3-t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1)
d917b786dac35670c330c9c5ae5971dfb495c8ae523ed97ee2420117b171f41effffffffffffffffffffffffffffffffffffffffffffffffffffffff2001f6f6,e45b71e110b831f2bdad8651994526e58393fde4328b1ec04d59897142584691,valid_x(x3);t>=p
e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb4260000000000000000000000000000000000000000000000000000000000000000,66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5,t%p=0;valid_x(x3)
e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb426fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5,t%p=0;valid_x(x3);t>=p
e7ee5814c1706bf8a89396a9b032bc014c2cac9c121127dbf6c99278f8bb53d1dfd04dbcda8e352466b6fcd5f2dea3e17d5e133115886eda20db8a12b54de71b,e842c6e3529b234270a5e97744edc34a04d7ba94e44b6d2523c9cf0195730a50,(u'^3+t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1)
f292e46825f9225ad23dc057c1d91c4f57fcb1386f29ef10481cb1d22518593fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7011c989,3cea2c53b8b0170166ac7da67194694adacc84d56389225e330134dab85a4d55,(u'^3-t'^2+7)%p=0;valid_x(x3);t>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000000000000000000000000000000000000000000000000000000000000000,edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c,u%p=0;t%p=0;valid_x(x2);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f01d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771,b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c,u%p=0;valid_x(x1);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b,u%p=0;(u'^3-t'^2+7)%p=0;valid_x(x3);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f82277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f,f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2,u%p=0;valid_x(x3);valid_x(x2);valid_x(x1);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0,9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0,u%p=0;valid_x(x2);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fd19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42,70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff,u%p=0;valid_x(x3);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c,u%p=0;t%p=0;valid_x(x2);u>=p;t>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5,50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b,u%p=0;valid_x(x3);valid_x(x2);valid_x(x1);u>=p;t>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d,1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e,u%p=0;valid_x(x2);u>=p;t>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7,12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e,u%p=0;valid_x(x1);u>=p;t>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9,7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783,u%p=0;valid_x(x3);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a70000000000000000000000000000000000000000000000000000000000000000,649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb,t%p=0;valid_x(x1);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb,t%p=0;valid_x(x1);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff15028c590063f64d5a7f1c14915cd61eac886ab295bebd91992504cf77edb028bdd6267f,3fde5713f8282eead7d39d4201f44a7c85a5ac8a0681f35e54085c6b69543374,(u'^3+t'^2+7)%p=0;valid_x(x2);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de860000000000000000000000000000000000000000000000000000000000000000,3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4,t%p=0;valid_x(x3);valid_x(x2);valid_x(x1);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de86fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4,t%p=0;valid_x(x3);valid_x(x2);valid_x(x1);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2c2c5709e7156c417717f2feab147141ec3da19fb759575cc6e37b2ea5ac9309f26f0f66,d2469ab3e04acbb21c65a1809f39caafe7a77c13d10f9dd38f391c01dc499c52,(u'^3-t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3a08cc1efffffffffffffffffffffffffffffffffffffffffffffffffffffffff760e9f0,38e2a5ce6a93e795e16d2c398bc99f0369202ce21e8f09d56777b40fc512bccc,valid_x(x3);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e91257d932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a,864b3dc902c376709c10a93ad4bbe29fce0012f3dc8672c6286bba28d7d6d6fc,valid_x(x3);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff795d6c1c322cadf599dbb86481522b3cc55f15a67932db2afa0111d9ed6981bcd124bf44,766dfe4a700d9bee288b903ad58870e3d4fe2f0ef780bcac5c823f320d9a9bef,(u'^3+t'^2+7)%p=0;valid_x(x1);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8e426f0392389078c12b1a89e9542f0593bc96b6bfde8224f8654ef5d5cda935a3582194,faec7bc1987b63233fbc5f956edbf37d54404e7461c58ab8631bc68e451a0478,valid_x(x1);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff91192139ffffffffffffffffffffffffffffffffffffffffffffffffffffffff45f0f1eb,ec29a50bae138dbf7d8e24825006bb5fc1a2cc1243ba335bc6116fb9e498ec1f,valid_x(x2);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff98eb9ab76e84499c483b3bf06214abfe065dddf43b8601de596d63b9e45a166a580541fe,1e0ff2dee9b09b136292a9e910f0d6ac3e552a644bba39e64e9dd3e3bbd3d4d4,(u'^3-t'^2+7)%p=0;valid_x(x3);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646,8b7dd5c3edba9ee97b70eff438f22dca9849c8254a2f3345a0a572ffeaae0928,valid_x(x2);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896,0881950c8f51d6b9a6387465d5f12609ef1bb25412a08a74cb2dfb200c74bfbf,valid_x(x3);valid_x(x2);valid_x(x1);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa2f5cd838816c16c4fe8a1661d606fdb13cf9af04b979a2e159a09409ebc8645d58fde02,2f083207b9fd9b550063c31cd62b8746bd543bdc5bbf10e3a35563e927f440c8,(u'^3+t'^2+7)%p=0;valid_x(x3);valid_x(x2);valid_x(x1);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c00000000000000000000000000000000000000000000000000000000000000000,4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0,t%p=0;valid_x(x3);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c0fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0,t%p=0;valid_x(x3);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8d0000000000000000000000000000000000000000000000000000000000000000,16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2,t%p=0;valid_x(x2);u>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8dfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2,t%p=0;valid_x(x2);u>=p;t>=p
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffef64d162750546ce42b0431361e52d4f5242d8f24f33e6b1f99b591647cbc808f462af51,d41244d11ca4f65240687759f95ca9efbab767ededb38fd18c36e18cd3b6f6a9,(u'^3+t'^2+7)%p=0;valid_x(x3);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0e5be52372dd6e894b2a326fc3605a6e8f3c69c710bf27d630dfe2004988b78eb6eab36,64bf84dd5e03670fdb24c0f5d3c2c365736f51db6c92d95010716ad2d36134c8,valid_x(x3);valid_x(x2);valid_x(x1);u>=p
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefbb982fffffffffffffffffffffffffffffffffffffffffffffffffffffffff6d6db1f,1c92ccdfcf4ac550c28db57cff0c8515cb26936c786584a70114008d6c33a34b,valid_x(x1);u>=p;t>=p
================================================
FILE: bip-0324/gen_test_vectors.py
================================================
"""Generate the BIP-0324 test vectors."""
import csv
import hashlib
import os
import sys
from reference import (
FE,
GE,
MINUS_3_SQRT,
hkdf_sha256,
SECP256K1_G,
ellswift_decode,
ellswift_ecdh_xonly,
xswiftec_inv,
xswiftec,
v2_ecdh,
initialize_v2_transport,
v2_enc_packet
)
FILENAME_PACKET_TEST = os.path.join(sys.path[0], 'packet_encoding_test_vectors.csv')
FILENAME_XSWIFTEC_INV_TEST = os.path.join(sys.path[0], 'xswiftec_inv_test_vectors.csv')
FILENAME_ELLSWIFT_DECODE_TEST = os.path.join(sys.path[0], 'ellswift_decode_test_vectors.csv')
def xswiftec_flagged(u, t, simplified=False):
"""A variant of xswiftec which also returns 'flags', describing conditions encountered."""
flags = []
if u == 0:
flags.append("u%p=0")
u = FE(1)
if t == 0:
flags.append("t%p=0")
t = FE(1)
if u**3 + t**2 + 7 == 0:
flags.append("(u'^3+t'^2+7)%p=0")
t = 2 * t
X = (u**3 + 7 - t**2) / (2 * t)
Y = (X + t) / (MINUS_3_SQRT * u)
if X == 0:
if not simplified:
flags.append("(u'^3-t'^2+7)%p=0")
x3 = u + 4 * Y**2
if GE.is_valid_x(x3):
flags.append("valid_x(x3)")
x2 = (-X / Y - u) / 2
if GE.is_valid_x(x2):
flags.append("valid_x(x2)")
x1 = (X / Y - u) / 2
if GE.is_valid_x(x1):
flags.append("valid_x(x1)")
for x in (x3, x2, x1):
if GE.is_valid_x(x):
break
return x, flags
def ellswift_create_deterministic(seed, features):
"""This is a variant of ellswift_create which doesn't use randomness.
features is an integer selecting some properties of the result:
- (f & 3) == 0: only x1 is valid on decoding (see xswiftec{_flagged})
- (f & 3) == 1: only x2 is valid on decoding
- (f & 3) == 2: only x3 is valid on decoding
- (f & 3) == 3: x1,x2,x3 are all valid on decoding
- (f & 4) == 4: u >= p
- (f & 8) == 8: u mod n == 0
Returns privkey, ellswift
"""
cnt = 0
while True:
sec = hkdf_sha256(32, seed, (cnt).to_bytes(4, 'little'), b"sec")
xval = (int.from_bytes(sec, 'big') * SECP256K1_G).x
cnt += 1
if features & 8:
u = 0
if features & 4:
u += FE.SIZE
else:
udat = hkdf_sha256(64, seed, (cnt).to_bytes(4, 'little'), b"u")
if features & 4:
u = FE.SIZE + 1 + int.from_bytes(udat, 'big') % (2**256 - FE.SIZE - 1)
else:
u = 1 + int.from_bytes(udat, 'big') % (FE.SIZE - 1)
case = hkdf_sha256(1, seed, (cnt).to_bytes(4, 'little'), b"case")[0] & 7
coru = FE(u) + ((features & 8) == 8)
t = xswiftec_inv(xval, coru, case)
if t is None:
continue
assert xswiftec(FE(u), t) == xval
x2, flags = xswiftec_flagged(FE(u), t)
assert x2 == xval
have_x1 = "valid_x(x1)" in flags
have_x2 = "valid_x(x2)" in flags
have_x3 = "valid_x(x3)" in flags
if (features & 3) == 0 and not (have_x1 and not have_x2 and not have_x3):
continue
if (features & 3) == 1 and not (not have_x1 and have_x2 and not have_x3):
continue
if (features & 3) == 2 and not (not have_x1 and not have_x2 and have_x3):
continue
if (features & 3) == 3 and not (have_x1 and have_x2 and have_x3):
continue
return sec, u.to_bytes(32, 'big') + t.to_bytes()
def ellswift_decode_flagged(ellswift, simplified=False):
"""Decode a 64-byte ElligatorSwift encoded coordinate, returning byte array + flag string."""
uv = int.from_bytes(ellswift[:32], 'big')
tv = int.from_bytes(ellswift[32:], 'big')
x, flags = xswiftec_flagged(FE(uv), FE(tv))
if not simplified:
if uv >= FE.SIZE:
flags.append("u>=p")
if tv >= FE.SIZE:
flags.append("t>=p")
return int(x).to_bytes(32, 'big'), ";".join(flags)
def random_fe_int(_, seed, i, p):
"""Function to use in tuple_expand, generating a random integer in 0..p-1."""
rng_out = hkdf_sha256(64, seed, i.to_bytes(4, 'little'), b"v%i_fe" % p)
return int.from_bytes(rng_out, 'big') % FE.SIZE
def random_fe_int_high(_, seed, i, p):
"""Function to use in tuple_expand, generating a random integer in p..2^256-1."""
rng_out = hkdf_sha256(64, seed, i.to_bytes(4, 'little'), b"v%i_fe_high" % p)
return FE.SIZE + int.from_bytes(rng_out, 'big') % (2**256 - FE.SIZE)
def fn_of(p_in, fn):
"""Function to use in tuple_expand, to pick one variable in function of another."""
def inner(vs, _seed, _i, p):
assert p != p_in
if isinstance(vs[p_in], int):
return fn(vs[p_in])
return None
return inner
def tuple_expand(out, tuplespec, prio, seed=None, cnt=1):
"""Given a tuple specification, expand it cnt times, and add results to out.
Expansion is defined recursively:
- If any of the spec elements is a list, each element of the list results
in an expansion (by replacing the list with its element).
- If any of the spec elements is a function, that function is invoked with
(spec, seed, expansion count, index in spec) as arguments. If the function
needs to wait for other indices to be expanded, it can return None.
The output consists of (prio, expansion count, SHA256(result), result, seed)
tuples."""
def recurse(vs, seed, i, change_pos=None, change=None):
if change_pos is not None:
vs = list(vs)
vs[change_pos] = change
for p, v in enumerate(vs):
if v is None:
return
if isinstance(v, list):
for ve in v:
recurse(vs, seed, i, p, ve)
return
if callable(v):
res = v(vs, seed, i, p)
if res is not None:
recurse(vs, seed, i, p, res)
return
h = hashlib.sha256()
for v in vs:
h.update(int(v).to_bytes(32, 'big'))
out.append((prio, i, h.digest(), vs, seed))
for i in range(cnt):
recurse(tuplespec, seed, i)
def gen_ellswift_decode_cases(seed, simplified=False):
"""Generate a set of interesting (ellswift, x, flags) ellswift decoding cases."""
inputs = []
# Aggregate for use in tuple_expand, expanding to int in 0..p-1, and one in p..2^256-1.
RANDOM_VAL = [random_fe_int, random_fe_int_high]
# Aggregate for use in tuple_expand, expanding to integers which %p equal 0.
ZERO_VAL = [0, FE.SIZE]
# Helpers for constructing u and t values such that u^3+t^2+7=0 or u^3-t^2+7=0.
T_FOR_SUM_ZERO = fn_of(0, lambda u: (-FE(u)**3 - 7).sqrts())
T_FOR_DIFF_ZERO = fn_of(0, lambda u: (FE(u)**3 + 7).sqrts())
U_FOR_SUM_ZERO = fn_of(1, lambda t: (-FE(t)**2 - 7).cbrts())
U_FOR_DIFF_ZERO = fn_of(1, lambda t: (FE(t)**2 - 7).cbrts())
tuple_expand(inputs, [RANDOM_VAL, RANDOM_VAL], 0, seed + b"random", 64)
tuple_expand(inputs, [RANDOM_VAL, T_FOR_SUM_ZERO], 1, seed + b"t=sqrt(-u^3-7)", 64)
tuple_expand(inputs, [U_FOR_SUM_ZERO, RANDOM_VAL], 1, seed + b"u=cbrt(-t^2-7)", 64)
tuple_expand(inputs, [RANDOM_VAL, T_FOR_DIFF_ZERO], 1, seed + b"t=sqrt(u^3+7)", 64)
tuple_expand(inputs, [U_FOR_DIFF_ZERO, RANDOM_VAL], 1, seed + b"u=cbrt(t^2-7)", 64)
tuple_expand(inputs, [ZERO_VAL, RANDOM_VAL], 2, seed + b"u=0", 64)
tuple_expand(inputs, [RANDOM_VAL, ZERO_VAL], 2, seed + b"t=0", 64)
tuple_expand(inputs, [ZERO_VAL, FE(8).sqrts()], 3, seed + b"u=0;t=sqrt(8)")
tuple_expand(inputs, [FE(-8).cbrts(), ZERO_VAL], 3, seed + b"t=0;u=cbrt(-8)")
tuple_expand(inputs, [FE(-6).cbrts(), ZERO_VAL], 3, seed + b"t=0;u=cbrt(-6)")
tuple_expand(inputs, [ZERO_VAL, ZERO_VAL], 3, seed + b"u=0;t=0")
# Unused.
tuple_expand(inputs, [ZERO_VAL, FE(-8).sqrts()], 4, seed + b"u=0;t=sqrt(-8)")
seen = set()
cases = []
for _prio, _cnt, _hash, vs, _seed in sorted(inputs):
inp = int(vs[0]).to_bytes(32, 'big') + int(vs[1]).to_bytes(32, 'big')
outp, flags = ellswift_decode_flagged(inp, simplified)
if flags not in seen:
cases.append((inp, outp, flags))
seen.add(flags)
return cases
def gen_all_ellswift_decode_vectors(fil):
"""Generate all xelligatorswift decoding test vectors."""
cases = gen_ellswift_decode_cases(b"")
writer = csv.DictWriter(fil, ["ellswift", "x", "comment"])
writer.writeheader()
for val, x, flags in sorted(cases):
writer.writerow({"ellswift": val.hex(), "x": x.hex(), "comment": flags})
def xswiftec_inv_flagged(x, u, case):
"""A variant of xswiftec_inv which also returns flags, describing conditions encountered."""
flags = []
if case & 2 == 0:
if GE.is_valid_x(-x - u):
flags.append("bad[valid_x(-x-u)]")
return None, flags
v = x if case & 1 == 0 else -x - u
if v == 0:
flags.append("info[v=0]")
s = -(u**3 + 7) / (u**2 + u*v + v**2)
assert s != 0 # would imply X=0 on curve
else:
s = x - u
if s == 0:
flags.append("bad[s=0]")
return None, flags
q = (-s * (4 * (u**3 + 7) + 3 * s * u**2))
if q == 0:
flags.append("info[q=0]")
r = q.sqrt()
if r is None:
flags.append("bad[non_square(q)]")
return None, flags
if case & 1:
if r == 0:
flags.append("bad[r=0]")
return None, flags
r = -r
v = (-u + r / s) / 2
if v == 0:
flags.append("info[v=0]")
w = s.sqrt()
assert w != 0
if w is None:
flags.append("bad[non_square(s)]")
return None, flags
if case & 4:
w = -w
Y = w / 2
assert Y != 0
X = 2 * Y * (v + u / 2)
if X == 0:
flags.append("info[X=0]")
flags.append("ok")
return w * (u * (MINUS_3_SQRT - 1) / 2 - v), flags
def xswiftec_inv_combo_flagged(x, u):
"""Compute the aggregate results and flags from xswiftec_inv_flagged for case=0..7."""
ts = []
allflags = []
for case in range(8):
t, flags = xswiftec_inv_flagged(x, u, case)
if t is not None:
assert x == xswiftec(u, t)
ts.append(t)
allflags.append(f"case{case}:{'&'.join(flags)}")
return ts, ";".join(allflags)
def gen_all_xswiftec_inv_vectors(fil):
"""Generate all xswiftec_inv test vectors."""
# Two constants used below. Compute them only once.
C1 = (FE(MINUS_3_SQRT) - 1) / 2
C2 = (-FE(MINUS_3_SQRT) - 1) / 2
# Helper functions that pick x and u with special properties.
TRIGGER_Q_ZERO = fn_of(1, lambda u: (FE(u)**3 + 28) / (FE(-3) * FE(u)**2))
TRIGGER_DIVZERO_A = fn_of(1, lambda u: FE(u) * C1)
TRIGGER_DIVZERO_B = fn_of(1, lambda u: FE(u) * C2)
TRIGGER_V_ZERO = fn_of(1, lambda u: FE(-7) / FE(u)**2)
TRIGGER_X_ZERO = fn_of(0, lambda x: FE(-2) * FE(x))
inputs = []
tuple_expand(inputs, [random_fe_int, random_fe_int], 0, b"uniform", 256)
tuple_expand(inputs, [TRIGGER_Q_ZERO, random_fe_int], 1, b"x=-(u^3+28)/(3*u^2)", 64)
tuple_expand(inputs, [TRIGGER_V_ZERO, random_fe_int], 1, b"x=-7/u^2", 512)
tuple_expand(inputs, [random_fe_int, fn_of(0, lambda x: x)], 2, b"u=x", 64)
tuple_expand(inputs, [random_fe_int, fn_of(0, lambda x: -FE(x))], 2, b"u=-x", 64)
# Unused.
tuple_expand(inputs, [TRIGGER_DIVZERO_A, random_fe_int], 3, b"x=u*(sqrt(-3)-1)/2", 64)
tuple_expand(inputs, [TRIGGER_DIVZERO_B, random_fe_int], 3, b"x=u*(-sqrt(-3)-1)/2", 64)
tuple_expand(inputs, [random_fe_int, TRIGGER_X_ZERO], 3, b"u=-2x", 64)
seen = set()
cases = []
for _prio, _cnt, _hash, vs, _seed in sorted(inputs):
x, u = FE(vs[0]), FE(vs[1])
if u == 0:
continue
if not GE.is_valid_x(x):
continue
ts, flags = xswiftec_inv_combo_flagged(x, u)
if flags not in seen:
cases.append((int(u), int(x), ts, flags))
seen.add(flags)
writer = csv.DictWriter(fil, ["u", "x"] + [f"case{c}_t" for c in range(8)] + ["comment"])
writer.writeheader()
for u, x, ts, flags in sorted(cases):
row = {"u": FE(u), "x": FE(x), "comment": flags}
for c in range(8):
if ts[c] is not None:
row[f"case{c}_t"] = FE(ts[c])
writer.writerow(row)
def gen_packet_encoding_vector(case):
"""Given a dict case with specs, construct a packet_encoding test vector as a CSV line."""
ikm = str(case).encode('utf-8')
in_initiating = case["init"]
in_ignore = int(case["ignore"])
in_priv_ours, in_ellswift_ours = ellswift_create_deterministic(ikm, case["features"])
mid_x_ours = (int.from_bytes(in_priv_ours, 'big') * SECP256K1_G).x.to_bytes()
assert mid_x_ours == ellswift_decode(in_ellswift_ours)
in_ellswift_theirs = case["theirs"]
in_contents = hkdf_sha256(case["contentlen"], ikm, b"contents", b"")
contents = in_contents * case["multiply"]
in_aad = hkdf_sha256(case["aadlen"], ikm, b"aad", b"")
mid_shared_secret = v2_ecdh(in_priv_ours, in_ellswift_theirs, in_ellswift_ours, in_initiating)
peer = initialize_v2_transport(mid_shared_secret, in_initiating)
for _ in range(case["idx"]):
v2_enc_packet(peer, b"")
ciphertext = v2_enc_packet(peer, contents, in_aad, case["ignore"])
long_msg = len(ciphertext) > 128
return {
"in_idx": case['idx'],
"in_priv_ours": in_priv_ours.hex(),
"in_ellswift_ours": in_ellswift_ours.hex(),
"in_ellswift_theirs": in_ellswift_theirs.hex(),
"in_initiating": int(in_initiating),
"in_contents": in_contents.hex(),
"in_multiply": case['multiply'],
"in_aad": in_aad.hex(),
"in_ignore": in_ignore,
"mid_x_ours": mid_x_ours.hex(),
"mid_x_theirs": ellswift_decode(in_ellswift_theirs).hex(),
"mid_x_shared": ellswift_ecdh_xonly(in_ellswift_theirs, in_priv_ours).hex(),
"mid_shared_secret": mid_shared_secret.hex(),
"mid_initiator_l": peer['initiator_L'].hex(),
"mid_initiator_p": peer['initiator_P'].hex(),
"mid_responder_l": peer['responder_L'].hex(),
"mid_responder_p": peer['responder_P'].hex(),
"mid_send_garbage_terminator": peer["send_garbage_terminator"].hex(),
"mid_recv_garbage_terminator": peer["recv_garbage_terminator"].hex(),
"out_session_id": peer["session_id"].hex(),
"out_ciphertext": "" if long_msg else ciphertext.hex(),
"out_ciphertext_endswith": ciphertext[-128:].hex() if long_msg else ""
}
def gen_all_packet_encoding_vectors(fil):
"""Return a list of CSV lines, one for each packet encoding vector."""
ellswift = gen_ellswift_decode_cases(b"simplified_", simplified=True)
ellswift.sort(key=lambda x: hashlib.sha256(b"simplified:" + x[0]).digest())
fields = [
"in_idx", "in_priv_ours", "in_ellswift_ours", "in_ellswift_theirs", "in_initiating",
"in_contents", "in_multiply", "in_aad", "in_ignore", "mid_x_ours", "mid_x_theirs",
"mid_x_shared", "mid_shared_secret", "mid_initiator_l", "mid_initiator_p",
"mid_responder_l", "mid_responder_p", "mid_send_garbage_terminator",
"mid_recv_garbage_terminator", "out_session_id", "out_ciphertext", "out_ciphertext_endswith"
]
writer = csv.DictWriter(fil, fields)
writer.writeheader()
for case in [
{"init": True, "contentlen": 1, "multiply": 1, "aadlen": 0, "ignore": False, "idx": 1,
"theirs": ellswift[0][0], "features": 0},
{"init": False, "contentlen": 17, "multiply": 1, "aadlen": 0, "ignore": False, "idx": 999,
"theirs": ellswift[1][0], "features": 1},
{"init": True, "contentlen": 63, "multiply": 1, "aadlen": 4095, "ignore": False, "idx": 0,
"theirs": ellswift[2][0], "features": 2},
{"init": False, "contentlen": 128, "multiply": 1, "aadlen": 0, "ignore": True, "idx": 223,
"theirs": ellswift[3][0], "features": 3},
{"init": True, "contentlen": 193, "multiply": 1, "aadlen": 0, "ignore": False, "idx": 448,
"theirs": ellswift[4][0], "features": 4},
{"init": False, "contentlen": 41, "multiply": 97561, "aadlen": 0, "ignore": False,
"idx": 673, "theirs": ellswift[5][0], "features": 5},
{"init": True, "contentlen": 241, "multiply": 69615, "aadlen": 0, "ignore": True,
"idx": 1024, "theirs": ellswift[6][0], "features": 6},
]:
writer.writerow(gen_packet_encoding_vector(case))
if __name__ == "__main__":
print(f"Generating {FILENAME_PACKET_TEST}...")
with open(FILENAME_PACKET_TEST, "w", encoding="utf-8") as fil_packet:
gen_all_packet_encoding_vectors(fil_packet)
print(f"Generating {FILENAME_XSWIFTEC_INV_TEST}...")
with open(FILENAME_XSWIFTEC_INV_TEST, "w", encoding="utf-8") as fil_xswiftec_inv:
gen_all_xswiftec_inv_vectors(fil_xswiftec_inv)
print(f"Generating {FILENAME_ELLSWIFT_DECODE_TEST}...")
with open(FILENAME_ELLSWIFT_DECODE_TEST, "w", encoding="utf-8") as fil_ellswift_decode:
gen_all_ellswift_decode_vectors(fil_ellswift_decode)
================================================
FILE: bip-0324/message_type_ids.md
================================================
# One-byte message type allocations
This table lists additional message type IDs that various BIPs have
assigned or proposed for assignment.
Type | Message | Proposal
---- | ------------ | --------
29 | uproof | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
30 | getuproof | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
31 | uttls | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
32 | getuttls | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
33 | usummary | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
34 | utreexotx | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
35 | uroot | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
36 | geturoot | [BIP 183 / PR#1923](https://github.com/bitcoin/bips/pull/1923)
37 | feature | [BIP 434](https://github.com/bitcoin/bips/blob/master/bip-0434.md)
Note that this table is not authoritative but instead is reflective
of the BIPs proposing the changes. If multiple BIPs make conflicting
assignments for message type IDs, that may lead to multiple entries for
the same message type ID in this table. BIPs that are in Draft status
may be included in the table, and as a result, the IDs and messages they
define may be changed in future.
================================================
FILE: bip-0324/packet_encoding_test_vectors.csv
================================================
in_idx,in_priv_ours,in_ellswift_ours,in_ellswift_theirs,in_initiating,in_contents,in_multiply,in_aad,in_ignore,mid_x_ours,mid_x_theirs,mid_x_shared,mid_shared_secret,mid_initiator_l,mid_initiator_p,mid_responder_l,mid_responder_p,mid_send_garbage_terminator,mid_recv_garbage_terminator,out_session_id,out_ciphertext,out_ciphertext_endswith
1,61062ea5071d800bbfd59e2e8b53d47d194b095ae5a4df04936b49772ef0d4d7,ec0adff257bbfe500c188c80b4fdd640f6b45a482bbc15fc7cef5931deff0aa186f6eb9bba7b85dc4dcc28b28722de1e3d9108b985e2967045668f66098e475b,a4a94dfce69b4a2a0a099313d10f9f7e7d649d60501c9e1d274c300e0d89aafaffffffffffffffffffffffffffffffffffffffffffffffffffffffff8faf88d5,1,8e,1,,0,19e965bc20fc40614e33f2f82d4eeff81b5e7516b12a5c6c0d6053527eba0923,0c71defa3fafd74cb835102acd81490963f6b72d889495e06561375bd65f6ffc,4eb2bf85bd00939468ea2abb25b63bc642e3d1eb8b967fb90caa2d89e716050e,c6992a117f5edbea70c3f511d32d26b9798be4b81a62eaee1a5acaa8459a3592,9a6478b5fbab1f4dd2f78994b774c03211c78312786e602da75a0d1767fb55cf,7d0c7820ba6a4d29ce40baf2caa6035e04f1e1cefd59f3e7e59e9e5af84f1f51,17bc726421e4054ac6a1d54915085aaa766f4d3cf67bbd168e6080eac289d15e,9f0fc1c0e85fd9a8eee07e6fc41dba2ff54c7729068a239ac97c37c524cca1c0,faef555dfcdb936425d84aba524758f3,02cb8ff24307a6e27de3b4e7ea3fa65b,ce72dffb015da62b0d0f5474cab8bc72605225b0cee3f62312ec680ec5f41ba5,7530d2a18720162ac09c25329a60d75adf36eda3c3,
999,6f312890ec83bbb26798abaadd574684a53e74ccef7953b790fcc29409080246,a8785af31c029efc82fa9fc677d7118031358d7c6a25b5779a9b900e5ccd94aac97eb36a3c5dbcdb2ca5843cc4c2fe0aaa46d10eb3d233a81c3dde476da00eef,fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000000000000000000000000000000000000000000000000000000000000000,0,3eb1d4e98035cfd8eeb29bac969ed3824a,1,,0,d4b65faa965b31fe2d9faaeb806c6449a50fe3679555c3518f7a0885f572457f,edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c,13c1bf6a3ca37da9ffc7f45ec1810fa935c45454c03dc0144c1a9755bb52f81f,a6f79eb08243b6f65dbe42bfe4a6cf3f131d6963fa5d06c770a18f7b9c489b78,efc938c88c925459a9c837238716cfadfb1c3016f60d12923933710b5fcc9b55,91702f3cbd33b3c4a0b29b40548aea1ab01e43582db194afee70637d247aa036,7f457572e4260c611a6858acc8f325d87a3c8af8a59ce1da26ef6041f35715e8,1fe4d56334f5b0a5bd3c71ce4e338f40fc7e194925daa7ee6ce98aecf1766d7c,44737108aec5f8b6c1c277b31bbce9c1,ca29b3a35237f8212bd13ed187a1da2e,b0490e26111cb2d55bbff2ace00f7f644f64006539abb4e7513f05107bb10608,d78adbcba0eebfb15cfbd8142c84dc729d233d0dc11b1d851e46a114122b8d5b96b7d59317,
0,846a784f1a03dea59cc679754a60a7145542fa130e3efbd815c81e909ce32933,480eacf1536b52257bf8ce78d8f4ce09395d744767c6c129e7838947ee625af3245592c111275e877d5baae22584cb5f1153e67c16bcd7da767726cd0d0c846a,ffffffffffffffffffffffffffffffffffffffffffffffffffffffff22d5e441524d571a52b3def126189d3f416890a99d4da6ede2b0cde1760ce2c3f98457ae,1,054290a6c6ba8d80478172e89d32bf690913ae9835de6dcf206ff1f4d652286fe0ddf74deba41d55de3edc77c42a32af79bbea2c00bae7492264c60866ae5a,1,84932a55aac22b51e7b128d31d9f0550da28e6a3f394224707d878603386b2f9d0c6bcd8046679bfed7b68c517e7431e75d9dd34605727d2ef1c2babbf680ecc8d68d2c4886e9953a4034abde6da4189cd47c6bb3192242cf714d502ca6103ee84e08bc2ca4fd370d5ad4e7d06c7fbf496c6c7cc7eb19c40c61fb33df2a9ba48497a96c98d7b10c1f91098a6b7b16b4bab9687f27585ade1491ae0dba6a79e1e2d85dd9d9d45c5135ca5fca3f0f99a60ea39edbc9efc7923111c937913f225d67788d5f7e8852b697e26b92ec7bfcaa334a1665511c2b4c0a42d06f7ab98a9719516c8fd17f73804555ee84ab3b7d1762f6096b778d3cb9c799cbd49a9e4a325197b4e6cc4a5c4651f8b41ff88a92ec428354531f970263b467c77ed11312e2617d0d53fe9a8707f51f9f57a77bfb49afe3d89d85ec05ee17b9186f360c94ab8bb2926b65ca99dae1d6ee1af96cad09de70b6767e949023e4b380e66669914a741ed0fa420a48dbc7bfae5ef2019af36d1022283dd90655f25eec7151d471265d22a6d3f91dc700ba749bb67c0fe4bc0888593fbaf59d3c6fff1bf756a125910a63b9682b597c20f560ecb99c11a92c8c8c3f7fbfaa103146083a0ccaecf7a5f5e735a784a8820155914a289d57d8141870ffcaf588882332e0bcd8779efa931aa108dab6c3cce76691e345df4a91a03b71074d66333fd3591bff071ea099360f787bbe43b7b3dff2a59c41c7642eb79870222ad1c6f2e5a191ed5acea51134679587c9cf71c7d8ee290be6bf465c4ee47897a125708704ad610d8d00252d01959209d7cd04d5ecbbb1419a7e84037a55fefa13dee464b48a35c96bcb9a53e7ed461c3a1607ee00c3c302fd47cd73fda7493e947c9834a92d63dcfbd65aa7c38c3e3a2748bb5d9a58e7495d243d6b741078c8f7ee9c8813e473a323375702702b0afae1550c8341eedf5247627343a95240cb02e3e17d5dca16f8d8d3b2228e19c06399f8ec5c5e9dbe4caef6a0ea3ffb1d3c7eac03ae030e791fa12e537c80d56b55b764cadf27a8701052df1282ba8b5e3eb62b5dc7973ac40160e00722fa958d95102fc25c549d8c0e84bed95b7acb61ba65700c4de4feebf78d13b9682c52e937d23026fb4c6193e6644e2d3c99f91f4f39a8b9fc6d013f89c3793ef703987954dc0412b550652c01d922f525704d32d70d6d4079bc3551b563fb29577b3aecdc9505011701dddfd94830431e7a4918927ee44fb3831ce8c4513839e2deea1287f3fa1ab9b61a256c09637dbc7b4f0f8fbb783840f9c24526da883b0df0c473cf231656bd7bc1aaba7f321fec0971c8c2c3444bff2f55e1df7fea66ec3e440a612db9aa87bb505163a59e06b96d46f50d8120b92814ac5ab146bc78dbbf91065af26107815678ce6e33812e6bf3285d4ef3b7b04b076f21e7820dcbfdb4ad5218cf4ff6a65812d8fcb98ecc1e95e2fa58e3efe4ce26cd0bd400d6036ab2ad4f6c713082b5e3f1e04eb9e3b6c8f63f57953894b9e220e0130308e1fd91f72d398c1e7962ca2c31be83f31d6157633581a0a6910496de8d55d3d07090b6aa087159e388b7e7dec60f5d8a60d93ca2ae91296bd484d916bfaaa17c8f45ea4b1a91b37c82821199a2b7596672c37156d8701e7352aa48671d3b1bbbd2bd5f0a2268894a25b0cb2514af39c8743f8cce8ab4b523053739fd8a522222a09acf51ac704489cf17e4b7125455cb8f125b4d31af1eba1f8cf7f81a5a100a141a7ee72e8083e065616649c241f233645c5fc865d17f0285f5c52d9f45312c979bfb3ce5f2a1b951deddf280ffb3f370410cffd1583bfa90077835aa201a0712d1dcd1293ee177738b14e6b5e2a496d05220c3253bb6578d6aff774be91946a614dd7e879fb3dcf7451e0b9adb6a8c44f53c2c464bcc0019e9fad89cac7791a0a3f2974f759a9856351d4d2d7c5612c17cfc50f8479945df57716767b120a590f4bf656f4645029a525694d8a238446c5f5c2c1c995c09c1405b8b1eb9e0352ffdf766cc964f8dcf9f8f043dfab6d102cf4b298021abd78f1d9025fa1f8e1d710b38d9d1652f2d88d1305874ec41609b6617b65c5adb19b6295dc5c5da5fdf69f28144ea12f17c3c6fcce6b9b5157b3dfc969d6725fa5b098a4d9b1d31547ed4c9187452d281d0a5d456008caf1aa251fac8f950ca561982dc2dc908d3691ee3b6ad3ae3d22d002577264ca8e49c523bd51c4846be0d198ad9407bf6f7b82c79893eb2c05fe9981f687a97a4f01fe45ff8c8b7ecc551135cd960a0d6001ad35020be07ffb53cb9e731522ca8ae9364628914b9b8e8cc2f37f03393263603cc2b45295767eb0aac29b0930390eb89587ab2779d2e3decb8042acece725ba42eda650863f418f8d0d50d104e44fbbe5aa7389a4a144a8cecf00f45fb14c39112f9bfb56c0acbd44fa3ff261f5ce4acaa5134c2c1d0cca447040820c81ab1bcdc16aa075b7c68b10d06bbb7ce08b5b805e0238f24402cf24a4b4e00701935a0c68add3de090903f9b85b153cb179a582f57113bfc21c2093803f0cfa4d9d4672c2b05a24f7e4c34a8e9101b70303a7378b9c50b6cddd46814ef7fd73ef6923feceab8fc5aa8b0d185f2e83c7a99dcb1077c0ab5c1f5d5f01ba2f0420443f75c4417db9ebf1665efbb33dca224989920a64b44dc26f682cc77b4632c8454d49135e52503da855bc0f6ff8edc1145451a9772c06891f41064036b66c3119a0fc6e80dffeb65dc456108b7ca0296f4175fff3ed2b0f842cd46bd7e86f4c62dfaf1ddbf836263c00b34803de164983d0811cebfac86e7720c726d3048934c36c23189b02386a722ca9f0fe00233ab50db928d3bccea355cc681144b8b7edcaae4884d5a8f04425c0890ae2c74326e138066d8c05f4c82b29df99b034ea727afde590a1f2177ace3af99cfb1729d6539ce7f7f7314b046aab74497e63dd399e1f7d5f16517c23bd830d1fdee810f3c3b77573dd69c4b97d80d71fb5a632e00acdfa4f8e829faf3580d6a72c40b28a82172f8dcd4627663ebf6069736f21735fd84a226f427cd06bb055f94e7c92f31c48075a2955d82a5b9d2d0198ce0d4e131a112570a8ee40fb80462a81436a58e7db4e34b6e2c422e82f934ecda9949893da5730fc5c23c7c920f363f85ab28cc6a4206713c3152669b47efa8238fa826735f17b4e78750276162024ec85458cd5808e06f40dd9fd43775a456a3ff6cae90550d76d8b2899e0762ad9a371482b3e38083b1274708301d6346c22fea9bb4b73db490ff3ab05b2f7f9e187adef139a7794454b7300b8cc64d3ad76c0e4bc54e08833a4419251550655380d675bc91855aeb82585220bb97f03e976579c08f321b5f8f70988d3061f41465517d53ac571dbf1b24b94443d2e9a8e8a79b392b3d6a4ecdd7f626925c365ef6221305105ce9b5f5b6ecc5bed3d702bd4b7f5008aa8eb8c7aa3ade8ecf6251516fbefeea4e1082aa0e1848eddb31ffe44b04792d296054402826e4bd054e671f223e5557e4c94f89ca01c25c44f1a2ff2c05a70b43408250705e1b858bf0670679fdcd379203e36be3500dd981b1a6422c3cf15224f7fefdef0a5f225c5a09d15767598ecd9e262460bb33a4b5d09a64591efabc57c923d3be406979032ae0bc0997b65336a06dd75b253332ad6a8b63ef043f780a1b3fb6d0b6cad98b1ef4a02535eb39e14a866cfc5fc3a9c5deb2261300d71280ebe66a0776a151469551c3c5fa308757f956655278ec6330ae9e3625468c5f87e02cd9a6489910d4143c1f4ee13aa21a6859d907b788e28572fecee273d44e4a900fa0aa668dd861a60fb6b6b12c2c5ef3c8df1bd7ef5d4b0d1cdb8c15fffbb365b9784bd94abd001c6966216b9b67554ad7cb7f958b70092514f7800fc40244003e0fd1133a9b850fb17f4fcafde07fc87b07fb510670654a5d2d6fc9876ac74728ea41593beef003d6858786a52d3a40af7529596767c17000bfaf8dc52e871359f4ad8bf6e7b2853e5229bdf39657e213580294a5317c5df172865e1e17fe37093b585e04613f5f078f761b2b1752eb32983afda24b523af8851df9a02b37e77f543f18888a782a994a50563334282bf9cdfccc183fdf4fcd75ad86ee0d94f91ee2300a5befbccd14e03a77fc031a8cfe4f01e4c5290f5ac1da0d58ea054bd4837cfd93e5e34fc0eb16e48044ba76131f228d16cde9b0bb978ca7cdcd10653c358bdb26fdb723a530232c32ae0a4cecc06082f46e1c1d596bfe60621ad1e354e01e07b040cc7347c016653f44d926d13ca74e6cbc9d4ab4c99f4491c95c76fff5076b3936eb9d0a286b97c035ca88a3c6309f5febfd4cdaac869e4f58ed409b1e9eb4192fb2f9c2f12176d460fd98286c9d6df84598f260119fd29c63f800c07d8df83d5cc95f8c2fea2812e7890e8a0718bb1e031ecbebc0436dcf3e3b9a58bcc06b4c17f711f80fe1dffc3326a6eb6e00283055c6dabe20d311bfd5019591b7954f8163c9afad9ef8390a38f3582e0a79cdf0353de8eeb6b5f9f27b16ffdef7dd62869b4840ee226ccdce95e02c4545eb981b60571cd83f03dc5eaf8c97a0829a4318a9b3dc06c0e003db700b2260ff1fa8fee66890e637b109abb03ec901b05ca599775f48af50154c0e67d82bf0f558d7d3e0778dc38bea1eb5f74dc8d7f90abdf5511a424be66bf8b6a3cacb477d2e7ef4db68d2eba4d5289122d851f9501ba7e9c4957d8eba3be3fc8e785c4265a1d65c46f2809b70846c693864b169c9dcb78be26ea14b8613f145b01887222979a9e67aee5f800caa6f5c4229bdeefc901232ace6143c9865e4d9c07f51aa200afaf7e48a7d1d8faf366023beab12906ffcb3eaf72c0eb68075e4daf3c080e0c31911befc16f0cc4a09908bb7c1e26abab38bd7b788e1a09c0edf1a35a38d2ff1d3ed47fcdaae2f0934224694f5b56705b9409b6d3d64f3833b686f7576ec64bbdd6ff174e56c2d1edac0011f904681a73face26573fbba4e34652f7ae84acfb2fa5a5b3046f98178cd0831df7477de70e06a4c00e305f31aafc026ef064dd68fd3e4252b1b91d617b26c6d09b6891a00df68f105b5962e7f9d82da101dd595d286da721443b72b2aba2377f6e7772e33b3a5e3753da9c2578c5d1daab80187f55518c72a64ee150a7cb5649823c08c9f62cd7d020b45ec2cba8310db1a7785a46ab24785b4d54ff1660b5ca78e05a9a55edba9c60bf044737bc468101c4e8bd1480d749be5024adefca1d998abe33eaeb6b11fbb39da5d905fdd3f611b2e51517ccee4b8af72c2d948573505590d61a6783ab7278fc43fe55b1fcc0e7216444d3c8039bb8145ef1ce01c50e95a3f3feab0aee883fdb94cc13ee4d21c542aa795e18932228981690f4d4c57ca4db6eb5c092e29d8a05139d509a8aeb48baa1eb97a76e597a32b280b5e9d6c36859064c98ff96ef5126130264fa8d2f49213870d9fb036cff95da51f270311d9976208554e48ffd486470d0ecdb4e619ccbd8226147204baf8e235f54d8b1cba8fa34a9a4d055de515cdf180d2bb6739a175183c472e30b5c914d09eeb1b7dafd6872b38b48c6afc146101200e6e6a44fe5684e220adc11f5c403ddb15df8051e6bdef09117a3a5349938513776286473a3cf1d2788bb875052a2e6459fa7926da33380149c7f98d7700528a60c954e6f5ecb65842fde69d614be69eaa2040a4819ae6e756accf936e14c1e894489744a79c1f2c1eb295d13e2d767c09964b61f9cfe497649f712,0,014e5bdbb1d7eb34a88a016ab3dd45e343dc703fafa8266907ab67a76c5eb2d6,568146140669e69646a6ffeb3793e8010e2732209b4c34ec13e209a070109183,10578110283044630bc13a9f12b00eb0af7cba9f53506add2b57ae07b3987ced,e500c670f1b32f60e05009bddcdbfa7153afb19c20479583a54b43d85b3433a8,67b155367abf65d45a60412e16bd5ef5e862aa0a4a7a56366cfcc602072176b8,93f5b4c59038c16c3f09793976c75e522bf994635e3f1ef9f04e628281e0d5f7,08fe46857ab4e62d7463c00ac510e041d28dbfc21853e8f4db971890c7330098,2271d5f5351a91ca768a83c5aa7f45fb2b2742e89351d93a680f51a030f9255c,3ba1f51de6272aa28fd21059b91d3893,faf3b317340de00e29f2181db270ff81,d083d09c1bdf71795b39a9534601cf7c7a7e767e578c44a17dfaf43a3c18f98c,6aa28bc4b6719eca144ac33a3f17859317d5450e4978db9365ce61e7085a617dd386ec18eb436c9056aa1d2d4736c9bffd25803d967fcae916ce1647ccae3d5258b17dfa1cdc7eb99581c48ff2898ef92d3aa1,
223,c0f15820459f64d98e5c48681d13340572c574533dd9f7161b85fcc8224fdf30,682871104d694baca8b9c7990ae6288f49e1ff4feb21dd5cffad67db7752fdfb6c3608d6996c54be04b35feef037da09ee4d9dca2363b343bc2d4f6d0ea609da,56bd0c06f10352c3a1a9f4b4c92f6fa2b26df124b57878353c1fc691c51abea77c8817daeeb9fa546b77c8daf79d89b22b0e1b87574ece42371f00237aa9d83a,0,7e0e78eb6990b059e6cf0ded66ea93ef82e72aa2f18ac24f2fc6ebab561ae557420729da103f64cecfa20527e15f9fb669a49bbbf274ef0389b3e43c8c44e5f60bf2ac38e2b55e7ec4273dba15ba41d21f8f5b3ee1688b3c29951218caf847a97fb50d75a86515d445699497d968164bf740012679b8962de573be941c62b7ef,1,,1,5d673dd0a75ccacf4e1310e9402ecdacdd474d8bbfa6eeefdde2e1b216d41dbe,2dd7b9cc85524f8670f695c3143ac26b45cebcabb2782a85e0fe15aee3956535,1c229ba46fadced7217df782d410961c1399375135e4aa718fa3424ec36539cc,b764f617cf8c8dcf6018e4f5e8ee603a086498a3732621c9b0fc0a485ea0d2f0,e25747c749e78c7a0102352378f7c15566145b57f082f7e10b10a0606b323996,c0547fbf3082c7a0377b4e709b982ecb4710012dcf3b0c073ed3811a2b7c1309,5bb291885bf5b08a4218c2bf3498d3591be93a47412c770b60299c8e740ac560,fdf5a3e3e75afc15a924373e58af505052731efa75c76a1fa3546954d60b50b1,8461c1dc173be7e6a2316d09710ebd8d,dfa2d33623fe80e2347999e6de0f96fd,279a96e6ce08e5074608fcad77d6a78f90c8b618a4520575435b1a37b1c56df9,,5afbd61f6e989833df2f12ff70c98f1a20ebe84acba2a05429cc6a57238dba87cdc432474f378889b2d0e95ade9f892eb1a1f6b03b73f903682476537f653f738f7a9f1cc9856ed75f3d69122bdeb00af48e66a64872f639a67fc109ee5ca124d0ee183da3c2b8f2da828850b50976b491f1add78d7f01e07565570621266852
448,96cb391886681d1d3e23948e51987771a8ec3001b640c18fb994a855cea66b6e,ffffffffffffffffffffffffffffffffffffffffffffffffffffffffdde3a077a6fd73711a27250c439ba78ef63d89cd0918c0a0a75f301ed96aa2a43ecf3f61,ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa7730be30000000000000000000000000000000000000000000000000000000000000000,1,00cf68f8f7ac49ffaa02c4864fdf6dfe7bbf2c740b88d98c50ebafe32c92f3427f57601ffcb21a3435979287db8fee6c302926741f9d5e464c647eeb9b7acaeda46e00abd7506fc9a719847e9a7328215801e96198dac141a15c7c2f68e0690dd1176292a0dded04d1f548aad88f1aebdc0a8f87da4bb22df32dd7c160c225b843e83f6525d6d484f502f16d923124fc538794e21da2eb689d18d87406ecced5b9f92137239ed1d37bcfa7836641a83cf5e0a1cf63f51b06f158e499a459ede41c,1,,0,f7561c791f6f4aa73dcef3cac32f2433b4cfa4ab0666e93552b7cbc7249fb2de,5232c4b6bde9d3d45d7b763ebd7495399bb825cc21de51011761cd81a51bdc84,2651a46a622f79e2ab18819587e7f897e3f8351b1e1b66d8ed4543a1e40bc569,779a18107756169a6b369d043f3ef9a90178c7ab8c8c37b4edcd9b5397e41eca,368c7283e088e40b79e6214046beab64cbac30a89940acbc30d430f941fe7d35,224065c728d5cdabbe209cd52621324471ce8dc229907c018cec05781a9c770d,9ce33c019a081e5f8b62e1f12d652f0b036ed65f5de195d931dfcd92043b5eb2,001e576d8828a6d84913b01cb88e8f5532207f34275017b61650ba1383646cbc,7bf55f6b58f73cdff19ee3292607239f,d121874372c61a48fd87da6d01d89da4,e9515794acced50e0550a3ebd95c170d2abd48b5f23fccca73bc597f00c88cf2,,33953941be2682da1c6d1b167cbf180d7cb8159c94c6ea1c52356716f1057af4df53321f18894c285f7b2fd85b2edc44a13c9295f310962fdfc8d944bd77c5500b10ca68ca5d0977d19d183a7def742c41cfeee763dc09ef985c96ab6e74e464f66992f752c9368e42082ad338705062ddfcad4ca1c9c54004b9345d8df25953
673,4a7065c3ddbf84e29b8e20da0da3aaae1f708eae8ad1af4c4c00f46a7cda7b6b,ffffffffffffffffffffffffffffffffffffffffffffffffffffffff450012ec3aeecf516f4b374af2e7fbb040e92dc3c0f12eafd00c729a137f4e892e5293c3,9652d78baefc028cd37a6a92625b8b8f85fde1e4c944ad3f20e198bef8c02f19fffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e91870,0,5c6272ee55da855bbbf7b1246d9885aa7aa601a715ab86fa46c50da533badf82b97597c968293ae04e,97561,,0,a0ff3dd41ca11036eea75ea08993c938894c7eebca99354ac2e0daa8a1a6b2ca,64c383e0e78ac99476ddff2061683eeefa505e3666673a1371342c3e6c26981d,ca3f58a228c530be63eec8a427d16496776aefb22e693152a3a9394b9a87d097,a993062a328371beecae7e2b05a34355c1cefbad7f855ad48331dcf002972999,24cdf9d8533696a5795cadcf5b94826ddbe5f047ba02c832b3495ac7c1110e31,7b5d1c66668d20d57a4e0a6ba4d9aa3e3ba0f704697aa7edb9ce9471d46647da,e6a808d35ee403b3f4bbcd8fd49fa005a40dfaaf36f9f504318bb94637067060,d6ae42117344fb71cb1817a1dc192a4b5bb35d885005093c3e9bd4576069b217,1fec304dcaacf1f5b088325306272d78,d2d16a8452807baa4f63b059b5804624,dccb606c4f2a0f64bc164dbc00eb0f6cf1474575e89d7928be6346720bb53610,,58daef966f33c036740aeb3f6a4b31c0f0a070b25fd6a1abf82ef56fc2cb3ca8da8c434f23790c69349dd0cb4058f88a7bd0e333c8ceba3c80f21e951b9fdb1c84e2e7f49f43c21087566d58f1bcc42b041e0b462e37e927c0071caa9a2b650dccf448c9f88d73b62e80a3e5d5e4e46992e34b416ceb9590a7c8b7bfaccf37ab
1024,0f69aeffeff6172647ee5aa80bfb418ee742f4e9f1a51b463ac7c120d620e37d,ffffffffffffffffffffffffffffffffffffffffffffffffffffffff04df0e67f9753e2cdb066b3b588a0069fde936a312e0d3f31acb335026b7072d8f2ad24c,12a50f3fafea7c1eeada4cf8d33777704b77361453afc83bda91eef349ae044d20126c6200547ea5a6911776c05dee2a7f1a9ba7dfbabbbd273c3ef29ef46e46,1,5f67d15d22ca9b2804eeab0a66f7f8e3a10fa5de5809a046084348cbc5304e843ef96f59a59c7d7fdfe5946489f3ea297d941bac326225df316a25fc90f0e65b0d31a9c497e960fdbf8c482516bc8a9c1c77b7f6d0e1143810c737f76f9224e6f2c9af5186b4f7259c7e8d165b6e4fe3d38a60bdbdd4d06ecdcaaf62086070dbb68686b802d53dfd7db14b18743832605f5461ad81e2af4b7e8ff0eff0867a25b93cec7becf15c43131895fed09a83bf1ee4a87d44dd0f02a837bf5a1232e201cb882734eb9643dc2dc4d4e8b5690840766212c7ac8f38ad8a9ec47c7a9b3e022ae3eb6a32522128b518bd0d0085dd81c5,69615,,1,115b298a52a9362706ddd1e493de09443dd8ac2b0c3e4e5e8b6bb295598db05d,eef379db9bd4b1aa90fc347fad33f7d53083389e22e971036f59f4e29d325ac2,32e15c20a09591b6600c778752a582fed444444fd0d3317613555c6509ff4b8d,1756deace376ece25da9825fe49f76a9272a89a7b746c83ca2c4016f5a30ead4,15e26b12238d66ebc4cb72d16a62a8bb404c94d31bbe3b1d22a01b851e935010,c135367f39b24a9cc9b73ad628fba1887737f5686062c4c36146e76849828a50,ffa25ddf7cd4cd10a47f6c3b32a54ee882837058e31677d3958539f4f23e4616,12f9b3ebbf743f6b93c7d0f4f20259fac2a27ea6735fd9ef2e2699049af60fcc,4dfac3b0a99401f6aad1a8df3cd7dd05,e5d4905a8b6a5d18ec6cebbdecd703d3,fc2431beb9a666bf888df0662276a4b6a1af5061072992ef408f2b686c86a2ac,,1a7f3fb83ad2b050b663b8df6b7c2cc2d8e169a869a58bf7ef5ab5db97a505c84a812e100d9445da4fc39a1176d6aed3995f6868631224b86f10603217c8d13270e0c6d054ad9e0d0b7dc0c8e59a37cd05a0a45faa14b4ffc8d12b641f62e6f1b71c1f72b737e9ce3fe74be779b25e70bf11d98766b3876d0fa28d3c669087fc
================================================
FILE: bip-0324/reference.py
================================================
"""Reference implementation for the cryptographic aspects of BIP-324"""
import sys
import random
import hashlib
import hmac
### BIP-340 tagged hash
def TaggedHash(tag, data):
"""Compute BIP-340 tagged hash with specified tag string of data."""
ss = hashlib.sha256(tag.encode('utf-8')).digest()
ss += ss
ss += data
return hashlib.sha256(ss).digest()
### HKDF-SHA256
def hmac_sha256(key, data):
"""Compute HMAC-SHA256 from specified byte arrays key and data."""
return hmac.new(key, data, hashlib.sha256).digest()
def hkdf_sha256(length, ikm, salt, info):
"""Derive a key using HKDF-SHA256."""
if len(salt) == 0:
salt = bytes([0] * 32)
prk = hmac_sha256(salt, ikm)
t = b""
okm = b""
for i in range((length + 32 - 1) // 32):
t = hmac_sha256(prk, t + info + bytes([i + 1]))
okm += t
return okm[:length]
### secp256k1 field/group elements
def modinv(a, n):
"""Compute the modular inverse of a modulo n using the extended Euclidean
Algorithm. See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers.
"""
a = a % n
if a == 0:
return 0
if sys.hexversion >= 0x3080000:
# A more efficient version is available in Python 3.8.
return pow(a, -1, n)
t1, t2 = 0, 1
r1, r2 = n, a
while r2 != 0:
q = r1 // r2
t1, t2 = t2, t1 - q * t2
r1, r2 = r2, r1 - q * r2
if r1 > 1:
return None
if t1 < 0:
t1 += n
return t1
class FE:
"""Objects of this class represent elements of the field GF(2**256 - 2**32 - 977).
They are represented internally in numerator / denominator form, in order to delay inversions.
"""
SIZE = 2**256 - 2**32 - 977
def __init__(self, a=0, b=1):
"""Initialize an FE as a/b; both a and b can be ints or field elements."""
if isinstance(b, FE):
if isinstance(a, FE):
self.num = (a.num * b.den) % FE.SIZE
self.den = (a.den * b.num) % FE.SIZE
else:
self.num = (a * b.den) % FE.SIZE
self.den = b.num
else:
b = b % FE.SIZE
assert b != 0
if isinstance(a, FE):
self.num = a.num
self.den = (a.den * b) % FE.SIZE
else:
self.num = a % FE.SIZE
self.den = b
def __add__(self, a):
"""Compute the sum of two field elements (second may be int)."""
if isinstance(a, FE):
return FE(self.num * a.den + self.den * a.num, self.den * a.den)
return FE(self.num + self.den * a, self.den)
def __radd__(self, a):
"""Compute the sum of an integer and a field element."""
return FE(self.num + self.den * a, self.den)
def __sub__(self, a):
"""Compute the difference of two field elements (second may be int)."""
if isinstance(a, FE):
return FE(self.num * a.den - self.den * a.num, self.den * a.den)
return FE(self.num - self.den * a, self.den)
def __rsub__(self, a):
"""Compute the difference between an integer and a field element."""
return FE(self.den * a - self.num, self.den)
def __mul__(self, a):
"""Compute the product of two field elements (second may be int)."""
if isinstance(a, FE):
return FE(self.num * a.num, self.den * a.den)
return FE(self.num * a, self.den)
def __rmul__(self, a):
"""Compute the product of an integer with a field element."""
return FE(self.num * a, self.den)
def __truediv__(self, a):
"""Compute the ratio of two field elements (second may be int)."""
return FE(self, a)
def __rtruediv__(self, a):
"""Compute the ratio of an integer and a field element."""
return FE(a, self)
def __pow__(self, a):
"""Raise a field element to a (positive) integer power."""
return FE(pow(self.num, a, FE.SIZE), pow(self.den, a, FE.SIZE))
def __neg__(self):
"""Negate a field element."""
return FE(-self.num, self.den)
def __int__(self):
"""Convert a field element to an integer. The result is cached."""
if self.den != 1:
self.num = (self.num * modinv(self.den, FE.SIZE)) % FE.SIZE
self.den = 1
return self.num
def sqrt(self):
"""Compute the square root of a field element.
Due to the fact that our modulus p is of the form p = 3 (mod 4), the
Tonelli-Shanks algorithm (https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm)
is simply raising the argument to the power (p + 1) / 4.
To see why: p-1 = 0 (mod 2), so 2 divides the order of the multiplicative group,
and thus only half of the non-zero field elements are squares. An element a is
a (nonzero) square when Euler's criterion, a^((p-1)/2) = 1 (mod p), holds. We're
looking for x such that x^2 = a (mod p). Given a^((p-1)/2) = 1 (mod p), that is
equivalent to x^2 = a^(1 + (p-1)/2) (mod p). As (1 + (p-1)/2) is even, this is
equivalent to x = a^((1 + (p-1)/2)/2) (mod p), or x = a^((p+1)/4) (mod p)."""
v = int(self)
s = pow(v, (FE.SIZE + 1) // 4, FE.SIZE)
if s**2 % FE.SIZE == v:
return FE(s)
return None
def sqrts(self):
"""Compute all square roots of a field element, if any."""
s = self.sqrt()
if s is None:
return []
return [FE(s), -FE(s)]
# The cube roots of 1 (mod p).
CBRT1 = [
1,
0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40,
0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee
]
def cbrts(self):
"""Compute all cube roots of a field element, if any.
Due to the fact that our modulus p is of the form p = 7 (mod 9), one cube root
can always be computed by raising to the power of (p + 2) / 9. The other roots
(if any) can be found by multiplying with the two non-trivial cube roots of 1.
To see why: p-1 = 0 (mod 3), so 3 divides the order of the multiplicative group,
and thus only 1/3 of the non-zero field elements are cubes. An element a is a
(nonzero) cube when a^((p-1)/3) = 1 (mod p). We're looking for x such that
x^3 = a (mod p). Given a^((p-1)/3) = 1 (mod p), that is equivalent to
x^3 = a^(1 + (p-1)/3) (mod p). As (1 + (p-1)/3) is a multiple of 3, this is
equivalent to x = a^((1 + (p-1)/3)/3) (mod p), or x = a^((p+2)/9) (mod p)."""
v = int(self)
c = pow(v, (FE.SIZE + 2) // 9, FE.SIZE)
if pow(c, 3, FE.SIZE) == v:
return [FE(c * f) for f in FE.CBRT1]
return []
def is_square(self):
"""Determine if this field element has a square root."""
# Compute the Jacobi symbol of (self / p). Since our modulus is prime, this
# is the same as the Legendre symbol, which determines quadratic residuosity.
# See https://en.wikipedia.org/wiki/Jacobi_symbol for the algorithm.
n, k, t = (self.num * self.den) % FE.SIZE, FE.SIZE, 0
if n == 0:
return True
while n != 0:
while n & 1 == 0:
n >>= 1
r = k & 7
t ^= (r in (3, 5))
n, k = k, n
t ^= (n & k & 3 == 3)
n = n % k
assert k == 1
return not t
def __eq__(self, a):
"""Check whether two field elements are equal (second may be an int)."""
if isinstance(a, FE):
return (self.num * a.den - self.den * a.num) % FE.SIZE == 0
return (self.num - self.den * a) % FE.SIZE == 0
def to_bytes(self):
"""Convert a field element to 32-byte big endian encoding."""
return int(self).to_bytes(32, 'big')
@staticmethod
def from_bytes(b):
"""Convert a 32-byte big endian encoding of a field element to an FE."""
v = int.from_bytes(b, 'big')
if v >= FE.SIZE:
return None
return FE(v)
def __str__(self):
"""Convert this field element to a string."""
return f"{int(self):064x}"
def __repr__(self):
"""Get a string representation of this field element."""
return f"FE(0x{int(self):x})"
assert all(pow(c, 3, FE.SIZE) == 1 for c in FE.CBRT1)
class GE:
"""Objects of this class represent points (group elements) on the secp256k1 curve.
The point at infinity is represented as None."""
ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
ORDER_HALF = ORDER // 2
def __init__(self, x, y):
"""Initialize a group element with specified x and y coordinates (must be on curve)."""
fx = FE(x)
fy = FE(y)
assert fy**2 == fx**3 + 7
self.x = fx
self.y = fy
def double(self):
"""Compute the double of a point."""
l = 3 * self.x**2 / (2 * self.y)
x3 = l**2 - 2 * self.x
y3 = l * (self.x - x3) - self.y
return GE(x3, y3)
def __add__(self, a):
"""Add two points, or a point and infinity, together."""
if a is None:
# Adding point at infinity
return self
if self.x != a.x:
# Adding distinct x coordinates
l = (a.y - self.y) / (a.x - self.x)
x3 = l**2 - self.x - a.x
y3 = l * (self.x - x3) - self.y
return GE(x3, y3)
if self.y == a.y:
# Adding point to itself
return self.double()
# Adding point to its negation
return None
def __radd__(self, a):
"""Add infinity to a point."""
assert a is None
return self
def __mul__(self, a):
"""Multiply a point with an integer (scalar multiplication)."""
r = None
for i in range(a.bit_length() - 1, -1, -1):
if r is not None:
r = r.double()
if (a >> i) & 1:
r += self
return r
def __rmul__(self, a):
"""Multiply an integer with a point (scalar multiplication)."""
return self * a
@staticmethod
def lift_x(x):
"""Take an FE, and return the point with that as X coordinate, and square Y."""
y = (FE(x)**3 + 7).sqrt()
if y is None:
return None
return GE(x, y)
@staticmethod
def is_valid_x(x):
"""Determine whether the provided field element is a valid X coordinate."""
return (FE(x)**3 + 7).is_square()
def __str__(self):
"""Convert this group element to a string."""
return f"({self.x},{self.y})"
def __repr__(self):
"""Get a string representation for this group element."""
return f"GE(0x{int(self.x)},0x{int(self.y)})"
SECP256K1_G = GE(
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
### ElligatorSwift
# Precomputed constant square root of -3 (mod p).
MINUS_3_SQRT = FE(-3).sqrt()
def xswiftec(u, t):
"""Decode field elements (u, t) to an X coordinate on the curve."""
if u == 0:
u = FE(1)
if t == 0:
t = FE(1)
if u**3 + t**2 + 7 == 0:
t = 2 * t
X = (u**3 + 7 - t**2) / (2 * t)
Y = (X + t) / (MINUS_3_SQRT * u)
for x in (u + 4 * Y**2, (-X / Y - u) / 2, (X / Y - u) / 2):
if GE.is_valid_x(x):
return x
assert False
def xswiftec_inv(x, u, case):
"""Given x and u, find t such that xswiftec(u, t) = x, or return None.
Case selects which of the up to 8 results to return."""
if case & 2 == 0:
if GE.is_valid_x(-x - u):
return None
v = x
s = -(u**3 + 7) / (u**2 + u*v + v**2)
else:
s = x - u
if s == 0:
return None
r = (-s * (4 * (u**3 + 7) + 3 * s * u**2)).sqrt()
if r is None:
return None
if case & 1 and r == 0:
return None
v = (-u + r / s) / 2
w = s.sqrt()
if w is None:
return None
if case & 5 == 0: return -w * (u * (1 - MINUS_3_SQRT) / 2 + v)
if case & 5 == 1: return w * (u * (1 + MINUS_3_SQRT) / 2 + v)
if case & 5 == 4: return w * (u * (1 - MINUS_3_SQRT) / 2 + v)
if case & 5 == 5: return -w * (u * (1 + MINUS_3_SQRT) / 2 + v)
def xelligatorswift(x):
"""Given a field element X on the curve, find (u, t) that encode them."""
while True:
u = FE(random.randrange(1, GE.ORDER))
case = random.randrange(0, 8)
t = xswiftec_inv(x, u, case)
if t is not None:
return u, t
def ellswift_create():
"""Generate a (privkey, ellswift_pubkey) pair."""
priv = random.randrange(1, GE.ORDER)
u, t = xelligatorswift((priv * SECP256K1_G).x)
return priv.to_bytes(32, 'big'), u.to_bytes() + t.to_bytes()
def ellswift_decode(ellswift):
"""Convert ellswift encoded X coordinate to 32-byte xonly format."""
u = FE(int.from_bytes(ellswift[:32], 'big'))
t = FE(int.from_bytes(ellswift[32:], 'big'))
return xswiftec(u, t).to_bytes()
def ellswift_ecdh_xonly(pubkey_theirs, privkey):
"""Compute X coordinate of shared ECDH point between elswift pubkey and privkey."""
d = int.from_bytes(privkey, 'big')
pub = ellswift_decode(pubkey_theirs)
return (d * GE.lift_x(FE.from_bytes(pub))).x.to_bytes()
### Poly1305
class Poly1305:
"""Class representing a running poly1305 computation."""
MODULUS = 2**130 - 5
def __init__(self, key):
self.r = int.from_bytes(key[:16], 'little') & 0xffffffc0ffffffc0ffffffc0fffffff
self.s = int.from_bytes(key[16:], 'little')
self.acc = 0
def add(self, msg, length=None, pad=False):
"""Add a message of any length. Input so far must be a multiple of 16 bytes."""
length = len(msg) if length is None else length
for i in range((length + 15) // 16):
chunk = msg[i * 16:i * 16 + min(16, length - i * 16)]
val = int.from_bytes(chunk, 'little') + 256**(16 if pad else len(chunk))
self.acc = (self.r * (self.acc + val)) % Poly1305.MODULUS
return self
def tag(self):
"""Compute the poly1305 tag."""
return ((self.acc + self.s) & 0xffffffffffffffffffffffffffffffff).to_bytes(16, 'little')
### ChaCha20
CHACHA20_INDICES = (
(0, 4, 8, 12), (1, 5, 9, 13), (2, 6, 10, 14), (3, 7, 11, 15),
(0, 5, 10, 15), (1, 6, 11, 12), (2, 7, 8, 13), (3, 4, 9, 14)
)
CHACHA20_CONSTANTS = (0x61707865, 0x3320646e, 0x79622d32, 0x6b206574)
def rotl32(v, bits):
"""Rotate the 32-bit value v left by bits bits."""
return ((v << bits) & 0xffffffff) | (v >> (32 - bits))
def chacha20_doubleround(s):
"""Apply a ChaCha20 double round to 16-element state array s.
See https://cr.yp.to/chacha/chacha-20080128.pdf and https://tools.ietf.org/html/rfc8439
"""
for a, b, c, d in CHACHA20_INDICES:
s[a] = (s[a] + s[b]) & 0xffffffff
s[d] = rotl32(s[d] ^ s[a], 16)
s[c] = (s[c] + s[d]) & 0xffffffff
s[b] = rotl32(s[b] ^ s[c], 12)
s[a] = (s[a] + s[b]) & 0xffffffff
s[d] = rotl32(s[d] ^ s[a], 8)
s[c] = (s[c] + s[d]) & 0xffffffff
s[b] = rotl32(s[b] ^ s[c], 7)
def chacha20_block(key, nonce, cnt):
"""Compute the 64-byte output of the ChaCha20 block function.
Takes as input a 32-byte key, 12-byte nonce, and 32-bit integer counter.
"""
# Initial state.
init = [0 for _ in range(16)]
for i in range(4):
init[i] = CHACHA20_CONSTANTS[i]
for i in range(8):
init[4 + i] = int.from_bytes(key[4 * i:4 * (i+1)], 'little')
init[12] = cnt
for i in range(3):
init[13 + i] = int.from_bytes(nonce[4 * i:4 * (i+1)], 'little')
# Perform 20 rounds.
state = list(init)
for _ in range(10):
chacha20_doubleround(state)
# Add initial values back into state.
for i in range(16):
state[i] = (state[i] + init[i]) & 0xffffffff
# Produce byte output
return b''.join(state[i].to_bytes(4, 'little') for i in range(16))
### ChaCha20Poly1305
def aead_chacha20_poly1305_encrypt(key, nonce, aad, plaintext):
"""Encrypt a plaintext using ChaCha20Poly1305."""
ret = bytearray()
msg_len = len(plaintext)
for i in range((msg_len + 63) // 64):
now = min(64, msg_len - 64 * i)
keystream = chacha20_block(key, nonce, i + 1)
for j in range(now):
ret.append(plaintext[j + 64 * i] ^ keystream[j])
poly1305 = Poly1305(chacha20_block(key, nonce, 0)[:32])
poly1305.add(aad, pad=True).add(ret, pad=True)
poly1305.add(len(aad).to_bytes(8, 'little') + msg_len.to_bytes(8, 'little'))
ret += poly1305.tag()
return bytes(ret)
def aead_chacha20_poly1305_decrypt(key, nonce, aad, ciphertext):
"""Decrypt a ChaCha20Poly1305 ciphertext."""
if len(ciphertext) < 16:
return None
msg_len = len(ciphertext) - 16
poly1305 = Poly1305(chacha20_block(key, nonce, 0)[:32])
poly1305.add(aad, pad=True)
poly1305.add(ciphertext, length=msg_len, pad=True)
poly1305.add(len(aad).to_bytes(8, 'little') + msg_len.to_bytes(8, 'little'))
if ciphertext[-16:] != poly1305.tag():
return None
ret = bytearray()
for i in range((msg_len + 63) // 64):
now = min(64, msg_len - 64 * i)
keystream = chacha20_block(key, nonce, i + 1)
for j in range(now):
ret.append(ciphertext[j + 64 * i] ^ keystream[j])
return bytes(ret)
### FSChaCha20{,Poly1305}
REKEY_INTERVAL = 224 # packets
class FSChaCha20Poly1305:
"""Rekeying wrapper AEAD around ChaCha20Poly1305."""
def __init__(self, initial_key):
self.key = initial_key
self.packet_counter = 0
def crypt(self, aad, text, is_decrypt):
"""Encrypt or decrypt the specified (plain/cipher)text."""
nonce = ((self.packet_counter % REKEY_INTERVAL).to_bytes(4, 'little') +
(self.packet_counter // REKEY_INTERVAL).to_bytes(8, 'little'))
if is_decrypt:
ret = aead_chacha20_poly1305_decrypt(self.key, nonce, aad, text)
else:
ret = aead_chacha20_poly1305_encrypt(self.key, nonce, aad, text)
if (self.packet_counter + 1) % REKEY_INTERVAL == 0:
rekey_nonce = b"\xFF\xFF\xFF\xFF" + nonce[4:]
newkey1 = aead_chacha20_poly1305_encrypt(self.key, rekey_nonce, b"", b"\x00" * 32)[:32]
newkey2 = chacha20_block(self.key, rekey_nonce, 1)[:32]
assert newkey1 == newkey2
self.key = newkey1
self.packet_counter += 1
return ret
def encrypt(self, aad, plaintext):
"""Encrypt the specified plaintext with provided AAD."""
return self.crypt(aad, plaintext, False)
def decrypt(self, aad, ciphertext):
"""Decrypt the specified ciphertext with provided AAD."""
return self.crypt(aad, ciphertext, True)
class FSChaCha20:
"""Rekeying wrapper stream cipher around ChaCha20."""
def __init__(self, initial_key):
self.key = initial_key
self.block_counter = 0
self.chunk_counter = 0
self.keystream = b''
def get_keystream_bytes(self, nbytes):
"""Generate nbytes keystream bytes."""
while len(self.keystream) < nbytes:
nonce = ((0).to_bytes(4, 'little') +
(self.chunk_counter // REKEY_INTERVAL).to_bytes(8, 'little'))
self.keystream += chacha20_block(self.key, nonce, self.block_counter)
self.block_counter += 1
ret = self.keystream[:nbytes]
self.keystream = self.keystream[nbytes:]
return ret
def crypt(self, chunk):
"""Encrypt or decrypt chunk."""
ks = self.get_keystream_bytes(len(chunk))
ret = bytes([ks[i] ^ chunk[i] for i in range(len(chunk))])
if ((self.chunk_counter + 1) % REKEY_INTERVAL) == 0:
self.key = self.get_keystream_bytes(32)
self.block_counter = 0
self.chunk_counter += 1
return ret
def encrypt(self, chunk):
"""Encrypt chunk."""
return self.crypt(chunk)
def decrypt(self, chunk):
"""Decrypt chunk."""
return self.crypt(chunk)
### Shared secret computation
def v2_ecdh(priv, ellswift_theirs, ellswift_ours, initiating):
"""Compute BIP324 shared secret."""
ecdh_point_x32 = ellswift_ecdh_xonly(ellswift_theirs, priv)
if initiating:
# Initiating, place our public key encoding first.
return TaggedHash("bip324_ellswift_xonly_ecdh",
ellswift_ours + ellswift_theirs + ecdh_point_x32)
# Responding, place their public key encoding first.
return TaggedHash("bip324_ellswift_xonly_ecdh",
ellswift_theirs + ellswift_ours + ecdh_point_x32)
### Key derivation
NETWORK_MAGIC = b'\xf9\xbe\xb4\xd9'
def initialize_v2_transport(ecdh_secret, initiating):
"""Return a peer object with various BIP324 derived keys and ciphers."""
peer = {}
salt = b'bitcoin_v2_shared_secret' + NETWORK_MAGIC
for name, length in (
('initiator_L', 32), ('initiator_P', 32), ('responder_L', 32), ('responder_P', 32),
('garbage_terminators', 32), ('session_id', 32)):
peer[name] = hkdf_sha256(
salt=salt, ikm=ecdh_secret, info=name.encode('utf-8'), length=length)
peer['initiator_garbage_terminator'] = peer['garbage_terminators'][:16]
peer['responder_garbage_terminator'] = peer['garbage_terminators'][16:]
del peer['garbage_terminators']
if initiating:
peer['send_L'] = FSChaCha20(peer['initiator_L'])
peer['send_P'] = FSChaCha20Poly1305(peer['initiator_P'])
peer['send_garbage_terminator'] = peer['initiator_garbage_terminator']
peer['recv_L'] = FSChaCha20(peer['responder_L'])
peer['recv_P'] = FSChaCha20Poly1305(peer['responder_P'])
peer['recv_garbage_terminator'] = peer['responder_garbage_terminator']
else:
peer['send_L'] = FSChaCha20(peer['responder_L'])
peer['send_P'] = FSChaCha20Poly1305(peer['responder_P'])
peer['send_garbage_terminator'] = peer['responder_garbage_terminator']
peer['recv_L'] = FSChaCha20(peer['initiator_L'])
peer['recv_P'] = FSChaCha20Poly1305(peer['initiator_P'])
peer['recv_garbage_terminator'] = peer['initiator_garbage_terminator']
return peer
### Packet encryption
LENGTH_FIELD_LEN = 3
HEADER_LEN = 1
IGNORE_BIT_POS = 7
def v2_enc_packet(peer, contents, aad=b'', ignore=False):
"""Encrypt a BIP324 packet."""
assert len(contents) <= 2**24 - 1
header = (ignore << IGNORE_BIT_POS).to_bytes(HEADER_LEN, 'little')
plaintext = header + contents
aead_ciphertext = peer['send_P'].encrypt(aad, plaintext)
enc_plaintext_len = peer['send_L'].encrypt(len(contents).to_bytes(LENGTH_FIELD_LEN, 'little'))
return enc_plaintext_len + aead_ciphertext
================================================
FILE: bip-0324/run_test_vectors.py
================================================
"""Run the BIP-324 test vectors."""
import csv
import os
import sys
import reference
FILENAME_PACKET_TEST = os.path.join(sys.path[0], 'packet_encoding_test_vectors.csv')
FILENAME_XSWIFTEC_INV_TEST = os.path.join(sys.path[0], 'xswiftec_inv_test_vectors.csv')
FILENAME_ELLSWIFT_DECODE_TEST = os.path.join(sys.path[0], 'ellswift_decode_test_vectors.csv')
with open(FILENAME_PACKET_TEST, newline='', encoding='utf-8') as csvfile:
print(f"Running {FILENAME_PACKET_TEST} tests...")
reader = csv.DictReader(csvfile)
for row in reader:
in_initiating = int(row['in_initiating'])
bytes_priv_ours = bytes.fromhex(row['in_priv_ours'])
int_priv_ours = int.from_bytes(bytes_priv_ours, 'big')
assert row['mid_x_ours'] == (int_priv_ours * reference.SECP256K1_G).x.to_bytes().hex()
bytes_ellswift_ours = bytes.fromhex(row['in_ellswift_ours'])
assert row['mid_x_ours'] == reference.ellswift_decode(bytes_ellswift_ours).hex()
bytes_ellswift_theirs = bytes.fromhex(row['in_ellswift_theirs'])
assert row['mid_x_theirs'] == reference.ellswift_decode(bytes_ellswift_theirs).hex()
x_shared = reference.ellswift_ecdh_xonly(bytes_ellswift_theirs, bytes_priv_ours)
assert row['mid_x_shared'] == x_shared.hex()
shared_secret = reference.v2_ecdh(bytes_priv_ours, bytes_ellswift_theirs,
bytes_ellswift_ours, in_initiating)
assert row['mid_shared_secret'] == shared_secret.hex()
peer = reference.initialize_v2_transport(shared_secret, in_initiating)
assert row['mid_initiator_l'] == peer['initiator_L'].hex()
assert row['mid_initiator_p'] == peer['initiator_P'].hex()
assert row['mid_responder_l'] == peer['responder_L'].hex()
assert row['mid_responder_p'] == peer['responder_P'].hex()
assert row['mid_send_garbage_terminator'] == peer['send_garbage_terminator'].hex()
assert row['mid_recv_garbage_terminator'] == peer['recv_garbage_terminator'].hex()
assert row['out_session_id'] == peer['session_id'].hex()
for _ in range(int(row['in_idx'])):
reference.v2_enc_packet(peer, b"")
ciphertext = reference.v2_enc_packet(
peer,
bytes.fromhex(row['in_contents']) * int(row['in_multiply']),
bytes.fromhex(row['in_aad']), int(row['in_ignore']))
if len(row['out_ciphertext']):
assert row['out_ciphertext'] == ciphertext.hex()
if len(row['out_ciphertext_endswith']):
assert ciphertext.hex().endswith(row['out_ciphertext_endswith'])
with open(FILENAME_XSWIFTEC_INV_TEST, newline='', encoding='utf-8') as csvfile:
print(f"Running {FILENAME_XSWIFTEC_INV_TEST} tests...")
reader = csv.DictReader(csvfile)
for row in reader:
u = reference.FE.from_bytes(bytes.fromhex(row['u']))
x = reference.FE.from_bytes(bytes.fromhex(row['x']))
for case in range(8):
ret = reference.xswiftec_inv(x, u, case)
if ret is None:
assert row[f"case{case}_t"] == ""
else:
assert row[f"case{case}_t"] == ret.to_bytes().hex()
assert reference.xswiftec(u, ret) == x
with open(FILENAME_ELLSWIFT_DECODE_TEST, newline='', encoding='utf-8') as csvfile:
print(f"Running {FILENAME_ELLSWIFT_DECODE_TEST} tests...")
reader = csv.DictReader(csvfile)
for row in reader:
ellswift = bytes.fromhex(row['ellswift'])
assert reference.ellswift_decode(ellswift).hex() == row['x']
================================================
FILE: bip-0324/secp256k1_test_vectors.py
================================================
"""Convert the BIP-324 test vectors to secp256k1 code."""
import csv
import reference
import os
import sys
FILENAME_XSWIFTEC_INV_TEST = os.path.join(sys.path[0], 'xswiftec_inv_test_vectors.csv')
FILENAME_ELLSWIFT_DECODE_TEST = os.path.join(sys.path[0], 'ellswift_decode_test_vectors.csv')
def format_int(v):
"""Format 0 as "0", but other integers as 0x%08x."""
if v == 0:
return "0"
return f"0x{v:08x}"
def format_fe(fe):
"""Format a field element constant as SECP256K1_FE_CONST code."""
vals = [(int(fe) >> (32 * (7 - i))) & 0xffffffff for i in range(8)]
strs = ", ".join(format_int(v) for v in vals)
return f"SECP256K1_FE_CONST({strs})"
def output_xswiftec_inv_cases():
"""Generate lines corresponding to the xswiftec_inv test cases."""
with open(FILENAME_XSWIFTEC_INV_TEST, newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
print("xswiftec_inv cases:")
for row in reader:
u = int.from_bytes(bytes.fromhex(row['u']), 'big')
x = int.from_bytes(bytes.fromhex(row['x']), 'big')
pat = sum(1<
BIP: 324
Layer: Peer Services
Title: Version 2 P2P Encrypted Transport Protocol
Authors: Dhruv Mehta
Tim Ruffing
Jonas Schnelli
Pieter Wuille
Status: Deployed
Type: Specification
Assigned: 2019-03-08
License: BSD-3-Clause
Version: 1.0.2
Replaces: 151
== Introduction ==
=== Abstract ===
This document proposes a new Bitcoin P2P transport protocol, which features opportunistic encryption, a mild bandwidth reduction, and the ability to negotiate upgrades before exchanging application messages.
=== Copyright ===
This document is licensed under the 3-clause BSD license.
=== Motivation ===
Bitcoin is a permissionless network whose purpose is to reach consensus over public data. Since all data relayed in the Bitcoin P2P network is inherently public, and the protocol lacks a notion of cryptographic identities, peers talk to each other over unencrypted and unauthenticated connections. Nevertheless, this plaintext nature of the current P2P protocol (referred to as v1 in this document) has severe drawbacks in the presence of attackers:
* While the relayed data itself is public in nature, the associated metadata may reveal private information and hamper privacy of users. For example, a global passive attacker eavesdropping on all Bitcoin P2P connections can trivially identify the source and timing of a transaction.
* Since connections are unauthenticated, they can be tampered with at a low cost and often even with a low risk of detection. For example, an attacker can alter specific bytes of a connection (such as node flags) on-the-fly without the need to keep any state.
* The protocol is self-revealing. For example, deep packet inspection can identify a P2P connection trivially because connections start with a fixed sequence of magic bytes. The ability to detect connections enables censorship and facilitates the aforementioned attacks as well as other attacks which require the attacker to control the connections of victims, e.g., eclipse attacks targeted at miners.
This proposal for a new P2P protocol version (v2) aims to improve upon this by raising the costs for performing these attacks substantially, primarily through the use of unauthenticated, opportunistic transport encryption. In addition, the bytestream on the wire is made pseudorandom (i.e., indistinguishable from uniformly random bytes) to a passive eavesdropper.
* Encryption, even when it is unauthenticated and only used when both endpoints support v2, impedes eavesdropping by forcing the attacker to become active: either by performing a persistent man-in-the-middle (MitM) attack, by downgrading connections to v1, or by spinning up their own nodes and getting honest nodes to make connections to them. Active attacks at scale are more resource intensive in general, but in the case of manual, deliberate connections (as opposed to automatic, random ones), they are also in principle detectable: even very basic checks, e.g., operators manually comparing protocol versions and session IDs (as supported by the proposed protocol), will expose the attacker.
* Tampering, while already an inherently active attack, is costlier if the attacker is forced to maintain the state necessary for a full MitM interception.
* A pseudorandom bytestream excludes identification techniques based on pattern matching, and makes it easier to shape the bytestream in order to mimic other protocols used on the Internet. This raises the cost of a connection censoring firewall, forcing them to either resort to a full MitM attack, or operate on a more obvious allowlist basis, rather than a blocklist basis.
''' Why encrypt without authentication?'''
As we have argued above, unauthenticated encryption'''What does ''authentication'' mean in this context?''' Unfortunately, the term authentication in the context of secure channel protocols is ambiguous. It can refer to:
* The encryption scheme guaranteeing that a message obtained via successful decryption was encrypted by someone having access to the (symmetric) encryption key, and not modified after encryption by a third party. The proposal in this document achieves that property through the use of an AEAD.
* The communication protocol establishing that the communication partner's identity matches who we expect them to be, through some public key mechanism. The proposal in this document does '''not''' include such a mechanism. provides strictly better security than no encryption. Thus, all connections should use encryption, even if they are unauthenticated.
When it comes to authentication, the situation is not as clear as for encryption. Due to Bitcoin's permissionless nature, authentication will always be restricted to specific scenarios (e.g., connections between peers belonging to the same operator), and whether some form of (possibly partially anonymous) authentication is desired depends on the specific requirements of the involved peers. As a consequence, we believe that authentication should be addressed separately (if desired), and this proposal aims to provide a solid technical basis for future protocol upgrades, including the addition of optional authentication (see [https://github.com/sipa/writeups/tree/main/private-authentication-protocols Private authentication protocols]).
''' Why have a pseudorandom bytestream when traffic analysis is still possible? '''
Traffic analysis, e.g., observing packet lengths and timing, as well as active attacks can still reveal that the Bitcoin v2 P2P protocol is in use. Nevertheless, a pseudorandom bytestream raises the cost of fingerprinting the protocol substantially, and may force some intermediaries to attack any protocol they cannot identify, causing collateral cost.
A pseudorandom bytestream is not self-identifying. Moreover, it is unopinionated and thus a canonical choice for similar protocols. As a result, Bitcoin P2P traffic will be indistinguishable from traffic of other protocols which make the same choice (e.g., [https://gitlab.com/yawning/obfs4 obfs4] and a recently proposed [https://datatracker.ietf.org/doc/draft-cpbs-pseudorandom-ctls/ cTLS extension]). Moreover, traffic shapers and protocol wrappers (for example, making the traffic look like HTTPS or SSH) can further mitigate traffic analysis and active attacks but are out of scope for this proposal.
''' Why not use a secure tunnel protocol? '''
Our goal includes making opportunistic encryption ubiquitously available, as that provides the best defense against large-scale attacks. That implies protecting both the manual, deliberate connections node operators instruct their software to make, and the automatic connections Bitcoin nodes make with each other based on IP addresses obtained via gossip. While encryption per se is already possible with proxy networks or VPN protocols, these are not desirable or applicable for automatic connections at scale:
* Proxy networks like Tor or I2P introduce a separate address space, independent of network topology, with a very low cost per address making eclipse attacks cheaper. In comparison, clearnet IPv4 and IPv6 networks make obtaining multiple network identities in distinct, well-known network partitions carry a non-trivial cost. Thus, it is not desirable to have a substantial portion of nodes be exclusively connected this way, as this would significantly reduce Eclipse attack costs.'''Why is it a bad idea to have nodes exclusively connected over Tor?''' See the [https://arxiv.org/abs/1410.6079 Bitcoin over Tor isn't a Good Idea] paper Additionally, Tor connections come with significant bandwidth and latency costs that may not be desirable for all network users.
* VPN protocols like WireGuard or OpenVPN inherently define a private network, which requires manual configuration and therefore is not a realistic avenue for automatic connections.
Thus, to achieve our goal, we need a solution that has minimal costs, works without configuration, and is always enabled – on top of any network layer rather than be part of the network layer.
''' Why not use a general-purpose transport encryption protocol? '''
While it would be possible to rely on an off-the-shelf transport encryption protocol such as TLS or Noise, the specific requirements of the Bitcoin P2P network laid out above make these protocols an unsuitable choice.
The primary requirement which existing protocols fail to meet is a sufficiently modular treatment of encryption and authentication. As we argue above, whether and which form of authentication is desired in the Bitcoin P2P network will depend on the specific requirements of the involved peers (resulting in a mix of authenticated and unauthenticated connections), and thus the question of authentication should be decoupled from encryption. However, native support for a handful of standard authentication scenarios (e.g., using digital signatures and certificates) is at the core of the design of existing general-purpose transport encryption protocols. This focus on authentication would not provide clear benefits for the Bitcoin P2P network but would come with a large amount of additional complexity.
In contrast, our proposal instead aims for a simple modular design that makes it possible to address authentication separately. Our proposal provides a foundation for authentication by exporting a ''session ID'' that uniquely identifies the encrypted channel. After an encrypted channel has been established, the two endpoints are able to use any authentication protocol to confirm that they have the same session ID. (This is sometimes called ''channel binding'' because the session ID binds the encrypted channel to the authentication protocol.) Since in our proposal, any authentication needs to run after an encrypted connection has been established, the price we pay for this modularity is a possibly higher number of roundtrips as opposed to other protocols that perform authentication alongside the Diffie-Hellman key exchange.'''Do other protocols not support exporting a session ID?''' While [https://noiseprotocol.org/noise.html#channel-binding Noise] and [https://datatracker.ietf.org/doc/draft-ietf-kitten-tls-channel-bindings-for-tls13/ TLS (as a draft)] offer similar protocol extensions for exporting session IDs, using channel binding for authentication is not at the focus of their design and would not avoid the bulk of additional complexity due to the native support of authentication methods. However, the resulting increase in connection establishment latency is a not a concern for Bitcoin's long-lived connections, [https://www.dsn.kastel.kit.edu/bitcoin/ which typically live for hours or even weeks].
Besides this fundamentally different treatment of authentication, further technical issues arise when applying TLS or Noise to our desired use case:
* Neither offers a pseudorandom bytestream.
* Neither offers native support for elliptic curve cryptography on the curve secp256k1 as otherwise used in Bitcoin. While using secp256k1 is not strictly necessary, it is the obvious choice is for any new asymmetric cryptography in Bitcoin because it minimizes the cryptographic hardness assumptions as well as the dependencies that Bitcoin software will need.
* Neither offers shapability of the bytestream.
* Both provide a stream-based interface to the application layer, whereas Bitcoin requires a packet-based interface, resulting in the need for an additional thin layer to perform packet serialization and deserialization.
While existing protocols could be amended to address all of the aforementioned issues, this would negate the benefits of using them as off-the-shelf solution, e.g., the possibility to re-use existing implementations and security analyses.
== Goals ==
This proposal aims to achieve the following properties:
* Confidentiality against passive attacks: A passive attacker having recorded a v2 P2P bytestream (without timing and fragmentation information) must not be able to determine the plaintext being exchanged by the nodes.
* Observability of active attacks: A session ID identifying the encrypted channel uniquely is derived deterministically from a Diffie-Hellman negotiation. An active man-in-the-middle attacker is forced to incur a risk of being detected as peer operators can compare session IDs manually, or using optional authentication methods possibly introduced in future protocol versions.
* Pseudorandom bytestream: A passive attacker having recorded a v2 P2P bytestream (without timing information and fragmentation information) must not be able to distinguish it from a uniformly random bytestream.
* Shapable bytestream: It should be possible to shape the bytestream to increase resistance to traffic analysis (for example, to conceal block propagation), or censorship avoidance.'''How can shapability help circumvent fragmentation-pattern based censoring?''' See [https://gitlab.torproject.org/legacy/trac/-/issues/20348#note_2229522 this Tor issue] as an example.
* Forward secrecy: An eavesdropping attacker who compromises a peer's sessions secrets should not be able to decrypt past session traffic, except for the latest few packets.
* Upgradability: The proposal provides an upgrade path using transport versioning which can be used to add features like authentication, PQC handshake upgrade, etc. in the future.
* Compatibility: v2 clients will allow inbound v1 connections to minimize risk of network partitions.
* Low overhead: the introduction of a new P2P transport protocol should not substantially increase computational cost or bandwidth for nodes that implement it, compared to the current protocol.
== Specification ==
The specification consists of three parts:
* The '''Transport layer''' concerns how to set up an encrypted connection between two nodes, capable of transporting application-level messages between them.
* The '''Application layer''' concerns how to encode Bitcoin P2P messages and commands for transport by the Transport Layer.
* The '''Signaling''' concerns how v2 nodes advertise their support for the v2 protocol to potential peers.
=== Transport layer specification ===
In this section, we define the encryption protocol for messages between peers.
==== Overview and design ====
We first give an informal overview of the entire protocol flow and packet encryption.
'''Protocol flow overview'''
Given a newly established connection (typically TCP/IP) between two v2 P2P nodes, there are 3 phases the connection goes through. The first starts immediately, i.e. there are no v1 messages or any other bytes exchanged on the link beforehand. The two parties are called the '''initiator''' (who established the connection) and the '''responder''' (who accepted the connection).
# The '''Key exchange phase''', where nodes exchange data to establish shared secrets.
#* The initiator:
#** Generates a random ephemeral secp256k1 private key and sends a corresponding 64-byte ElligatorSwift'''What is ElligatorSwift and why use it?''' The [https://eprint.iacr.org/2022/759.pdf SwiftEC paper] describes a method called ElligatorSwift which allows encoding elliptic curve points in a way that is indistinguishable from a uniformly distributed bitstream. While a random 256-bit string has about 50% chance of being a valid X coordinate on the secp256k1 curve, every 512-bit string is a valid ElligatorSwift encoding of a curve point, making the encoded point indistinguishable from random when using an encoder that can sample uniformly.'''How fast is ElligatorSwift?''' Our benchmarks show that ElligatorSwift encoded ECDH is about 50% more expensive than unencoded ECDH. Given the fast performance of ECDH and the low frequency of new connections, we found the performance trade-off acceptable for the pseudorandom bytestream and future censorship resistance it can enable.-encoded public key to the responder.
#** May send up to 4095'''How was the limit of 4095 bytes garbage chosen?''' It is a balance between having sufficient freedom to hide information, and allowing it to be large enough so that the necessary 64 bytes of public key is small compared to it on the one hand, and bandwidth waste on the other hand. bytes of arbitrary data after their public key, called '''garbage''', providing a form of shapability and avoiding a recognizable pattern of exactly 64 bytes.'''Why does the affordance for garbage exist in the protocol?''' The garbage strings after the public keys are needed for shapability of the handshake. Neither peer can send decoy packets before having received at least the other peer's public key, i.e., neither peer can send more than 64 bytes before having received 64 bytes.
#* The responder:
#** Waits until one byte is received which does not match the 16 bytes consisting of the network magic followed by "version\x00\x00\x00\x00\x00". If the first 16 bytes do match, the connection is treated as using the v1 protocol instead.'''What if a v2 initiator's public key starts accidentally with these 16 bytes?''' This is so unlikely (probability of ''2-128'') to happen randomly in the v2 protocol that the initiator does not need to specifically avoid it. The optional detection of wrong-network v1 peers has a probability of ''2-96'', which is still negligible compared to random network failures.Bitcoin Core versions <=0.4.0 and >=22.0 ignore valid P2P messages that are received prior to a VERSION message. Bitcoin Core versions between 0.4.0 and 22.0 assign a misbehavior score to the peer upon receiving such messages. v2 clients implementing this proposal will interpret any message other than VERSION received as the first message to be the initiation of a v2 connection, and will result in disconnection for v1 initiators that send any message type other than VERSION as the first message. We are not aware of any implementations where this could pose a problem.
#** If the first 4 received bytes do not match the network magic, but the 12 bytes after that do match the version message encoding above, implementations may interpret this as a v1 peer of a different network, and disconnect them.
#** Similarly generates a random ephemeral private key and sends a corresponding 64-byte ElligatorSwift-encoded public key to the initiator.
#** Similarly may send up to 4095 bytes of garbage data after their public key.
#* Both parties:
#** Receive (the remainder of) the full 64-byte public key from the other side.
#** Use X-only'''Why use X-only ECDH?''' Using only the X coordinate provides the same security as using a full encoding of the secret curve point but allows for more efficient implementation by avoiding the need for square roots to compute Y coordinates. ECDH to compute a shared secret from their private key and the exchanged public keys'''Why is the shared secret computation a function of the exact 64-byte public encodings sent?''' This makes sure that an attacker cannot modify the public key encoding used without modifying the rest of the stream. If a third party wants the ability to modify stream bytes, they need to perform a full MitM attack on the connection., and deterministically derive from the secret 4 '''encryption keys''' (two in each direction: one for packet lengths, one for content encryption), a '''session id''', and two 16-byte '''garbage terminators''''''What length is sufficient for garbage terminators?''' The length of the garbage terminators determines the probability of accidental termination of a legitimate v2 connection due to garbage bytes (sent prior to ECDH) inadvertently including the terminator. 16 byte terminators with 4095 bytes of garbage yield a negligible probability of such collision which is likely orders of magnitude lower than random connection failure on the Internet.'''What does a garbage terminator in the wild look like?'''
[[File:bip-0324/garbage_terminator.png|none|256px|A garbage terminator model TX-v2 in the wild... sent by the responder]]
(one in each direction) using HKDF-SHA256.
#** Send their 16-byte garbage terminator.'''Why does the protocol need a garbage terminator?''' While it is in principle possible to use the first packet after the garbage directly as a terminator (scan until a valid packet follows), this would be significantly slower than just scanning for a fixed byte sequence, as it would require recomputing a Poly1305 tag after every received byte.
#** Receive up to 4111 bytes, stopping when encountering the garbage terminator.
#* At this point, both parties have the same keys, and all further communication proceeds in the form of '''encrypted packets'''.
#** Encrypted packets have an '''ignore bit''', which makes them '''decoy packets''' if set. Decoy packets are to be ignored by the receiver apart from verifying they decrypt correctly. Either peer may send such decoy packets at any point from here on. These form the primary shapability mechanism in the protocol. How and when to use them is out of scope for this document.
#** For each of the two directions, the first encrypted packet that will be sent in that direction (regardless of it being a decoy packet or not) will make use of the associated authenticated data (AAD) feature of the AEAD to authenticate the garbage that has been sent in that direction.'''Why does the protocol authenticate the garbage?''' Without garbage authentication, the garbage would be modifiable by a third party without consequences. We want to force any active attacker to have to maintain a full protocol state. In addition, such malleability without the consequence of connection termination could enable protocol fingerprinting.
# The '''Version negotiation phase''', where parties negotiate what transport version they will use, as well as data defined by that version.'''What features could be added in future protocol versions?''' Examples of features that could be added in future versions include post-quantum cryptography upgrades to the handshake, and optional authentication.
#* The responder:
#** Sends a '''version packet''' with empty content, to indicate support for the v2 P2P protocol proposed by this document. Any other value for content is reserved for future versions.
#* The initiator:
#** Receives a packet, ignores its contents. The idea is that features added by future versions get negotiated based on what is supported by both parties. Since there is just one version so far, the contents here can simply be ignored. But in the future, receiving a non-empty contents here may trigger other behavior; we defer specifying the encoding for such version content until there is a need for it.'''How will future versions encode version numbers in the version packet?''' Future versions could, for example, specify that the contents of the version packet is to be interpreted as an integer version number (with empty representing 0), and if the minimum of both numbers is N, that being interpreted as choosing a "v2.N" protocol version. Alternatively, certain bytes of the version packet contents could be interpreted as a bitvector of optional features.
#** Sends a '''version packet''' with empty content as well, to indicate support for the v2 P2P protocol.
#* The responder:
#** Receives a packet, ignores its contents.
# The '''Application phase''', where the packets exchanged have contents to be interpreted as application data.
#* Whenever either peer has a message to send, it sends a packet with that application message as '''contents'''.
To avoid the recognizable pattern of first messages being at least 64 bytes, a future backwards-compatible upgrade to this protocol may allow both peers to send their public key + garbage + garbage terminator in multiple rounds, slicing those bytes up into messages arbitrarily, as long as progress is guaranteed.'''How can progress be guaranteed in a backwards-compatible way?''' In order to guarantee progress, it must be ensured that no deadlock occurs, i.e., no state is reached in which each party waits for the other party indefinitely. For example, any upgrade that adheres to the following conditions will guarantee progress:
* The initiator must start by sending at least as many bytes as necessary to mismatch the magic/version 16 bytes prefix.
* The responder must start sending after having received at least one byte that mismatches that 16-byte prefix.
* As soon as either party has received the other peer's garbage terminator, or has received 4095 bytes of garbage, they must send their own garbage terminator. (When either of these conditions is met, the other party has nothing to respond with anymore that would be needed to guarantee progress otherwise.)
* Whenever either party receives any nonzero number of bytes, while not having sent their garbage terminator completely yet, they must send at least one byte in response without waiting for more bytes.
* After either party has sent their garbage terminator, they must transition to the version negotiation phase without waiting for more bytes.
Since the protocol as specified here adheres to these conditions, any upgrade which also adheres to these conditions will be backwards-compatible.
Note that the version negotiation phase does not need to wait for the key exchange phase to complete; version packets can be sent immediately after sending the garbage terminator. So the first two phases together, jointly called '''the handshake''', comprise just 1.5 roundtrips:
* the initiator sends public key + garbage
* the responder sends public key + garbage + garbage terminator + decoy packets (optional) + version packet
* the initiator sends garbage terminator + decoy packets (optional) + version packet
'''Packet encryption overview'''
All data on the wire after the garbage terminators takes the form of encrypted packets. Every packet encodes an encrypted variable-length byte array, called the '''contents''', as well as an '''ignore bit''' as mentioned before. The total size of a packet is 20 bytes plus the length of its contents.
Each packet consists of:
* A 3-byte encrypted '''length''' field, encoding the length of the '''contents''' (between ''0'' and ''224-1'''''Is ''224-1'' bytes sufficient as maximum content size?''' The current Bitcoin P2P protocol has no messages which support more than 4000000 bytes of application payload. By supporting up to ''224-1'' we can accommodate future evolutions needing more than 4 times that value. Hypothetical protocol changes that have even more data to exchange than that should probably use multiple separate messages anyway, because of the per-peer receive buffer sizes involved, and the inability to start processing a message before it is fully received. Of course, future versions of the transport protocol could change the size of the length field, if this were really needed., inclusive).
* An authenticated encryption of the '''plaintext''', which consists of:
** A 1-byte '''header''' which consists of transport layer protocol flags. Currently, only the highest bit is defined as the '''ignore bit'''. The other bits are ignored, but this may change in future versions'''Why is the header a part of the plaintext and not included alongside the length field?''' The packet length field is the minimum information that must be available before we can leverage the standard RFC8439 AEAD. Any other data, including metadata like the header being in the content encryption makes it easier to reason about the protocol security w.r.t. data being used before it is authenticated. If the ignore bit was not part of the content, another mechanism would be needed to authenticate it; for example, it could be fed as AAD to the AEAD cipher. We feel the complexity of such an approach outweighs the benefit of saving one byte per message..
** The variable-length '''contents'''.
The encryption of the plaintext uses '''[https://en.wikipedia.org/wiki/ChaCha20-Poly1305 ChaCha20Poly1305]''''''Why is ChaCha20Poly1305 chosen as the basis for packet encryption?''' It is a very widely used authenticated encryption cipher (used among others in SSH, TLS 1.2, TLS 1.3, [https://en.wikipedia.org/wiki/QUIC QUIC], Noise, and [https://www.wireguard.com/protocol/ WireGuard]; in the latter it is currently even the only supported cipher), with very good performance in general purpose software implementations. While AES-based ciphers (including the winners in the [https://competitions.cr.yp.to/caesar.html CAESAR] competition in non-lightweight categories) perform significantly better on systems with AES hardware acceleration, they are also significantly slower in pure software implementations. We choose to optimize for the weakest hardware., an [https://en.wikipedia.org/wiki/Authenticated_encryption authenticated encryption with associated data] (AEAD) cipher specified in [https://datatracker.ietf.org/doc/html/rfc8439 RFC 8439]. Every packet's plaintext is treated as a separate AEAD message, with a different nonce for each.
The length must be dealt with specially, as it is needed to determine packet boundaries before the whole packet is received and authenticated. As we want a stream that is pseudorandom to a passive attacker, it still needs encryption. We use unauthenticated'''Why is the length encryption not separately authenticated?''' Informally, the relevant security goal we aim for is to hide the number of packets and their lengths (i.e., the packet boundaries) against a passive attacker that receives the bytestream without timing or fragmentation information. (A formal definition can be found for example in [https://himsen.github.io/pdf/thesis.pdf Hansen 2016 (Definition 22)] under the name "boundary hiding against chosen-plaintext attacks (BH-CPA)".) However, we do not aim to hide packet boundaries against active attackers because active attackers can always exploit the fact that the Bitcoin P2P protocol is largely query-response based: they can trickle the bytes on the stream one-by-one unmodified and observe when a response comes (see [https://himsen.github.io/pdf/thesis.pdf Hansen 2016 (Section 3.9)] for a in-depth discussion). With that in mind, we accept that an active (non-MitM) attacker is able to figure out some information about packet boundaries by flipping certain bits in the unauthenticated length field, and observing the other side disconnecting immediately or later. Thus, we choose to use unauthenticated encryption for the length data, which is sufficient to achieve boundary hiding against passive attackers, and saves 16 bytes of bandwidth per packet. '''ChaCha20''' encryption for this, with an independent key. Note that the plaintext length is still implicitly authenticated by the encryption of the plaintext, but this can only be verified after receiving the whole packet. This design is inspired by that of the ChaCha20Poly1305 cipher suite in [http://bxr.su/OpenBSD/usr.bin/ssh/PROTOCOL.chacha20poly1305 OpenSSH].'''How does packet encryption differ from the OpenSSH design?''' The differences are:
* The length field is only 3 bytes instead of 4, as that is sufficient for our purposes.
* Length encryption keeps drawing pseudorandom bytes from the same ChaCha20 cipher for multiple packets, rather than incrementing the nonce for every packet.
* The Poly1305 authentication tag only covers the encrypted plaintext, and not the encrypted length field. This means that plaintext encryption uses the standard ChaCha20Poly1305 construction without any modifications, maximizing applicability of analysis and review of that cipher. The length encryption can be seen as a separate layer, using a separate key, and thus cannot affect any of the confidentiality or integrity guarantees of the plaintext encryption. On the other hand, this change w.r.t. OpenSSH also does not worsen any properties, as incorrect lengths will still trigger authentication failure for the overall packet (the plaintext length is implicitly authenticated by ChaCha20Poly1305).
* A hash step is performed every 224'''How was the rekeying interval 224 chosen?''' Assuming a node sends only ping messages every 20 minutes (the timeout interval for post-[https://github.com/bitcoin/bips/blob/master/bip-0031.mediawiki BIP31] connections) on a connection, the node will transmit 224 packets in about 3.11 days. This means ''soft rekeying'' after a fixed number of packets automatically translates to an upper-bound of time interval for rekeying, while being much simpler to coordinate than an actual time-based rekeying regime. At the same time, doing it once every 224 messages is sufficiently infrequent that it has only negligible impact on performance. Furthermore, 224 times 3 bytes (the number of bytes consumed by each length encryption) is 672, which is a multiple of 64 minus 32. This means that at the end of 224 length encryptions, exactly 32 bytes of keystream data remain that can be used as next key. messages to rekey the encryption ciphers, in order to provide forward security.
Because only fixed-length chunks (3-byte length fields) are encrypted, we do not need to treat all length chunks as separate messages. Instead, a single cipher (with the same nonce) is used for multiple consecutive length fields. This avoids wasting 61 pseudorandom bytes per packet, and makes the cost of having a separate cipher for length encryption negligible.'''Is it acceptable to use a less standard construction for length encryption?''' The fact that multiple (non-overlapping) bytes generated by a single ChaCha20 cipher are used for the encryption of multiple consecutive length fields is uncommon. We feel the performance cost gained by this deviation is worth it (especially for small packets, which are very common in Bitcoin's P2P protocol), given the low guarantees that are feasible for length encryption in the first place, and the result is still sufficient to provide pseudorandomness from the view of passive attackers. For plaintext encryption, we independently use a very standard construction, as the stakes for confidentiality and integrity there are much higher.
In order to provide forward security'''What value does forward security provide?''' Re-keying ensures [https://eprint.iacr.org/2001/035.pdf forward secrecy within a session], i.e., an attacker compromising the current session secrets cannot derive past encryption keys in the same session.'''Why have a cipher with forward secrecy but no periodical refresh of the ECDH key exchange?''' Our cipher ratchets encryption keys forward in order to protect messages encrypted under ''past'' encryption keys. In contrast, re-performing ECDH key exchange would protect messages encrypted under ''future'' encryption keys, i.e., it would re-establish security after the attacker had compromised one of the peers ''temporarily'' (e.g., the attacker obtains a memory dump). We do not believe protecting against that is a priority: an attacker that, for whatever reason, is capable of an attack that reveals encryption keys (or other session secrets) of a peer once is likely capable of performing the same attack again after peers have re-performed the ECDH key exchange. Thus, we do not believe the benefits of re-performing key exchange outweigh the additional complexity that comes with the necessary coordination between the peers. We note that the initiator could choose to close and re-open the entire connection to force a refresh of the ECDH key exchange, but that introduces other issues: a connection slot needs to be kept open at the responder side, it is not cryptographically guaranteed that really the same initiator will use it, and the observable TCP reset and handshake may create a detectable pattern., the encryption keys for both plaintext and length encryption are cycled every 224 messages, by switching to a new key that is generated by the key stream using the old key.
==== Handshake: key exchange and version negotiation ====
Next we specify the handshake of a connection in detail.
As explained before, these messages are sent to set up the connection:
===== Shared secret computation =====
The peers derive their shared secret through X-only ECDH, hashed together with the exactly 64-byte public keys' encodings sent over the wire.
def v2_ecdh(priv, ellswift_theirs, ellswift_ours, initiating):
ecdh_point_x32 = ellswift_ecdh_xonly(ellswift_theirs, priv)
if initiating:
# Initiating, place our public key encoding first.
return sha256_tagged("bip324_ellswift_xonly_ecdh", ellswift_ours + ellswift_theirs + ecdh_point_x32)
else:
# Responding, place their public key encoding first.
return sha256_tagged("bip324_ellswift_xonly_ecdh", ellswift_theirs + ellswift_ours + ecdh_point_x32)
Here, sha256_tagged(tag, x) returns a tagged hash value SHA256(SHA256(tag) || SHA256(tag) || x) as in [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#specification BIP340].
===== ElligatorSwift encoding of curve X coordinates =====
The functions ellswift_create and ellswift_ecdh_xonly encapsulate the construction of ElligatorSwift-encoded public keys, and the computation of X-only ECDH with
ElligatorSwift-encoded public keys.
First we define a constant:
* Let ''c = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852''.'''What is the ''c'' constant used in ''XSwiftEC''?''' The algorithm requires a constant ''√-3 (mod p)''; in other words, a number ''c'' such that ''-c2 mod p = 3''. There are two solutions to this equation, one which is itself a square modulo ''p'', and its negation. We choose the square one.
To define the needed functions, we first introduce a helper function, matching the XSwiftEC function from the [https://eprint.iacr.org/2022/759.pdf SwiftEC] paper, instantiated for the secp256k1 curve, with minor modifications. It maps pairs of integers ''(u, t)'' (both in range ''0..p-1'') to valid X coordinates on the curve. Note that the specification here does not attempt to be constant time, as it does not operate on secret data. In what follows, we use the notation from [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#specification BIP340].
* ''XSwiftEC(u, t)'':
** Alter the inputs to guarantee an X coordinate on the curve:'''Why do the inputs to the XSwiftEC algorithm need to be altered?''' This step deviates from the paper, which maps a negligibly small subset of inputs (around ''3/2256'') to the point at infinity. To avoid the need to deal with the case where a peer could craft encodings that intentionally trigger this edge case, we remap them to inputs that yield a valid X coordinate.
*** If ''u mod p = 0'', let ''u = 1'' instead.
*** If ''t mod p = 0'', let ''t = 1'' instead.
*** If ''(u3 + t2 + 7) mod p = 0'', let ''t = 2t (mod p)'' instead.
** Let ''X = (u3 + 7 - t2)/(2t) (mod p).'''''What does the division (/) sign in modular arithmetic refer to?''' Note that the division in these expressions corresponds to multiplication with the modular inverse modulo ''p'', i.e. ''a / b (mod p)'' with nonzero ''b'' is the unique solution ''x'' for which ''bx = a (mod p)''. It can be computed as ''abp-2 (mod p)'', but more efficient algorithms exist.
** Let ''Y = (X + t)/(cu) (mod p)''.
** For every ''x'' in ''{u + 4Y2, (-X/Y - u)/2, (X/Y - u)/2}'' (all ''mod p''; the order matters):
*** If ''lift_x(x)'' succeeds, return ''x''. There is at least one such ''x''.
To find encodings of a given X coordinate ''x'', we first need the inverse of ''XSwiftEC''. The function ''XSwiftECInv(x, u, case)'' either returns ''t'' such that ''XSwiftEC(u, t) = x'', or ''None''. The ''case'' variable is an integer in range ''0..7'', which selects which of the up to 8 valid such ''t'' values to return:
* ''XSwiftECInv(x, u, case)'':
** If ''case & 2 = 0'':
*** If ''lift_x(-x - u)'' succeeds, return ''None''.
*** Let ''v = x''.
*** Let ''s = -(u3 + 7)/(u2 + uv + v2) (mod p)''.
** Else (''case & 2 = 2''):
*** Let ''s = x - u (mod p)''.
*** If ''s = 0'', return ''None''.
*** Let ''r'' be the square root of ''-s(4(u3 + 7) + 3u2s) (mod p).'''''How to compute a square root mod ''p''?''' Due to the structure of ''p'', a candidate for the square root of ''a'' mod ''p'' can be computed as ''x = a(p+1)/4 mod p''. If ''a'' is not a square mod ''p'', this formula returns the square root of ''-a mod p'' instead, so it is necessary to verify that ''x2 mod p = a''. If that is the case ''-x mod p'' is a solution too, but we define "the" square root to be equal to that expression (the square root will therefore always be a square itself, as ''(p+1)/4'' is even). This algorithm is a specialization of the [https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm Tonelli-Shanks algorithm]. Return ''None'' if it does not exist.
*** If ''case & 1 = 1'' and ''r = 0'', return ''None''.
*** Let ''v = (r/s - u)/2''.
** Let ''w'' be the square root of ''s (mod p)''. Return ''None'' if it does not exist.
** If ''case & 5 = 0'', return ''-w(u(1 - c)/2 + v)''.
** If ''case & 5 = 1'', return ''w(u(1 + c)/2 + v)''.
** If ''case & 5 = 4'', return ''w(u(1 - c)/2 + v)''.
** If ''case & 5 = 5'', return ''-w(u(1 + c)/2 + v)''.
The overall ''XElligatorSwift'' algorithm, matching the name used in the paper, then uses this inverse to randomly'''''Can the ElligatorSwift encoding be used to construct public key encodings that satisfy a certain structure (and not pseudorandom)?''' The algorithm chooses the first 32 bytes (i.e., the value ''u'') and then computes a corresponding ''t'' such that the mapping to the curve point holds. In general, picking ''u'' from a uniformly random distribution provides pseudorandomness. But we can also fix any of the 32 bytes in ''u'', and the algorithm will still find a corresponding ''t''. The fact that it is possible to fix the first 32 bytes, combined with the garbage bytes in the handshake, provides a limited but very simple method of parroting other protocols such as [https://tls13.xargs.org/ TLS 1.3], which can be deployed by one of the peers without explicit support from the other peer. More general methods of parroting, e.g., introduced by defining new protocol or a protocol upgrade, are not precluded. sample encodings of ''x'':
* ''XElligatorSwift(x)'':
** Loop:
*** Let ''u'' be a random non-zero integer in range ''1..p-1'' inclusive.
*** Let ''case'' be a random integer in range ''0..7'' inclusive.
*** Compute ''t = XSwiftECInv(x, u, case)''.
*** If ''t'' is not ''None'', return ''(u, t)''. Otherwise, restart loop.
This is used to define the ellswift_create algorithm used in the previous section; it generates a random private key, along with a uniformly sampled 64-byte ElligatorSwift-encoded public key corresponding to it:
* ''ellswift_create()'':
** Generate a random private key ''priv'' in range ''1..p-1''.
** Let ''P = priv⋅G'', the corresponding public key point to ''priv''.
** Let ''(u, t) = XElligatorSwift(x(P))'', an encoding of ''x(P)''.
** ''ellswift_pub = bytes(u) || bytes(t)'', its encoding as 64 bytes.
** Return ''(priv, ellswift_pub)''.
Finally the ellswift_ecdh_xonly algorithm is:
* ''ellswift_ecdh_xonly(ellswift_theirs, priv)'':
** Let ''u = int(ellswift_theirs[:32]) mod p''.
** Let ''t = int(ellswift_theirs[32:]) mod p''.
** Return ''bytes(x(priv⋅lift_x(XSwiftEC(u, t))))''.'''Does it matter which point ''lift_x'' maps to?''' Either point is valid, as they are negations of each other, and negations do not affect the output X coordinate.
===== Keys and session ID derivation =====
The authenticated encryption construction proposed here requires two 32-byte keys per communication direction. These (in addition to a session ID) are computed using HKDF'''Why use HKDF for deriving key material?''' The shared secret already involves a hash function to make sure the public key encodings contribute to it, which negates some of the need for HKDF already. We still use it as it is the standard mechanism for deriving many keys from a single secret, and its computational cost is low enough to be negligible compared to the rest of a connection setup. as specified in [https://tools.ietf.org/html/rfc5869 RFC 5869] with SHA256 as the hash function:
def initialize_v2_transport(peer, ecdh_secret, initiating):
# Include NETWORK_MAGIC to ensure a connection between nodes on different networks will immediately fail
prk = HKDF_Extract(Hash=sha256, salt=b'bitcoin_v2_shared_secret' + NETWORK_MAGIC, ikm=ecdh_secret)
peer.session_id = HKDF_Expand(Hash=sha256, PRK=prk, info=b'session_id', L=32)
# Initialize the packet encryption ciphers.
initiator_L = HKDF_Expand(Hash=sha256, PRK=prk, info=b'initiator_L', L=32)
initiator_P = HKDF_Expand(Hash=sha256, PRK=prk, info=b'initiator_P', L=32)
responder_L = HKDF_Expand(Hash=sha256, PRK=prk, info=b'responder_L', L=32)
responder_P = HKDF_Expand(Hash=sha256, PRK=prk, info=b'responder_P', L=32)
garbage_terminators = HKDF_Expand(Hash=sha256, PRK=prk, info=b'garbage_terminators', L=32)
initiator_garbage_terminator = garbage_terminators[:16]
responder_garbage_terminator = garbage_terminators[16:]
if initiating:
peer.send_L = FSChaCha20(initiator_L)
peer.send_P = FSChaCha20Poly1305(initiator_P)
peer.send_garbage_terminator = initiator_garbage_terminator
peer.recv_L = FSChaCha20(responder_L)
peer.recv_P = FSChaCha20Poly1305(responder_P)
peer.recv_garbage_terminator = responder_garbage_terminator
else:
peer.send_L = FSChaCha20(responder_L)
peer.send_P = FSChaCha20Poly1305(responder_P)
peer.send_garbage_terminator = responder_garbage_terminator
peer.recv_L = FSChaCha20(initiator_L)
peer.recv_P = FSChaCha20Poly1305(initiator_P)
peer.recv_garbage_terminator = initiator_garbage_terminator
# To achieve forward secrecy we must wipe the key material used to initialize the ciphers:
memory_cleanse(ecdh_secret, prk, initiator_L, initiator_P, responder_L, responder_K)
The session ID uniquely identifies the encrypted channel. v2 clients supporting this proposal may present the entire session ID (encoded as a hex string) to the node operator to allow for manual, out of band comparison with the peer node operator. Future transport versions may introduce optional authentication methods that compare the session ID as seen by the two endpoints in order to bind the encrypted channel to the authentication.
===== Overall handshake pseudocode =====
To establish a v2 encrypted connection, the initiator generates an ephemeral secp256k1 keypair and sends an unencrypted ElligatorSwift encoding of the public key to the responding peer followed by unencrypted pseudorandom bytes initiator_garbage of length garbage_len < 4096.
The responder generates an ephemeral keypair for itself and derives the shared ECDH secret (using the first 64 received bytes) which enables it to instantiate the encrypted transport. It then sends 64 bytes of the unencrypted ElligatorSwift encoding of its own public key and its own responder_garbage also of length garbage_len < 4096. If the first 16 bytes received match the v1 prefix, the v1 protocol is used instead.
Upon receiving the encoded responder public key, the initiator derives the shared ECDH secret and instantiates the encrypted transport. It then sends the derived 16-byte initiator_garbage_terminator, optionally followed by an arbitrary number of decoy packets. Afterwards, it receives the responder's garbage (delimited by the garbage terminator). The responder performs very similar steps but includes the earlier received prefix bytes in the public key. Both the initiator and the responder set the AAD of the first encrypted packet they send after the garbage terminator (i.e., either an optional decoy packet or the version packet) to the garbage they have just sent, not including the garbage terminator.
def complete_handshake(peer, initiating, decoy_content_lengths=[]):
received_prefix = b'' if initiating else peer.received_prefix
ellswift_theirs = receive(peer, 64 - len(received_prefix))
if not initiating and ellswift_theirs[4:16] == V1_PREFIX[4:16]:
# Looks like a v1 peer from the wrong network.
disconnect(peer)
ecdh_secret = v2_ecdh(peer.privkey_ours, ellswift_theirs, peer.ellswift_ours,
initiating=initiating)
initialize_v2_transport(peer, ecdh_secret, initiating=True)
# Send garbage terminator
send(peer, peer.send_garbage_terminator)
# Optionally send decoy packets after garbage terminator.
aad = peer.sent_garbage
for decoy_content_len in decoy_content_lengths:
send(v2_enc_packet(peer, decoy_content_len * b'\x00', aad=aad))
aad = b''
# Send version packet.
send(v2_enc_packet(peer, TRANSPORT_VERSION, aad=aad))
# Skip garbage, until encountering garbage terminator.
received_garbage = recv(peer, 16)
for i in range(4096):
if received_garbage[-16:] == peer.recv_garbage_terminator:
# Receive, decode, and ignore version packet.
# This includes skipping decoys and authenticating the received garbage.
v2_receive_packet(peer, aad=received_garbage[:-16])
return
else:
received_garbage += recv(peer, 1)
# Garbage terminator was not seen after 4 KiB of garbage.
disconnect(peer)
==== Packet encryption ====
Lastly, we specify the packet encryption cipher in detail.
===== Existing cryptographic primitives =====
Packet encryption is built on two existing primitives:
* '''ChaCha20Poly1305''' is specified as AEAD_CHACHA20_POLY1305 in [https://datatracker.ietf.org/doc/html/rfc8439#section-2.8 RFC 8439 section 2.8]. It is an authenticated encryption protocol with associated data (AEAD), taking a 256-bit key, 96-bit nonce, and an arbitrary-length byte array of associated authenticated data (AAD). Due to the built-in authentication tag, ciphertexts are 16 bytes longer than the corresponding plaintext. In what follows:
** aead_chacha20_poly1305_encrypt(key, nonce, aad, plaintext) refers to a function that takes as input a 32-byte array ''key'', a 12-byte array ''nonce'', an arbitrary-length byte array ''aad'', and an arbitrary-length byte array ''plaintext'', and returns a byte array ''ciphertext'', 16 bytes longer than the plaintext.
** aead_chacha20_poly1305_decrypt(key, nonce, aad, ciphertext) refers to a function that takes as input a 32-byte array ''key'', a 12-byte array ''nonce'', an arbitrary-length byte array ''aad'', and an arbitrary-length byte array ''ciphertext'', and returns either a byte array ''plaintext'' (16 bytes shorter than the ciphertext), or ''None'' in case the ciphertext was not a valid ChaCha20Poly1305 encryption of any plaintext with the specified ''key'', ''nonce'', and ''aad''.
* The '''ChaCha20 Block Function''' is specified in [https://datatracker.ietf.org/doc/html/rfc8439#section-2.3 RFC 8439 section 2.3]. It is a pseudorandom function (PRF) taking a 256-bit key, 96-bit nonce, and 32-bit counter, and outputs 64 pseudorandom bytes. It is the underlying building block on which ChaCha20 (and ultimately, ChaCha20Poly1305) is built. In what follows:
** chacha20_block(key, nonce, count) refers to a function that takes as input a 32-byte array ''key'', a 12-byte array ''nonce'', and an integer ''count'' in range ''0..232-1'', and returns a byte array of length 64.
These will be used for plaintext encryption and length encryption, respectively.
===== Rekeying wrappers: FSChaCha20Poly1305 and FSChaCha20 =====
To provide re-keying every 224 packets, we specify two wrappers.
The first is '''FSChaCha20Poly1305''', which represents a ChaCha20Poly1305 AEAD, which automatically changes the nonce after every message, and rekeys every 224 messages by encrypting 32 zero bytes'''Why is rekeying implemented in terms of an invocation of the AEAD?''' This means the FSChaCha20Poly1305 wrapper can be thought of as a pure layer around the ChaCha20Poly1305 AEAD. Actual implementations can take advantage of the fact that this formulation is equivalent to using byte 64 through 95 of the keystream output of the underlying ChaCha20 cipher as new key, avoiding the need for Poly1305 in the process., and using the first 32 bytes of the result. Each message will be used for one packet. Note that in our protocol, any FSChaCha20Poly1305 instance is always either exclusively encryption or exclusively decryption, as separate instances are used for each direction of the protocol. The nonce used for a message is composed of the 32-bit little-endian encoding of the number of messages with the current key, followed by the 64-bit little-endian encoding of the number of rekeyings performed. For rekeying, the first 32-bit integer is set to ''0xffffffff''.
The second is '''FSChaCha20''', a (single) stream cipher which is used for the lengths of all packets. Encryption and decryption are identical here, so a single function crypt is exposed. It XORs the input with bytes generated using the ChaCha20 block function, rekeying every 224 chunks using the next 32 bytes of the block function output as new key. A ''chunk'' refers here to a single invocation of crypt. As explained before, the same cipher is used for 224 consecutive chunks, to avoid wasting cipher output. The nonce used for these batches of 224 chunks is composed of 4 zero bytes followed by the 64-bit little-endian encoding of the number of rekeyings performed. The block counter is reset to 0 after every rekeying.
class FSChaCha20:
"""Rekeying wrapper stream cipher around ChaCha20."""
def __init__(self, initial_key):
self.key = initial_key
self.block_counter = 0
self.chunk_counter = 0
self.keystream = b''
def get_keystream_bytes(self, nbytes):
while len(self.keystream) < nbytes:
nonce = ((0).to_bytes(4, 'little') +
(self.chunk_counter // REKEY_INTERVAL).to_bytes(8, 'little'))
self.keystream += chacha20_block(self.key, nonce, self.block_counter)
self.block_counter += 1
ret = self.keystream[:nbytes]
self.keystream = self.keystream[nbytes:]
return ret
def crypt(self, chunk):
ks = self.get_keystream_bytes(len(chunk))
ret = bytes([ks[i] ^ chunk[i] for i in range(len(chunk))])
if ((self.chunk_counter + 1) % REKEY_INTERVAL) == 0:
self.key = self.get_keystream_bytes(32)
self.block_counter = 0
self.chunk_counter += 1
return ret
===== Overall packet encryption and decryption pseudocode =====
Encryption and decryption of packets then follow by composing the ciphers from the previous section as building blocks.
CHACHA20POLY1305_EXPANSION = 16
def v2_receive_packet(peer, aad=b''):
while True:
enc_contents_len = receive(peer, LENGTH_FIELD_LEN)
contents_len = int.from_bytes(peer.recv_L.crypt(enc_contents_len), 'little')
aead_ciphertext = receive(peer, HEADER_LEN + contents_len + CHACHA20POLY1305_EXPANSION)
plaintext = peer.recv_P.decrypt(aad, aead_ciphertext)
if plaintext is None:
disconnect(peer)
break
# Only the first packet is expected to have non-empty AAD.
aad = b''
header = plaintext[:HEADER_LEN]
if not (header[0] & (1 << IGNORE_BIT_POS)):
return plaintext[HEADER_LEN:]
==== Performance ====
Each v1 P2P message uses a double-SHA256 checksum truncated to 4 bytes. Roughly the same amount of computation power is required for encrypting and authenticating a v2 P2P message as proposed.
=== Application layer specification ===
==== v2 Bitcoin P2P message structure ====
v2 Bitcoin P2P transport layer packets use the encrypted message structure shown above. An unencrypted application layer '''contents''' is composed of:
{|class="wikitable"
! Field !! Size in bytes !! Comments
|-
| message_type || 1 or 13 || either a one byte ID in range ''1..255'' or b'\x00' followed by a 12-byte ASCII message type (as in the v1 P2P protocol)
|-
| message_payload || message_length || message payload
|}
If the first byte of message_type is b'\x00', the following 12 bytes are interpreted as an ASCII message type (as in the v1 P2P protocol), trailing padded with b'\x00' as necessary. If the first byte of message_type is in the range ''1..255'', it is interpreted as a message type ID. This structure results in smaller messages than the v1 protocol, as most messages sent/received will have a message type ID. We recommend reserving 1-byte type IDs for message types that are sent more than once per direction per connection.'''How do the lengths between v1 and v2 compare?''' For messages that use the 1-byte short message type ID, v2 packets use 3 bytes less per message than v1.'''Why not allow variable length long message type IDs?''' Allowing for variable length long IDs reduces the available 1-byte ID space by 12 (to encode the length itself) and incentivizes less descriptive message types. In addition, limiting message types to fixed lengths of 1 or 13 hampers traffic analysis.
The value of message_length is '''length''' minus the size of the message_type.
The following table lists currently defined message type IDs and the 12-byte ASCII message type (trimmed of trailing padding) that they are treated as equivalent to:
{| class="wikitable"
|-
!
!0
!1
!2
!3
|-
!+0
|(12 bytes follow)||addr||block||blocktxn
|-
!+4
|cmpctblock||feefilter||filteradd||filterclear
|-
!+8
|filterload||getblocks||getblocktxn||getdata
|-
!+12
|getheaders||headers||inv||mempool
|-
!+16
|merkleblock||notfound||ping||pong
|-
!+20
|sendcmpct||tx||getcfilters||cfilter
|-
!+24
|getcfheaders||cfheaders||getcfcheckpt||cfcheckpt
|-
!+28
|addrv2
|-
!≥29
|| colspan="4" | (undefined)
|}
When a message type has both a 1-byte encoding and a 13-byte encoding defined, peers that support receiving that message type should accept messages using either encoding (e.g., if the "getblocktxn" message type is supported, then both the 1-byte b'\x0a' encoding and the 13-byte b'\x00getblocktxn\x00' should be supported, and behavior should not depend on which of the two encodings is received).
Additional message type IDs may be defined by other BIPs. They should be added to the [[bip-0324/message_type_ids.md|message type IDs table]] to ease coordination.
=== Signaling specification ===
==== Signaling v2 support ====
Peers supporting the v2 transport protocol signal support by advertising the NODE_P2P_V2 = (1 << 11) service flag in addr relay. If met with immediate disconnection when establishing a v2 connection, clients implementing this proposal are encouraged to retry connecting using the v1 protocol.'''Why are v2 clients met with immediate disconnection encouraged to retry with a v1 connection?''' Service flags propagated through untrusted intermediaries using ADDR and ADDRV2 P2P messages and are OR'ed when received from multiple sources. An untrusted intermediary could falsely advertise a potential peer as supportive of v2 connections. Connection downgrades to v1 mitigate the risk of a network participant being blackholed via false advertising.
== Test Vectors ==
For development and testing purposes, we provide a collection of test vectors in CSV format, and a naive, highly inefficient, [[bip-0324/reference.py|reference implementation]] of the relevant algorithms. This code is for demonstration purposes only:
* [[bip-0324/ellswift_decode_test_vectors.csv|XElligatorSwift decoding vectors]] provide examples of ElligatorSwift-encoded public keys, and the X coordinate they map to.
* [[bip-0324/xswiftec_inv_test_vectors.csv|XSwiftECInv vectors]] provide examples of ''(u, x)'' pairs, and the various ''t'' values that ''xswiftec_inv'' maps them to.
* [[bip-0324/packet_encoding_test_vectors.csv|Packet encoding vectors]] illustrate the lifecycle of the authenticated encryption scheme proposed in this document.
== Changelog ==
* 1.0.2 (2026-01-30)
* Add message type ID table in auxiliary file
* 1.0.1 (2026-01-16)
* Specify equivalence of 1-byte and 13-byte `message_type`
* 1.0.0 (2024-07-10)
* Marked as Final
== Rationale and References ==
== Acknowledgements ==
Thanks to everyone (last name order) that helped invent and develop the ideas in this proposal:
* Matt Corallo
* Lloyd Fournier
* Gregory Maxwell
* Anthony Towns
================================================
FILE: bip-0325.mediawiki
================================================
== Abstract ==
A new type of test network where signatures are used in addition to proof of work for block progress, enabling much better coordination and robustness (be reliably unreliable), for persistent, longer-term testing scenarios involving multiple independent parties.
== Motivation ==
Testnet is a great place to try out new things without risking real money, but it is notoriously unreliable. Huge block reorgs, long gaps in between blocks being mined or sudden bursts of blocks in rapid succession mean that realistic testing of software, especially involving multiple independent parties running software over an extended period of time, becomes infeasible in practice.
A new type of test network would be more suitable for integration testing by organizations such as exchanges, or testing of next generation Layer-2 protocols like Eltoo or sidechain pegs. The goal is not to be perfectly reliable but rather to have a predictable amount of unreliability. You want a test network to behave like mainnet (i.e. no thousands of block reorgs) while also making it easier to trigger expected but rare events like a 6-block reorg. Regtest is not suitable for longer-term scenarios involving multiple independent parties because creating blocks costs nothing, so any party can completely control the test network.
== Specification ==
A new type of network ("signet"), which takes an additional consensus parameter called the challenge (scriptPubKey). The challenge can be a simple pubkey (P2PKH style), or a k-of-n multisig, or any other script you would want.
Signet requires all blocks to have a BIP 141 commitment in the coinbase transaction. In order to provide a non-empty solution to the block challenge the block's BIP 141 commitment's optional data must include an additional commitment of the signature/solution for the block:
1-5 bytes - Push the following (4 + x + y) bytes
4 bytes - Signet header (0xecc7daa2)
x bytes - scriptSig
y bytes - scriptWitness
In the special case where an empty solution is valid (ie scriptSig and scriptWitness are both empty) this additional commitment can optionally be left out. This special case is to allow non-signet-aware block generation code to be used to test a custom signet chain where the challenge is trivially true.
The scriptSig is serialized by first encoding its length as CompactSize. The scriptWitness stack is serialized as described in BIP 141.
Any push operations that do not start with the 4 byte Signet header are ignored. Multiple push operations with the 4 byte Signet header are ignored except for the first instance of the header.
To sign the block or verify a block signature, two virtual transactions, each with a single input and output are constructed from the block as follows.
The "to_spend" transaction is:
nVersion = 0
nLockTime = 0
vin[0].prevout.hash = 0000...000
vin[0].prevout.n = 0xFFFFFFFF
vin[0].nSequence = 0
vin[0].scriptSig = OP_0 PUSH72[ block_data ]
vin[0].scriptWitness = []
vout[0].nValue = 0
vout[0].scriptPubKey = signet_challenge
where block_data is the serialization of the block's nVersion, hashPrevBlock, signet_merkle_root, and nTime. The signet_merkle_root is obtained by generating the merkle root of the block transactions, after modifying the coinbase witness commitment by replacing the signet solution with an empty solution (that is, the witness commitment includes a four byte push of the Signet header with no additional solution data, and no prior pushes beginning with the Signet header). This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed.
The "to_sign" transaction is:
nVersion = 0
nLockTime = 0
vin[0].prevout.hash = to_spend.txid
vin[0].prevout.n = 0
vin[0].nSequence = 0
vin[0].sigScript = [ signet_solution sigScript (x bytes), if any ]
vin[0].scriptWitness = [ signet_solution scriptWitness (y bytes), if any ]
vout[0].nValue = 0
vout[0].scriptPubKey = OP_RETURN
The scriptSig and/or scriptWitness for vin[0] are filled in from the Signet header push above.
To simplify block generation (mining), the signature also does not commit to the block nonce value, so that rolling the nonce to generate proof-of-work does not also require regenerating signatures. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
A block is considered fully validated only if the to_sign transaction is a valid spend of the to_spend transaction. It is recommended that this verification is done directly before or after the witness commitment verification, as the data required to do both is approximately the same.
There is one other acceptable special case: if a block's challenge is e.g. `OP_TRUE` (`0x51`), where an empty solution would result in success, the block is also considered valid if the signet commitment is absent.
=== Minimum Difficulty ===
The minimum difficulty for blocks in signet is approximately
0.0011265, corresponding to a maximum target of
00000377ae000000000000000000000000000000000000000000000000000000
which is represented by an nBits value of 0x1e0377ae.
This value is chosen so that multiplying the maximum target by maximum retarget timespan (8 weeks measured in seconds) does not overflow a uint256, making it easier to do difficulty adjustment calculations.
== Genesis Block and Message Start ==
The genesis block is the same for all signet networks, whereas the message start is defined as the first four bytes of the sha256d of the challenge script as a single data push (see below).
=== Genesis Block ===
* Time stamp: 1598918400
* Nonce: 52613770
* Difficulty: 0x1e0377ae
* Version: 1
The resulting genesis block hash is 00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6, and the block hex is 0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a008f4d5fae77031e8ad222030101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000.
=== Message Start ===
The message start is defined as the first four bytes of the sha256d of the challenge script, as a single push (i.e. prefixed with the challenge script length). Example:
* Challenge script = 512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be43051ae
* Sha256d(len || challenge script) = sha256d(25512103ad...51ae) = 7ec653a59b1912f9db10da2c461ed827d48f9404d5ef0346a6c94aadd4203646
* First four bytes = the message start = 7ec653a5
== Compatibility ==
This specification is backwards compatible in the sense that existing software can use Signet out of the box.
Simply by adding the network parameters for signet (magic number, etc), a client can connect to and use any signet network without further modifications. The block headers have valid proof of work, so clients can trivially check that blocks are "probably" valid.
However, anyone can mine blocks that are accepted by the client for any given signet network. These blocks do not contain the required signatures, however, so any fully validating node will promptly reject them. As such, clients need to either validate the block signature inside the coinbase transaction, or connect to trusted peers.
Other software need not add block signature validation code that they will not use in production. This is adequate for non-production test purposes where the goal is to have a network behave as much like mainnet as possible.
== Reference implementation ==
Pull request at https://github.com/bitcoin/bitcoin/pull/18267
== References ==
# Original mailing list thread: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-March/016734.html
# Bitcoin Wiki entry: https://en.bitcoin.it/wiki/Signet
== Copyright ==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
================================================
FILE: bip-0326.mediawiki
================================================
== Abstract ==
This document proposes a certain type of wallet behaviour which uses BIP341 taproot[1]. It provides a greater anonymity set for off-chain protocols which will make use of point-time-locked contracts (PTLCs) such as CoinSwap, Lightning and Discrete Log Contracts.
== Motivation ==
With taproot recently added to bitcoin, and wallet software about to implement taproot wallets, we are in a unique position to improve the privacy of off-chain protocols if we act soon.
Taproot allows for point-time-locked contracts (PTLCs) as a more private replacement for hash-time-locked contracts (HTLCs). If an off-chain contract (for example a Lightning channel) is closed using a PTLC instead of an HTLC, then the blockchain will just see a regular taproot script instead of a hash value and preimage. However, if a contract is closed using the timelock path, then the blockchain will either see a OP_CHECKSEQUENCEVERIFY opcode or a nSequence value in the transaction, neither of which are very common today, and this would mark the closing transaction as something special and unusual.
This BIP proposes to improve the privacy and fungibility of off-chain protocols by having on-chain wallets like Bitcoin Core also set the nSequence field in their taproot transactions as in BIP68[5]. This would be in place of their regular nLockTime anti-fee-sniping protection. The end result is that, if an observer of the blockchain sees a taproot spend with an nSequence value, then that could be either: a regular spend from a wallet, or an off-chain settlement transaction spent with a timelock. The two cases would be indistinguishable, and this could greatly improve the privacy and fungibility of bitcoin. The community and wallet developers should act now to implement this so that the anonymity set of nSequence transactions starts to be built up as soon as taproot itself becomes adopted by wallets.
== Background ==
=== Fee sniping ===
Fee sniping is a hypothetical outcome of bad incentives to bitcoin mining in the low-inflation future. For a large miner the value of the transactions in the best block and the mempool can be exceeded by the cost of deliberately attempting to mine two blocks to orphan the best block. However with anti-fee-sniping protection using nLockTime or nSequence the bad miner will soon run out of transactions that can be put in the first block, which means they now need to go in the second. Anti-fee-sniping adds to the incentive to move the blockchain forward.
The nLockTime field is being used this way today. It is implemented in Bitcoin Core[2] and Electrum[3], and adopted by approximately 20% of all recent transactions[4].
=== Absolute vs relative locktime ===
nLockTime is an absolute lock time, it allows the transaction to only be mined after a certain block height or unix time. The widespread adoption of it might have provided a good anonymity set for off-chain protocols. Unfortunately those protocols also commonly use relative lock times, because it allows contracts (for example Lightning payment channels or CoinSwaps) to remain open indefinitely as the countdown clock only starts ticking when the closing transaction is confirmed.
Absolute locktimes are also still used, so we should keep using nLockTime, but also often use nSequence.
=== Transaction pinning ===
Transaction pinning[8] is a method for making fee bumping prohibitively expensive by abusing node protections against attacks that can waste bandwidth, CPU, and memory. This can make fee management more difficult in multipart contract protocols (such as Lightning Network or CoinSwap). One possible way of solving the problem is to include a 1-block relative timelock `1 OP_CSV` to all spend paths, making it impossible to spend the unconfirmed UTXO. Such a 1-block locktime can also be created with an nSequence value of 1. Many on-chain transactions in bitcoin spend inputs that were created just one or two blocks ago, following this BIP such transactions with `nSequence=1` would also provide cover traffic for off-chain transactions which disable transaction pinning.
== Specifications ==
When wallets create transactions spending UTXOs protected by BIP341 taproot, they should set either an nLockTime value or nSequence values to discourage fee sniping, by allowing the transaction to only be mined in the next block after the tip, not the current block. This BIP suggests 50% probability for using nLockTime and 50% for nSequence. If nSequence is set it should apply to at least one of the inputs of the transaction, if it has multiple inputs. It is suggested that on-chain wallets pick an input randomly.
Wallets should also have a second random branch which sets the nLockTime or nSequence value even further back, so that transactions that are delayed after signing for whatever reason (e.g. high-latency mix networks) have better privacy. Existing behaviour is that with a probability of 10%, choose a random number between 0 and 99, and subtract it from the current block height. See the Bitcoin Core and Electrum source codes linked in the references for an example.
nSequence can only encode up to 65535 for the block distance[5] so if the UTXOs being spent have more than 65535 confirmations, then the wallet should use nLockTime instead.
=== Pseudocode ===
def apply_anti_fee_sniping_fields(transaction, rbf_set):
# bip68 requires v=2
transaction.version = 2
# Initialize all nsequence to indicate the requested RBF state
# nsequence can not be 2**32 - 1 in order for nlocktime to take effect
for input in transaction.inputs:
if rbf_set:
input.nsequence = 2**32 - 3
else:
input.nsequence = 2**32 - 2
# always set nlocktime if any of the transaction inputs have more
# confirmations than 65535 or are not taproot inputs, or have
# unconfirmed inputs
# otherwise choose either nlocktime or nsequence with 50% probability
if not rbf_set || any(map(lambda input: input.confirmations() > 65535
|| !input.is_taproot() || input.confirmations() == 0,
transaction.inputs)) || randint(2) == 0:
transaction.nlocktime = blockchain.height()
if randint(10) == 0:
transaction.nlocktime = max(0, transaction.nlocktime
- randint(0, 99))
# nsequence must be set in order for nlocktime to take effect
else:
transaction.nlocktime = 0
input_index = randint(len(transaction.inputs))
transaction.inputs[input_index].nsequence = transaction.inputs\
[input_index].confirmations()
if randint(10) == 0:
transaction.inputs[input_index].nsequence = max(1,
transaction.inputs[input_index].nsequence - randint(0, 99))
== Compatibility ==
This BIP doesn't need any consensus changes. It can be adopted unilaterally and gradually by wallets. Although for greater privacy it would be good for software to adopt it as soon as possible. Ideally during the process of developers implementing their taproot wallets, so that when taproot starts to be used it will already include the nSequence code.
All wallet software already keeps track of how many confirmations its UTXOs have, so the information required to set the nSequence field is already available.
== Acknowledgements ==
Originally suggested by David Harding[6] and mentioned to me by ZmnSCPxj.
Thanks to craigraw for suggesting a new value for input nsequence in the absolute locktime case[7].
== Copyright ==
This BIP is licensed under the Creative Commons CC0 1.0 Universal licence.
== References ==
[1] https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
[2] https://github.com/bitcoin/bitcoin/pull/2340
[3]
https://github.com/spesmilo/electrum/blob/7e6d65ec11c0dccfc24478471c5951d3ae586937/electrum/wallet.py#L211-L224
[4]
https://txstats.com/dashboard/db/blocks-statistics?panelId=4&fullscreen&orgId=1
[5] https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki
[6]
https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-January/002412.html
[7] https://github.com/sparrowwallet/sparrow/issues/161#issuecomment-925003231
[8] https://bitcoinops.org/en/topics/transaction-pinning/
================================================
FILE: bip-0327/gen_vectors_helper.py
================================================
from reference import *
def gen_key_agg_vectors():
print("key_agg_vectors.json: Intermediate tweaking result is point at infinity")
sk = bytes.fromhex("7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671")
pk = individual_pk(sk)
keygen_ctx = key_agg([pk])
aggpoint, _, _ = keygen_ctx
aggsk = key_agg_coeff([pk], pk)*int_from_bytes(sk) % n
t = n - aggsk
assert point_add(point_mul(G, t), aggpoint) == None
is_xonly = False
tweak = bytes_from_int(t)
assert_raises(ValueError, lambda: apply_tweak(keygen_ctx, tweak, is_xonly), lambda e: True)
print(" pubkey:", pk.hex().upper())
print(" tweak: ", tweak.hex().upper())
def check_sign_verify_vectors():
with open(os.path.join(sys.path[0], 'vectors', 'sign_verify_vectors.json')) as f:
test_data = json.load(f)
X = fromhex_all(test_data["pubkeys"])
pnonce = fromhex_all(test_data["pnonces"])
aggnonces = fromhex_all(test_data["aggnonces"])
msgs = fromhex_all(test_data["msgs"])
valid_test_cases = test_data["valid_test_cases"]
for (i, test_case) in enumerate(valid_test_cases):
pubkeys = [X[i] for i in test_case["key_indices"]]
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
aggnonce = aggnonces[test_case["aggnonce_index"]]
assert nonce_agg(pubnonces) == aggnonce
msg = msgs[test_case["msg_index"]]
signer_index = test_case["signer_index"]
expected = bytes.fromhex(test_case["expected"])
session_ctx = SessionContext(aggnonce, pubkeys, [], [], msg)
(Q, _, _, _, R, _) = get_session_values(session_ctx)
# Make sure the vectors include tests for both variants of Q and R
if i == 0:
assert has_even_y(Q) and not has_even_y(R)
if i == 1:
assert not has_even_y(Q) and has_even_y(R)
if i == 2:
assert has_even_y(Q) and has_even_y(R)
def check_tweak_vectors():
with open(os.path.join(sys.path[0], 'vectors', 'tweak_vectors.json')) as f:
test_data = json.load(f)
X = fromhex_all(test_data["pubkeys"])
pnonce = fromhex_all(test_data["pnonces"])
tweak = fromhex_all(test_data["tweaks"])
valid_test_cases = test_data["valid_test_cases"]
for (i, test_case) in enumerate(valid_test_cases):
pubkeys = [X[i] for i in test_case["key_indices"]]
tweaks = [tweak[i] for i in test_case["tweak_indices"]]
is_xonly = test_case["is_xonly"]
_, gacc, _ = key_agg_and_tweak(pubkeys, tweaks, is_xonly)
# Make sure the vectors include tests for gacc = 1 and -1
if i == 0:
assert gacc == n - 1
if i == 1:
assert gacc == 1
def sig_agg_vectors():
print("sig_agg_vectors.json:")
sk = fromhex_all([
"7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"3874D22DE7A7290C49CE7F1DC17D1A8CD8918E1F799055139D57FC0988D04D10",
"D0EA1B84481ED1BCFAA39D6775F97BDC9BF8D7C02FD0C009D6D85BAE5EC7B87A",
"FC2BF9E056B273AF0A8AABB815E541A3552C142AC10D4FE584F01D2CAB84F577"])
pubkeys = list(map(lambda secret: individual_pk(secret), sk))
indices32 = [i.to_bytes(32, 'big') for i in range(6)]
secnonces, pnonces = zip(*[nonce_gen_internal(r, None, pubkeys[0], None, None, None) for r in indices32])
tweaks = fromhex_all([
"B511DA492182A91B0FFB9A98020D55F260AE86D7ECBD0399C7383D59A5F2AF7C",
"A815FE049EE3C5AAB66310477FBC8BCCCAC2F3395F59F921C364ACD78A2F48DC",
"75448A87274B056468B977BE06EB1E9F657577B7320B0A3376EA51FD420D18A8"])
msg = bytes.fromhex("599C67EA410D005B9DA90817CF03ED3B1C868E4DA4EDF00A5880B0082C237869")
psigs = [None] * 9
valid_test_cases = [
{
"aggnonce": None,
"nonce_indices": [0, 1],
"key_indices": [0, 1],
"tweak_indices": [],
"is_xonly": [],
"psig_indices": [0, 1],
}, {
"aggnonce": None,
"nonce_indices": [0, 2],
"key_indices": [0, 2],
"tweak_indices": [],
"is_xonly": [],
"psig_indices": [2, 3],
}, {
"aggnonce": None,
"nonce_indices": [0, 3],
"key_indices": [0, 2],
"tweak_indices": [0],
"is_xonly": [False],
"psig_indices": [4, 5],
}, {
"aggnonce": None,
"nonce_indices": [0, 4],
"key_indices": [0, 3],
"tweak_indices": [0, 1, 2],
"is_xonly": [True, False, True],
"psig_indices": [6, 7],
},
]
for (i, test_case) in enumerate(valid_test_cases):
is_xonly = test_case["is_xonly"]
nonce_indices = test_case["nonce_indices"]
key_indices = test_case["key_indices"]
psig_indices = test_case["psig_indices"]
vec_pnonces = [pnonces[i] for i in nonce_indices]
vec_pubkeys = [pubkeys[i] for i in key_indices]
vec_tweaks = [tweaks[i] for i in test_case["tweak_indices"]]
aggnonce = nonce_agg(vec_pnonces)
test_case["aggnonce"] = aggnonce.hex().upper()
session_ctx = SessionContext(aggnonce, vec_pubkeys, vec_tweaks, is_xonly, msg)
for j in range(len(key_indices)):
# WARNING: An actual implementation should _not_ copy the secnonce.
# Reusing the secnonce, as we do here for testing purposes, can leak the
# secret key.
secnonce_tmp = bytearray(secnonces[nonce_indices[j]][:64] + pubkeys[key_indices[j]])
psigs[psig_indices[j]] = sign(secnonce_tmp, sk[key_indices[j]], session_ctx)
sig = partial_sig_agg([psigs[i] for i in psig_indices], session_ctx)
keygen_ctx = key_agg_and_tweak(vec_pubkeys, vec_tweaks, is_xonly)
# To maximize coverage of the sig_agg algorithm, we want one public key
# point with an even and one with an odd Y coordinate.
if i == 0:
assert(has_even_y(keygen_ctx[0]))
if i == 1:
assert(not has_even_y(keygen_ctx[0]))
aggpk = get_xonly_pk(keygen_ctx)
assert schnorr_verify(msg, aggpk, sig)
test_case["expected"] = sig.hex().upper()
error_test_case = {
"aggnonce": None,
"nonce_indices": [0, 4],
"key_indices": [0, 3],
"tweak_indices": [0, 1, 2],
"is_xonly": [True, False, True],
"psig_indices": [7, 8],
"error": {
"type": "invalid_contribution",
"signer": 1,
"contrib": "psig",
},
"comment": "Partial signature is invalid because it exceeds group size"
}
psigs[8] = bytes.fromhex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
vec_pnonces = [pnonces[i] for i in error_test_case["nonce_indices"]]
aggnonce = nonce_agg(vec_pnonces)
error_test_case["aggnonce"] = aggnonce.hex().upper()
def tohex_all(l):
return list(map(lambda e: e.hex().upper(), l))
print(json.dumps({
"pubkeys": tohex_all(pubkeys),
"pnonces": tohex_all(pnonces),
"tweaks": tohex_all(tweaks),
"psigs": tohex_all(psigs),
"msg": msg.hex().upper(),
"valid_test_cases": valid_test_cases,
"error_test_cases": [error_test_case]
}, indent=4))
gen_key_agg_vectors()
check_sign_verify_vectors()
check_tweak_vectors()
print()
sig_agg_vectors()
================================================
FILE: bip-0327/reference.py
================================================
# BIP327 reference implementation
#
# WARNING: This implementation is for demonstration purposes only and _not_ to
# be used in production environments. The code is vulnerable to timing attacks,
# for example.
from typing import List, Optional, Tuple, NewType, NamedTuple
import hashlib
import secrets
import time
#
# The following helper functions were copied from the BIP-340 reference implementation:
# https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py
#
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
# Points are tuples of X and Y coordinates and the point at infinity is
# represented by the None keyword.
G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
Point = Tuple[int, int]
# This implementation can be sped up by storing the midstate after hashing
# tag_hash instead of rehashing it all the time.
def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
def is_infinite(P: Optional[Point]) -> bool:
return P is None
def x(P: Point) -> int:
assert not is_infinite(P)
return P[0]
def y(P: Point) -> int:
assert not is_infinite(P)
return P[1]
def point_add(P1: Optional[Point], P2: Optional[Point]) -> Optional[Point]:
if P1 is None:
return P2
if P2 is None:
return P1
if (x(P1) == x(P2)) and (y(P1) != y(P2)):
return None
if P1 == P2:
lam = (3 * x(P1) * x(P1) * pow(2 * y(P1), p - 2, p)) % p
else:
lam = ((y(P2) - y(P1)) * pow(x(P2) - x(P1), p - 2, p)) % p
x3 = (lam * lam - x(P1) - x(P2)) % p
return (x3, (lam * (x(P1) - x3) - y(P1)) % p)
def point_mul(P: Optional[Point], n: int) -> Optional[Point]:
R = None
for i in range(256):
if (n >> i) & 1:
R = point_add(R, P)
P = point_add(P, P)
return R
def bytes_from_int(x: int) -> bytes:
return x.to_bytes(32, byteorder="big")
def lift_x(b: bytes) -> Optional[Point]:
x = int_from_bytes(b)
if x >= p:
return None
y_sq = (pow(x, 3, p) + 7) % p
y = pow(y_sq, (p + 1) // 4, p)
if pow(y, 2, p) != y_sq:
return None
return (x, y if y & 1 == 0 else p-y)
def int_from_bytes(b: bytes) -> int:
return int.from_bytes(b, byteorder="big")
def has_even_y(P: Point) -> bool:
assert not is_infinite(P)
return y(P) % 2 == 0
def schnorr_verify(msg: bytes, pubkey: bytes, sig: bytes) -> bool:
if len(msg) != 32:
raise ValueError('The message must be a 32-byte array.')
if len(pubkey) != 32:
raise ValueError('The public key must be a 32-byte array.')
if len(sig) != 64:
raise ValueError('The signature must be a 64-byte array.')
P = lift_x(pubkey)
r = int_from_bytes(sig[0:32])
s = int_from_bytes(sig[32:64])
if (P is None) or (r >= p) or (s >= n):
return False
e = int_from_bytes(tagged_hash("BIP0340/challenge", sig[0:32] + pubkey + msg)) % n
R = point_add(point_mul(G, s), point_mul(P, n - e))
if (R is None) or (not has_even_y(R)) or (x(R) != r):
return False
return True
#
# End of helper functions copied from BIP-340 reference implementation.
#
PlainPk = NewType('PlainPk', bytes)
XonlyPk = NewType('XonlyPk', bytes)
# There are two types of exceptions that can be raised by this implementation:
# - ValueError for indicating that an input doesn't conform to some function
# precondition (e.g. an input array is the wrong length, a serialized
# representation doesn't have the correct format).
# - InvalidContributionError for indicating that a signer (or the
# aggregator) is misbehaving in the protocol.
#
# Assertions are used to (1) satisfy the type-checking system, and (2) check for
# inconvenient events that can't happen except with negligible probability (e.g.
# output of a hash function is 0) and can't be manually triggered by any
# signer.
# This exception is raised if a party (signer or nonce aggregator) sends invalid
# values. Actual implementations should not crash when receiving invalid
# contributions. Instead, they should hold the offending party accountable.
class InvalidContributionError(Exception):
def __init__(self, signer, contrib):
self.signer = signer
# contrib is one of "pubkey", "pubnonce", "aggnonce", or "psig".
self.contrib = contrib
infinity = None
def xbytes(P: Point) -> bytes:
return bytes_from_int(x(P))
def cbytes(P: Point) -> bytes:
a = b'\x02' if has_even_y(P) else b'\x03'
return a + xbytes(P)
def cbytes_ext(P: Optional[Point]) -> bytes:
if is_infinite(P):
return (0).to_bytes(33, byteorder='big')
assert P is not None
return cbytes(P)
def point_negate(P: Optional[Point]) -> Optional[Point]:
if P is None:
return P
return (x(P), p - y(P))
def cpoint(x: bytes) -> Point:
if len(x) != 33:
raise ValueError('x is not a valid compressed point.')
P = lift_x(x[1:33])
if P is None:
raise ValueError('x is not a valid compressed point.')
if x[0] == 2:
return P
elif x[0] == 3:
P = point_negate(P)
assert P is not None
return P
else:
raise ValueError('x is not a valid compressed point.')
def cpoint_ext(x: bytes) -> Optional[Point]:
if x == (0).to_bytes(33, 'big'):
return None
else:
return cpoint(x)
# Return the plain public key corresponding to a given secret key
def individual_pk(seckey: bytes) -> PlainPk:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= n - 1):
raise ValueError('The secret key must be an integer in the range 1..n-1.')
P = point_mul(G, d0)
assert P is not None
return PlainPk(cbytes(P))
def key_sort(pubkeys: List[PlainPk]) -> List[PlainPk]:
pubkeys.sort()
return pubkeys
KeyAggContext = NamedTuple('KeyAggContext', [('Q', Point),
('gacc', int),
('tacc', int)])
def get_xonly_pk(keyagg_ctx: KeyAggContext) -> XonlyPk:
Q, _, _ = keyagg_ctx
return XonlyPk(xbytes(Q))
def key_agg(pubkeys: List[PlainPk]) -> KeyAggContext:
pk2 = get_second_key(pubkeys)
u = len(pubkeys)
Q = infinity
for i in range(u):
try:
P_i = cpoint(pubkeys[i])
except ValueError:
raise InvalidContributionError(i, "pubkey")
a_i = key_agg_coeff_internal(pubkeys, pubkeys[i], pk2)
Q = point_add(Q, point_mul(P_i, a_i))
# Q is not the point at infinity except with negligible probability.
assert(Q is not None)
gacc = 1
tacc = 0
return KeyAggContext(Q, gacc, tacc)
def hash_keys(pubkeys: List[PlainPk]) -> bytes:
return tagged_hash('KeyAgg list', b''.join(pubkeys))
def get_second_key(pubkeys: List[PlainPk]) -> PlainPk:
u = len(pubkeys)
for j in range(1, u):
if pubkeys[j] != pubkeys[0]:
return pubkeys[j]
return PlainPk(b'\x00'*33)
def key_agg_coeff(pubkeys: List[PlainPk], pk_: PlainPk) -> int:
pk2 = get_second_key(pubkeys)
return key_agg_coeff_internal(pubkeys, pk_, pk2)
def key_agg_coeff_internal(pubkeys: List[PlainPk], pk_: PlainPk, pk2: PlainPk) -> int:
L = hash_keys(pubkeys)
if pk_ == pk2:
return 1
return int_from_bytes(tagged_hash('KeyAgg coefficient', L + pk_)) % n
def apply_tweak(keyagg_ctx: KeyAggContext, tweak: bytes, is_xonly: bool) -> KeyAggContext:
if len(tweak) != 32:
raise ValueError('The tweak must be a 32-byte array.')
Q, gacc, tacc = keyagg_ctx
if is_xonly and not has_even_y(Q):
g = n - 1
else:
g = 1
t = int_from_bytes(tweak)
if t >= n:
raise ValueError('The tweak must be less than n.')
Q_ = point_add(point_mul(Q, g), point_mul(G, t))
if Q_ is None:
raise ValueError('The result of tweaking cannot be infinity.')
gacc_ = g * gacc % n
tacc_ = (t + g * tacc) % n
return KeyAggContext(Q_, gacc_, tacc_)
def bytes_xor(a: bytes, b: bytes) -> bytes:
return bytes(x ^ y for x, y in zip(a, b))
def nonce_hash(rand: bytes, pk: PlainPk, aggpk: XonlyPk, i: int, msg_prefixed: bytes, extra_in: bytes) -> int:
buf = b''
buf += rand
buf += len(pk).to_bytes(1, 'big')
buf += pk
buf += len(aggpk).to_bytes(1, 'big')
buf += aggpk
buf += msg_prefixed
buf += len(extra_in).to_bytes(4, 'big')
buf += extra_in
buf += i.to_bytes(1, 'big')
return int_from_bytes(tagged_hash('MuSig/nonce', buf))
def nonce_gen_internal(rand_: bytes, sk: Optional[bytes], pk: PlainPk, aggpk: Optional[XonlyPk], msg: Optional[bytes], extra_in: Optional[bytes]) -> Tuple[bytearray, bytes]:
if sk is not None:
rand = bytes_xor(sk, tagged_hash('MuSig/aux', rand_))
else:
rand = rand_
if aggpk is None:
aggpk = XonlyPk(b'')
if msg is None:
msg_prefixed = b'\x00'
else:
msg_prefixed = b'\x01'
msg_prefixed += len(msg).to_bytes(8, 'big')
msg_prefixed += msg
if extra_in is None:
extra_in = b''
k_1 = nonce_hash(rand, pk, aggpk, 0, msg_prefixed, extra_in) % n
k_2 = nonce_hash(rand, pk, aggpk, 1, msg_prefixed, extra_in) % n
# k_1 == 0 or k_2 == 0 cannot occur except with negligible probability.
assert k_1 != 0
assert k_2 != 0
R_s1 = point_mul(G, k_1)
R_s2 = point_mul(G, k_2)
assert R_s1 is not None
assert R_s2 is not None
pubnonce = cbytes(R_s1) + cbytes(R_s2)
secnonce = bytearray(bytes_from_int(k_1) + bytes_from_int(k_2) + pk)
return secnonce, pubnonce
def nonce_gen(sk: Optional[bytes], pk: PlainPk, aggpk: Optional[XonlyPk], msg: Optional[bytes], extra_in: Optional[bytes]) -> Tuple[bytearray, bytes]:
if sk is not None and len(sk) != 32:
raise ValueError('The optional byte array sk must have length 32.')
if aggpk is not None and len(aggpk) != 32:
raise ValueError('The optional byte array aggpk must have length 32.')
rand_ = secrets.token_bytes(32)
return nonce_gen_internal(rand_, sk, pk, aggpk, msg, extra_in)
def nonce_agg(pubnonces: List[bytes]) -> bytes:
u = len(pubnonces)
aggnonce = b''
for j in (1, 2):
R_j = infinity
for i in range(u):
try:
R_ij = cpoint(pubnonces[i][(j-1)*33:j*33])
except ValueError:
raise InvalidContributionError(i, "pubnonce")
R_j = point_add(R_j, R_ij)
aggnonce += cbytes_ext(R_j)
return aggnonce
SessionContext = NamedTuple('SessionContext', [('aggnonce', bytes),
('pubkeys', List[PlainPk]),
('tweaks', List[bytes]),
('is_xonly', List[bool]),
('msg', bytes)])
def key_agg_and_tweak(pubkeys: List[PlainPk], tweaks: List[bytes], is_xonly: List[bool]) -> KeyAggContext:
if len(tweaks) != len(is_xonly):
raise ValueError('The `tweaks` and `is_xonly` arrays must have the same length.')
keyagg_ctx = key_agg(pubkeys)
v = len(tweaks)
for i in range(v):
keyagg_ctx = apply_tweak(keyagg_ctx, tweaks[i], is_xonly[i])
return keyagg_ctx
def get_session_values(session_ctx: SessionContext) -> Tuple[Point, int, int, int, Point, int]:
(aggnonce, pubkeys, tweaks, is_xonly, msg) = session_ctx
Q, gacc, tacc = key_agg_and_tweak(pubkeys, tweaks, is_xonly)
b = int_from_bytes(tagged_hash('MuSig/noncecoef', aggnonce + xbytes(Q) + msg)) % n
try:
R_1 = cpoint_ext(aggnonce[0:33])
R_2 = cpoint_ext(aggnonce[33:66])
except ValueError:
# Nonce aggregator sent invalid nonces
raise InvalidContributionError(None, "aggnonce")
R_ = point_add(R_1, point_mul(R_2, b))
R = R_ if not is_infinite(R_) else G
assert R is not None
e = int_from_bytes(tagged_hash('BIP0340/challenge', xbytes(R) + xbytes(Q) + msg)) % n
return (Q, gacc, tacc, b, R, e)
def get_session_key_agg_coeff(session_ctx: SessionContext, P: Point) -> int:
(_, pubkeys, _, _, _) = session_ctx
pk = PlainPk(cbytes(P))
if pk not in pubkeys:
raise ValueError('The signer\'s pubkey must be included in the list of pubkeys.')
return key_agg_coeff(pubkeys, pk)
def sign(secnonce: bytearray, sk: bytes, session_ctx: SessionContext) -> bytes:
(Q, gacc, _, b, R, e) = get_session_values(session_ctx)
k_1_ = int_from_bytes(secnonce[0:32])
k_2_ = int_from_bytes(secnonce[32:64])
# Overwrite the secnonce argument with zeros such that subsequent calls of
# sign with the same secnonce raise a ValueError.
secnonce[:64] = bytearray(b'\x00'*64)
if not 0 < k_1_ < n:
raise ValueError('first secnonce value is out of range.')
if not 0 < k_2_ < n:
raise ValueError('second secnonce value is out of range.')
k_1 = k_1_ if has_even_y(R) else n - k_1_
k_2 = k_2_ if has_even_y(R) else n - k_2_
d_ = int_from_bytes(sk)
if not 0 < d_ < n:
raise ValueError('secret key value is out of range.')
P = point_mul(G, d_)
assert P is not None
pk = cbytes(P)
if not pk == secnonce[64:97]:
raise ValueError('Public key does not match nonce_gen argument')
a = get_session_key_agg_coeff(session_ctx, P)
g = 1 if has_even_y(Q) else n - 1
d = g * gacc * d_ % n
s = (k_1 + b * k_2 + e * a * d) % n
psig = bytes_from_int(s)
R_s1 = point_mul(G, k_1_)
R_s2 = point_mul(G, k_2_)
assert R_s1 is not None
assert R_s2 is not None
pubnonce = cbytes(R_s1) + cbytes(R_s2)
# Optional correctness check. The result of signing should pass signature verification.
assert partial_sig_verify_internal(psig, pubnonce, pk, session_ctx)
return psig
def det_nonce_hash(sk_: bytes, aggothernonce: bytes, aggpk: bytes, msg: bytes, i: int) -> int:
buf = b''
buf += sk_
buf += aggothernonce
buf += aggpk
buf += len(msg).to_bytes(8, 'big')
buf += msg
buf += i.to_bytes(1, 'big')
return int_from_bytes(tagged_hash('MuSig/deterministic/nonce', buf))
def deterministic_sign(sk: bytes, aggothernonce: bytes, pubkeys: List[PlainPk], tweaks: List[bytes], is_xonly: List[bool], msg: bytes, rand: Optional[bytes]) -> Tuple[bytes, bytes]:
if rand is not None:
sk_ = bytes_xor(sk, tagged_hash('MuSig/aux', rand))
else:
sk_ = sk
aggpk = get_xonly_pk(key_agg_and_tweak(pubkeys, tweaks, is_xonly))
k_1 = det_nonce_hash(sk_, aggothernonce, aggpk, msg, 0) % n
k_2 = det_nonce_hash(sk_, aggothernonce, aggpk, msg, 1) % n
# k_1 == 0 or k_2 == 0 cannot occur except with negligible probability.
assert k_1 != 0
assert k_2 != 0
R_s1 = point_mul(G, k_1)
R_s2 = point_mul(G, k_2)
assert R_s1 is not None
assert R_s2 is not None
pubnonce = cbytes(R_s1) + cbytes(R_s2)
secnonce = bytearray(bytes_from_int(k_1) + bytes_from_int(k_2) + individual_pk(sk))
try:
aggnonce = nonce_agg([pubnonce, aggothernonce])
except Exception:
raise InvalidContributionError(None, "aggothernonce")
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
psig = sign(secnonce, sk, session_ctx)
return (pubnonce, psig)
def partial_sig_verify(psig: bytes, pubnonces: List[bytes], pubkeys: List[PlainPk], tweaks: List[bytes], is_xonly: List[bool], msg: bytes, i: int) -> bool:
if len(pubnonces) != len(pubkeys):
raise ValueError('The `pubnonces` and `pubkeys` arrays must have the same length.')
if len(tweaks) != len(is_xonly):
raise ValueError('The `tweaks` and `is_xonly` arrays must have the same length.')
aggnonce = nonce_agg(pubnonces)
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
return partial_sig_verify_internal(psig, pubnonces[i], pubkeys[i], session_ctx)
def partial_sig_verify_internal(psig: bytes, pubnonce: bytes, pk: bytes, session_ctx: SessionContext) -> bool:
(Q, gacc, _, b, R, e) = get_session_values(session_ctx)
s = int_from_bytes(psig)
if s >= n:
return False
R_s1 = cpoint(pubnonce[0:33])
R_s2 = cpoint(pubnonce[33:66])
Re_s_ = point_add(R_s1, point_mul(R_s2, b))
Re_s = Re_s_ if has_even_y(R) else point_negate(Re_s_)
P = cpoint(pk)
a = get_session_key_agg_coeff(session_ctx, P)
g = 1 if has_even_y(Q) else n - 1
g_ = g * gacc % n
return point_mul(G, s) == point_add(Re_s, point_mul(P, e * a * g_ % n))
def partial_sig_agg(psigs: List[bytes], session_ctx: SessionContext) -> bytes:
(Q, _, tacc, _, R, e) = get_session_values(session_ctx)
s = 0
u = len(psigs)
for i in range(u):
s_i = int_from_bytes(psigs[i])
if s_i >= n:
raise InvalidContributionError(i, "psig")
s = (s + s_i) % n
g = 1 if has_even_y(Q) else n - 1
s = (s + e * g * tacc) % n
return xbytes(R) + bytes_from_int(s)
#
# The following code is only used for testing.
#
import json
import os
import sys
def fromhex_all(l):
return [bytes.fromhex(l_i) for l_i in l]
# Check if calling `try_fn` raises an exception. If yes, examine it with `except_fn`.
def assert_raises(exception, try_fn, except_fn):
raised = False
try:
try_fn()
except exception as e:
raised = True
assert(except_fn(e))
except BaseException:
raise AssertionError("Wrong exception raised in a test.")
if not raised:
raise AssertionError("Exception was _not_ raised in a test where it was required.")
def get_error_details(test_case):
error = test_case["error"]
if error["type"] == "invalid_contribution":
exception = InvalidContributionError
if "contrib" in error:
except_fn = lambda e: e.signer == error["signer"] and e.contrib == error["contrib"]
else:
except_fn = lambda e: e.signer == error["signer"]
elif error["type"] == "value":
exception = ValueError
except_fn = lambda e: str(e) == error["message"]
else:
raise RuntimeError(f"Invalid error type: {error['type']}")
return exception, except_fn
def test_key_sort_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'key_sort_vectors.json')) as f:
test_data = json.load(f)
X = fromhex_all(test_data["pubkeys"])
X_sorted = fromhex_all(test_data["sorted_pubkeys"])
assert key_sort(X) == X_sorted
def test_key_agg_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'key_agg_vectors.json')) as f:
test_data = json.load(f)
X = fromhex_all(test_data["pubkeys"])
T = fromhex_all(test_data["tweaks"])
valid_test_cases = test_data["valid_test_cases"]
error_test_cases = test_data["error_test_cases"]
for test_case in valid_test_cases:
pubkeys = [X[i] for i in test_case["key_indices"]]
expected = bytes.fromhex(test_case["expected"])
assert get_xonly_pk(key_agg(pubkeys)) == expected
for test_case in error_test_cases:
exception, except_fn = get_error_details(test_case)
pubkeys = [X[i] for i in test_case["key_indices"]]
tweaks = [T[i] for i in test_case["tweak_indices"]]
is_xonly = test_case["is_xonly"]
assert_raises(exception, lambda: key_agg_and_tweak(pubkeys, tweaks, is_xonly), except_fn)
def test_nonce_gen_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'nonce_gen_vectors.json')) as f:
test_data = json.load(f)
for test_case in test_data["test_cases"]:
def get_value(key) -> bytes:
return bytes.fromhex(test_case[key])
def get_value_maybe(key) -> Optional[bytes]:
if test_case[key] is not None:
return get_value(key)
else:
return None
rand_ = get_value("rand_")
sk = get_value_maybe("sk")
pk = PlainPk(get_value("pk"))
aggpk = get_value_maybe("aggpk")
if aggpk is not None:
aggpk = XonlyPk(aggpk)
msg = get_value_maybe("msg")
extra_in = get_value_maybe("extra_in")
expected_secnonce = get_value("expected_secnonce")
expected_pubnonce = get_value("expected_pubnonce")
assert nonce_gen_internal(rand_, sk, pk, aggpk, msg, extra_in) == (expected_secnonce, expected_pubnonce)
def test_nonce_agg_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'nonce_agg_vectors.json')) as f:
test_data = json.load(f)
pnonce = fromhex_all(test_data["pnonces"])
valid_test_cases = test_data["valid_test_cases"]
error_test_cases = test_data["error_test_cases"]
for test_case in valid_test_cases:
pubnonces = [pnonce[i] for i in test_case["pnonce_indices"]]
expected = bytes.fromhex(test_case["expected"])
assert nonce_agg(pubnonces) == expected
for test_case in error_test_cases:
exception, except_fn = get_error_details(test_case)
pubnonces = [pnonce[i] for i in test_case["pnonce_indices"]]
assert_raises(exception, lambda: nonce_agg(pubnonces), except_fn)
def test_sign_verify_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'sign_verify_vectors.json')) as f:
test_data = json.load(f)
sk = bytes.fromhex(test_data["sk"])
X = fromhex_all(test_data["pubkeys"])
# The public key corresponding to sk is at index 0
assert X[0] == individual_pk(sk)
secnonces = fromhex_all(test_data["secnonces"])
pnonce = fromhex_all(test_data["pnonces"])
# The public nonce corresponding to secnonces[0] is at index 0
k_1 = int_from_bytes(secnonces[0][0:32])
k_2 = int_from_bytes(secnonces[0][32:64])
R_s1 = point_mul(G, k_1)
R_s2 = point_mul(G, k_2)
assert R_s1 is not None and R_s2 is not None
assert pnonce[0] == cbytes(R_s1) + cbytes(R_s2)
aggnonces = fromhex_all(test_data["aggnonces"])
# The aggregate of the first three elements of pnonce is at index 0
assert (aggnonces[0] == nonce_agg([pnonce[0], pnonce[1], pnonce[2]]))
# The aggregate of the first and fourth elements of pnonce is at index 1,
# which is the infinity point encoded as a zeroed 33-byte array
assert (aggnonces[1] == nonce_agg([pnonce[0], pnonce[3]]))
msgs = fromhex_all(test_data["msgs"])
valid_test_cases = test_data["valid_test_cases"]
sign_error_test_cases = test_data["sign_error_test_cases"]
verify_fail_test_cases = test_data["verify_fail_test_cases"]
verify_error_test_cases = test_data["verify_error_test_cases"]
for test_case in valid_test_cases:
pubkeys = [X[i] for i in test_case["key_indices"]]
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
aggnonce = aggnonces[test_case["aggnonce_index"]]
# Make sure that pubnonces and aggnonce in the test vector are
# consistent
assert nonce_agg(pubnonces) == aggnonce
msg = msgs[test_case["msg_index"]]
signer_index = test_case["signer_index"]
expected = bytes.fromhex(test_case["expected"])
session_ctx = SessionContext(aggnonce, pubkeys, [], [], msg)
# WARNING: An actual implementation should _not_ copy the secnonce.
# Reusing the secnonce, as we do here for testing purposes, can leak the
# secret key.
secnonce_tmp = bytearray(secnonces[0])
assert sign(secnonce_tmp, sk, session_ctx) == expected
assert partial_sig_verify(expected, pubnonces, pubkeys, [], [], msg, signer_index)
for test_case in sign_error_test_cases:
exception, except_fn = get_error_details(test_case)
pubkeys = [X[i] for i in test_case["key_indices"]]
aggnonce = aggnonces[test_case["aggnonce_index"]]
msg = msgs[test_case["msg_index"]]
secnonce = bytearray(secnonces[test_case["secnonce_index"]])
session_ctx = SessionContext(aggnonce, pubkeys, [], [], msg)
assert_raises(exception, lambda: sign(secnonce, sk, session_ctx), except_fn)
for test_case in verify_fail_test_cases:
sig = bytes.fromhex(test_case["sig"])
pubkeys = [X[i] for i in test_case["key_indices"]]
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
msg = msgs[test_case["msg_index"]]
signer_index = test_case["signer_index"]
assert not partial_sig_verify(sig, pubnonces, pubkeys, [], [], msg, signer_index)
for test_case in verify_error_test_cases:
exception, except_fn = get_error_details(test_case)
sig = bytes.fromhex(test_case["sig"])
pubkeys = [X[i] for i in test_case["key_indices"]]
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
msg = msgs[test_case["msg_index"]]
signer_index = test_case["signer_index"]
assert_raises(exception, lambda: partial_sig_verify(sig, pubnonces, pubkeys, [], [], msg, signer_index), except_fn)
def test_tweak_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'tweak_vectors.json')) as f:
test_data = json.load(f)
sk = bytes.fromhex(test_data["sk"])
X = fromhex_all(test_data["pubkeys"])
# The public key corresponding to sk is at index 0
assert X[0] == individual_pk(sk)
secnonce = bytearray(bytes.fromhex(test_data["secnonce"]))
pnonce = fromhex_all(test_data["pnonces"])
# The public nonce corresponding to secnonce is at index 0
k_1 = int_from_bytes(secnonce[0:32])
k_2 = int_from_bytes(secnonce[32:64])
R_s1 = point_mul(G, k_1)
R_s2 = point_mul(G, k_2)
assert R_s1 is not None and R_s2 is not None
assert pnonce[0] == cbytes(R_s1) + cbytes(R_s2)
aggnonce = bytes.fromhex(test_data["aggnonce"])
# The aggnonce is the aggregate of the first three elements of pnonce
assert(aggnonce == nonce_agg([pnonce[0], pnonce[1], pnonce[2]]))
tweak = fromhex_all(test_data["tweaks"])
msg = bytes.fromhex(test_data["msg"])
valid_test_cases = test_data["valid_test_cases"]
error_test_cases = test_data["error_test_cases"]
for test_case in valid_test_cases:
pubkeys = [X[i] for i in test_case["key_indices"]]
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
tweaks = [tweak[i] for i in test_case["tweak_indices"]]
is_xonly = test_case["is_xonly"]
signer_index = test_case["signer_index"]
expected = bytes.fromhex(test_case["expected"])
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
secnonce_tmp = bytearray(secnonce)
# WARNING: An actual implementation should _not_ copy the secnonce.
# Reusing the secnonce, as we do here for testing purposes, can leak the
# secret key.
assert sign(secnonce_tmp, sk, session_ctx) == expected
assert partial_sig_verify(expected, pubnonces, pubkeys, tweaks, is_xonly, msg, signer_index)
for test_case in error_test_cases:
exception, except_fn = get_error_details(test_case)
pubkeys = [X[i] for i in test_case["key_indices"]]
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
tweaks = [tweak[i] for i in test_case["tweak_indices"]]
is_xonly = test_case["is_xonly"]
signer_index = test_case["signer_index"]
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
assert_raises(exception, lambda: sign(secnonce, sk, session_ctx), except_fn)
def test_det_sign_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'det_sign_vectors.json')) as f:
test_data = json.load(f)
sk = bytes.fromhex(test_data["sk"])
X = fromhex_all(test_data["pubkeys"])
# The public key corresponding to sk is at index 0
assert X[0] == individual_pk(sk)
msgs = fromhex_all(test_data["msgs"])
valid_test_cases = test_data["valid_test_cases"]
error_test_cases = test_data["error_test_cases"]
for test_case in valid_test_cases:
pubkeys = [X[i] for i in test_case["key_indices"]]
aggothernonce = bytes.fromhex(test_case["aggothernonce"])
tweaks = fromhex_all(test_case["tweaks"])
is_xonly = test_case["is_xonly"]
msg = msgs[test_case["msg_index"]]
signer_index = test_case["signer_index"]
rand = bytes.fromhex(test_case["rand"]) if test_case["rand"] is not None else None
expected = fromhex_all(test_case["expected"])
pubnonce, psig = deterministic_sign(sk, aggothernonce, pubkeys, tweaks, is_xonly, msg, rand)
assert pubnonce == expected[0]
assert psig == expected[1]
pubnonces = [aggothernonce, pubnonce]
aggnonce = nonce_agg(pubnonces)
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
assert partial_sig_verify_internal(psig, pubnonce, pubkeys[signer_index], session_ctx)
for test_case in error_test_cases:
exception, except_fn = get_error_details(test_case)
pubkeys = [X[i] for i in test_case["key_indices"]]
aggothernonce = bytes.fromhex(test_case["aggothernonce"])
tweaks = fromhex_all(test_case["tweaks"])
is_xonly = test_case["is_xonly"]
msg = msgs[test_case["msg_index"]]
signer_index = test_case["signer_index"]
rand = bytes.fromhex(test_case["rand"]) if test_case["rand"] is not None else None
try_fn = lambda: deterministic_sign(sk, aggothernonce, pubkeys, tweaks, is_xonly, msg, rand)
assert_raises(exception, try_fn, except_fn)
def test_sig_agg_vectors() -> None:
with open(os.path.join(sys.path[0], 'vectors', 'sig_agg_vectors.json')) as f:
test_data = json.load(f)
X = fromhex_all(test_data["pubkeys"])
# These nonces are only required if the tested API takes the individual
# nonces and not the aggregate nonce.
pnonce = fromhex_all(test_data["pnonces"])
tweak = fromhex_all(test_data["tweaks"])
psig = fromhex_all(test_data["psigs"])
msg = bytes.fromhex(test_data["msg"])
valid_test_cases = test_data["valid_test_cases"]
error_test_cases = test_data["error_test_cases"]
for test_case in valid_test_cases:
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
aggnonce = bytes.fromhex(test_case["aggnonce"])
assert aggnonce == nonce_agg(pubnonces)
pubkeys = [X[i] for i in test_case["key_indices"]]
tweaks = [tweak[i] for i in test_case["tweak_indices"]]
is_xonly = test_case["is_xonly"]
psigs = [psig[i] for i in test_case["psig_indices"]]
expected = bytes.fromhex(test_case["expected"])
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
sig = partial_sig_agg(psigs, session_ctx)
assert sig == expected
aggpk = get_xonly_pk(key_agg_and_tweak(pubkeys, tweaks, is_xonly))
assert schnorr_verify(msg, aggpk, sig)
for test_case in error_test_cases:
exception, except_fn = get_error_details(test_case)
pubnonces = [pnonce[i] for i in test_case["nonce_indices"]]
aggnonce = nonce_agg(pubnonces)
pubkeys = [X[i] for i in test_case["key_indices"]]
tweaks = [tweak[i] for i in test_case["tweak_indices"]]
is_xonly = test_case["is_xonly"]
psigs = [psig[i] for i in test_case["psig_indices"]]
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
assert_raises(exception, lambda: partial_sig_agg(psigs, session_ctx), except_fn)
def test_sign_and_verify_random(iters: int) -> None:
for i in range(iters):
sk_1 = secrets.token_bytes(32)
sk_2 = secrets.token_bytes(32)
pk_1 = individual_pk(sk_1)
pk_2 = individual_pk(sk_2)
pubkeys = [pk_1, pk_2]
# In this example, the message and aggregate pubkey are known
# before nonce generation, so they can be passed into the nonce
# generation function as a defense-in-depth measure to protect
# against nonce reuse.
#
# If these values are not known when nonce_gen is called, empty
# byte arrays can be passed in for the corresponding arguments
# instead.
msg = secrets.token_bytes(32)
v = secrets.randbelow(4)
tweaks = [secrets.token_bytes(32) for _ in range(v)]
is_xonly = [secrets.choice([False, True]) for _ in range(v)]
aggpk = get_xonly_pk(key_agg_and_tweak(pubkeys, tweaks, is_xonly))
# Use a non-repeating counter for extra_in
secnonce_1, pubnonce_1 = nonce_gen(sk_1, pk_1, aggpk, msg, i.to_bytes(4, 'big'))
# On even iterations use regular signing algorithm for signer 2,
# otherwise use deterministic signing algorithm
if i % 2 == 0:
# Use a clock for extra_in
t = time.clock_gettime_ns(time.CLOCK_MONOTONIC)
secnonce_2, pubnonce_2 = nonce_gen(sk_2, pk_2, aggpk, msg, t.to_bytes(8, 'big'))
else:
aggothernonce = nonce_agg([pubnonce_1])
rand = secrets.token_bytes(32)
pubnonce_2, psig_2 = deterministic_sign(sk_2, aggothernonce, pubkeys, tweaks, is_xonly, msg, rand)
pubnonces = [pubnonce_1, pubnonce_2]
aggnonce = nonce_agg(pubnonces)
session_ctx = SessionContext(aggnonce, pubkeys, tweaks, is_xonly, msg)
psig_1 = sign(secnonce_1, sk_1, session_ctx)
assert partial_sig_verify(psig_1, pubnonces, pubkeys, tweaks, is_xonly, msg, 0)
# An exception is thrown if secnonce_1 is accidentally reused
assert_raises(ValueError, lambda: sign(secnonce_1, sk_1, session_ctx), lambda e: True)
# Wrong signer index
assert not partial_sig_verify(psig_1, pubnonces, pubkeys, tweaks, is_xonly, msg, 1)
# Wrong message
assert not partial_sig_verify(psig_1, pubnonces, pubkeys, tweaks, is_xonly, secrets.token_bytes(32), 0)
if i % 2 == 0:
psig_2 = sign(secnonce_2, sk_2, session_ctx)
assert partial_sig_verify(psig_2, pubnonces, pubkeys, tweaks, is_xonly, msg, 1)
sig = partial_sig_agg([psig_1, psig_2], session_ctx)
assert schnorr_verify(msg, aggpk, sig)
if __name__ == '__main__':
test_key_sort_vectors()
test_key_agg_vectors()
test_nonce_gen_vectors()
test_nonce_agg_vectors()
test_sign_verify_vectors()
test_tweak_vectors()
test_det_sign_vectors()
test_sig_agg_vectors()
test_sign_and_verify_random(6)
================================================
FILE: bip-0327/tests.sh
================================================
#!/bin/sh
set -e
cd "$(dirname "$0")"
mypy --no-error-summary reference.py
python3 reference.py
python3 gen_vectors_helper.py > /dev/null
================================================
FILE: bip-0327/vectors/det_sign_vectors.json
================================================
{
"sk": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"pubkeys": [
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
"020000000000000000000000000000000000000000000000000000000000000007"
],
"msgs": [
"F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF",
"2626262626262626262626262626262626262626262626262626262626262626262626262626"
],
"valid_test_cases": [
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [0, 1, 2],
"tweaks": [],
"is_xonly": [],
"msg_index": 0,
"signer_index": 0,
"expected": [
"03D96275257C2FCCBB6EEB77BDDF51D3C88C26EE1626C6CDA8999B9D34F4BA13A60309BE2BF883C6ABE907FA822D9CA166D51A3DCC28910C57528F6983FC378B7843",
"41EA65093F71D084785B20DC26A887CD941C9597860A21660CBDB9CC2113CAD3"
]
},
{
"rand": null,
"aggothernonce": "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [1, 0, 2],
"tweaks": [],
"is_xonly": [],
"msg_index": 0,
"signer_index": 1,
"expected": [
"028FBCCF5BB73A7B61B270BAD15C0F9475D577DD85C2157C9D38BEF1EC922B48770253BE3638C87369BC287E446B7F2C8CA5BEB9FFBD1EA082C62913982A65FC214D",
"AEAA31262637BFA88D5606679018A0FEEEC341F3107D1199857F6C81DE61B8DD"
]
},
{
"rand": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
"aggothernonce": "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"key_indices": [1, 2, 0],
"tweaks": [],
"is_xonly": [],
"msg_index": 1,
"signer_index": 2,
"expected": [
"024FA8D774F0C8743FAA77AFB4D08EE5A013C2E8EEAD8A6F08A77DDD2D28266DB803050905E8C994477F3F2981861A2E3791EF558626E645FBF5AA131C5D6447C2C2",
"FEE28A56B8556B7632E42A84122C51A4861B1F2DEC7E81B632195E56A52E3E13"
],
"comment": "Message longer than 32 bytes"
},
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "032DE2662628C90B03F5E720284EB52FF7D71F4284F627B68A853D78C78E1FFE9303E4C5524E83FFE1493B9077CF1CA6BEB2090C93D930321071AD40B2F44E599046",
"key_indices": [0, 1, 2],
"tweaks": ["E8F791FF9225A2AF0102AFFF4A9A723D9612A682A25EBE79802B263CDFCD83BB"],
"is_xonly": [true],
"msg_index": 0,
"signer_index": 0,
"expected": [
"031E07C0D11A0134E55DB1FC16095ADCBD564236194374AA882BFB3C78273BF673039D0336E8CA6288C00BFC1F8B594563529C98661172B9BC1BE85C23A4CE1F616B",
"7B1246C5889E59CB0375FA395CC86AC42D5D7D59FD8EAB4FDF1DCAB2B2F006EA"
],
"comment": "Tweaked public key"
}
],
"error_test_cases": [
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [1, 0, 3],
"tweaks": [],
"is_xonly": [],
"msg_index": 0,
"signer_index": 1,
"error": {
"type": "invalid_contribution",
"signer": 2,
"contrib": "pubkey"
},
"comment": "Signer 2 provided an invalid public key"
},
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [1, 2],
"tweaks": [],
"is_xonly": [],
"msg_index": 0,
"signer_index": 1,
"error": {
"type": "value",
"message": "The signer's pubkey must be included in the list of pubkeys."
},
"comment": "The signers pubkey is not in the list of pubkeys"
},
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "0437C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [1, 2, 0],
"tweaks": [],
"is_xonly": [],
"msg_index": 0,
"signer_index": 2,
"error": {
"type": "invalid_contribution",
"signer": null,
"contrib": "aggothernonce"
},
"comment": "aggothernonce is invalid due wrong tag, 0x04, in the first half"
},
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "0000000000000000000000000000000000000000000000000000000000000000000287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [1, 2, 0],
"tweaks": [],
"is_xonly": [],
"msg_index": 0,
"signer_index": 2,
"error": {
"type": "invalid_contribution",
"signer": null,
"contrib": "aggothernonce"
},
"comment": "aggothernonce is invalid because first half corresponds to point at infinity"
},
{
"rand": "0000000000000000000000000000000000000000000000000000000000000000",
"aggothernonce": "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"key_indices": [1, 2, 0],
"tweaks": ["FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"],
"is_xonly": [false],
"msg_index": 0,
"signer_index": 2,
"error": {
"type": "value",
"message": "The tweak must be less than n."
},
"comment": "Tweak is invalid because it exceeds group size"
}
]
}
================================================
FILE: bip-0327/vectors/key_agg_vectors.json
================================================
{
"pubkeys": [
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
"020000000000000000000000000000000000000000000000000000000000000005",
"02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30",
"04F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
],
"tweaks": [
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
"252E4BD67410A76CDF933D30EAA1608214037F1B105A013ECCD3C5C184A6110B"
],
"valid_test_cases": [
{
"key_indices": [0, 1, 2],
"expected": "90539EEDE565F5D054F32CC0C220126889ED1E5D193BAF15AEF344FE59D4610C"
},
{
"key_indices": [2, 1, 0],
"expected": "6204DE8B083426DC6EAF9502D27024D53FC826BF7D2012148A0575435DF54B2B"
},
{
"key_indices": [0, 0, 0],
"expected": "B436E3BAD62B8CD409969A224731C193D051162D8C5AE8B109306127DA3AA935"
},
{
"key_indices": [0, 0, 1, 1],
"expected": "69BC22BFA5D106306E48A20679DE1D7389386124D07571D0D872686028C26A3E"
}
],
"error_test_cases": [
{
"key_indices": [0, 3],
"tweak_indices": [],
"is_xonly": [],
"error": {
"type": "invalid_contribution",
"signer": 1,
"contrib": "pubkey"
},
"comment": "Invalid public key"
},
{
"key_indices": [0, 4],
"tweak_indices": [],
"is_xonly": [],
"error": {
"type": "invalid_contribution",
"signer": 1,
"contrib": "pubkey"
},
"comment": "Public key exceeds field size"
},
{
"key_indices": [5, 0],
"tweak_indices": [],
"is_xonly": [],
"error": {
"type": "invalid_contribution",
"signer": 0,
"contrib": "pubkey"
},
"comment": "First byte of public key is not 2 or 3"
},
{
"key_indices": [0, 1],
"tweak_indices": [0],
"is_xonly": [true],
"error": {
"type": "value",
"message": "The tweak must be less than n."
},
"comment": "Tweak is out of range"
},
{
"key_indices": [6],
"tweak_indices": [1],
"is_xonly": [false],
"error": {
"type": "value",
"message": "The result of tweaking cannot be infinity."
},
"comment": "Intermediate tweaking result is point at infinity"
}
]
}
================================================
FILE: bip-0327/vectors/key_sort_vectors.json
================================================
{
"pubkeys": [
"02DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
"02DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EFF",
"02DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8"
],
"sorted_pubkeys": [
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
"02DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8",
"02DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8",
"02DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EFF",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
]
}
================================================
FILE: bip-0327/vectors/nonce_agg_vectors.json
================================================
{
"pnonces": [
"020151C80F435648DF67A22B749CD798CE54E0321D034B92B709B567D60A42E66603BA47FBC1834437B3212E89A84D8425E7BF12E0245D98262268EBDCB385D50641",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833",
"020151C80F435648DF67A22B749CD798CE54E0321D034B92B709B567D60A42E6660279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60379BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"04FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A60248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B831",
"03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A602FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"
],
"valid_test_cases": [
{
"pnonce_indices": [0, 1],
"expected": "035FE1873B4F2967F52FEA4A06AD5A8ECCBE9D0FD73068012C894E2E87CCB5804B024725377345BDE0E9C33AF3C43C0A29A9249F2F2956FA8CFEB55C8573D0262DC8"
},
{
"pnonce_indices": [2, 3],
"expected": "035FE1873B4F2967F52FEA4A06AD5A8ECCBE9D0FD73068012C894E2E87CCB5804B000000000000000000000000000000000000000000000000000000000000000000",
"comment": "Sum of second points encoded in the nonces is point at infinity which is serialized as 33 zero bytes"
}
],
"error_test_cases": [
{
"pnonce_indices": [0, 4],
"error": {
"type": "invalid_contribution",
"signer": 1,
"contrib": "pubnonce"
},
"comment": "Public nonce from signer 1 is invalid due wrong tag, 0x04, in the first half"
},
{
"pnonce_indices": [5, 1],
"error": {
"type": "invalid_contribution",
"signer": 0,
"contrib": "pubnonce"
},
"comment": "Public nonce from signer 0 is invalid because the second half does not correspond to an X coordinate"
},
{
"pnonce_indices": [6, 1],
"error": {
"type": "invalid_contribution",
"signer": 0,
"contrib": "pubnonce"
},
"comment": "Public nonce from signer 0 is invalid because second half exceeds field size"
}
]
}
================================================
FILE: bip-0327/vectors/nonce_gen_vectors.json
================================================
{
"test_cases": [
{
"rand_": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"sk": "0202020202020202020202020202020202020202020202020202020202020202",
"pk": "024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766",
"aggpk": "0707070707070707070707070707070707070707070707070707070707070707",
"msg": "0101010101010101010101010101010101010101010101010101010101010101",
"extra_in": "0808080808080808080808080808080808080808080808080808080808080808",
"expected_secnonce": "B114E502BEAA4E301DD08A50264172C84E41650E6CB726B410C0694D59EFFB6495B5CAF28D045B973D63E3C99A44B807BDE375FD6CB39E46DC4A511708D0E9D2024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766",
"expected_pubnonce": "02F7BE7089E8376EB355272368766B17E88E7DB72047D05E56AA881EA52B3B35DF02C29C8046FDD0DED4C7E55869137200FBDBFE2EB654267B6D7013602CAED3115A"
},
{
"rand_": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"sk": "0202020202020202020202020202020202020202020202020202020202020202",
"pk": "024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766",
"aggpk": "0707070707070707070707070707070707070707070707070707070707070707",
"msg": "",
"extra_in": "0808080808080808080808080808080808080808080808080808080808080808",
"expected_secnonce": "E862B068500320088138468D47E0E6F147E01B6024244AE45EAC40ACE5929B9F0789E051170B9E705D0B9EB49049A323BBBBB206D8E05C19F46C6228742AA7A9024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766",
"expected_pubnonce": "023034FA5E2679F01EE66E12225882A7A48CC66719B1B9D3B6C4DBD743EFEDA2C503F3FD6F01EB3A8E9CB315D73F1F3D287CAFBB44AB321153C6287F407600205109"
},
{
"rand_": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"sk": "0202020202020202020202020202020202020202020202020202020202020202",
"pk": "024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766",
"aggpk": "0707070707070707070707070707070707070707070707070707070707070707",
"msg": "2626262626262626262626262626262626262626262626262626262626262626262626262626",
"extra_in": "0808080808080808080808080808080808080808080808080808080808080808",
"expected_secnonce": "3221975ACBDEA6820EABF02A02B7F27D3A8EF68EE42787B88CBEFD9AA06AF3632EE85B1A61D8EF31126D4663A00DD96E9D1D4959E72D70FE5EBB6E7696EBA66F024D4B6CD1361032CA9BD2AEB9D900AA4D45D9EAD80AC9423374C451A7254D0766",
"expected_pubnonce": "02E5BBC21C69270F59BD634FCBFA281BE9D76601295345112C58954625BF23793A021307511C79F95D38ACACFF1B4DA98228B77E65AA216AD075E9673286EFB4EAF3"
},
{
"rand_": "0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F",
"sk": null,
"pk": "02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"aggpk": null,
"msg": null,
"extra_in": null,
"expected_secnonce": "89BDD787D0284E5E4D5FC572E49E316BAB7E21E3B1830DE37DFE80156FA41A6D0B17AE8D024C53679699A6FD7944D9C4A366B514BAF43088E0708B1023DD289702F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"expected_pubnonce": "02C96E7CB1E8AA5DAC64D872947914198F607D90ECDE5200DE52978AD5DED63C000299EC5117C2D29EDEE8A2092587C3909BE694D5CFF0667D6C02EA4059F7CD9786"
}
]
}
================================================
FILE: bip-0327/vectors/sig_agg_vectors.json
================================================
{
"pubkeys": [
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"02D2DC6F5DF7C56ACF38C7FA0AE7A759AE30E19B37359DFDE015872324C7EF6E05",
"03C7FB101D97FF930ACD0C6760852EF64E69083DE0B06AC6335724754BB4B0522C",
"02352433B21E7E05D3B452B81CAE566E06D2E003ECE16D1074AABA4289E0E3D581"
],
"pnonces": [
"036E5EE6E28824029FEA3E8A9DDD2C8483F5AF98F7177C3AF3CB6F47CAF8D94AE902DBA67E4A1F3680826172DA15AFB1A8CA85C7C5CC88900905C8DC8C328511B53E",
"03E4F798DA48A76EEC1C9CC5AB7A880FFBA201A5F064E627EC9CB0031D1D58FC5103E06180315C5A522B7EC7C08B69DCD721C313C940819296D0A7AB8E8795AC1F00",
"02C0068FD25523A31578B8077F24F78F5BD5F2422AFF47C1FADA0F36B3CEB6C7D202098A55D1736AA5FCC21CF0729CCE852575C06C081125144763C2C4C4A05C09B6",
"031F5C87DCFBFCF330DEE4311D85E8F1DEA01D87A6F1C14CDFC7E4F1D8C441CFA40277BF176E9F747C34F81B0D9F072B1B404A86F402C2D86CF9EA9E9C69876EA3B9",
"023F7042046E0397822C4144A17F8B63D78748696A46C3B9F0A901D296EC3406C302022B0B464292CF9751D699F10980AC764E6F671EFCA15069BBE62B0D1C62522A",
"02D97DDA5988461DF58C5897444F116A7C74E5711BF77A9446E27806563F3B6C47020CBAD9C363A7737F99FA06B6BE093CEAFF5397316C5AC46915C43767AE867C00"
],
"tweaks": [
"B511DA492182A91B0FFB9A98020D55F260AE86D7ECBD0399C7383D59A5F2AF7C",
"A815FE049EE3C5AAB66310477FBC8BCCCAC2F3395F59F921C364ACD78A2F48DC",
"75448A87274B056468B977BE06EB1E9F657577B7320B0A3376EA51FD420D18A8"
],
"psigs": [
"B15D2CD3C3D22B04DAE438CE653F6B4ECF042F42CFDED7C41B64AAF9B4AF53FB",
"6193D6AC61B354E9105BBDC8937A3454A6D705B6D57322A5A472A02CE99FCB64",
"9A87D3B79EC67228CB97878B76049B15DBD05B8158D17B5B9114D3C226887505",
"66F82EA90923689B855D36C6B7E032FB9970301481B99E01CDB4D6AC7C347A15",
"4F5AEE41510848A6447DCD1BBC78457EF69024944C87F40250D3EF2C25D33EFE",
"DDEF427BBB847CC027BEFF4EDB01038148917832253EBC355FC33F4A8E2FCCE4",
"97B890A26C981DA8102D3BC294159D171D72810FDF7C6A691DEF02F0F7AF3FDC",
"53FA9E08BA5243CBCB0D797C5EE83BC6728E539EB76C2D0BF0F971EE4E909971",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
],
"msg": "599C67EA410D005B9DA90817CF03ED3B1C868E4DA4EDF00A5880B0082C237869",
"valid_test_cases": [
{
"aggnonce": "0341432722C5CD0268D829C702CF0D1CBCE57033EED201FD335191385227C3210C03D377F2D258B64AADC0E16F26462323D701D286046A2EA93365656AFD9875982B",
"nonce_indices": [
0,
1
],
"key_indices": [
0,
1
],
"tweak_indices": [],
"is_xonly": [],
"psig_indices": [
0,
1
],
"expected": "041DA22223CE65C92C9A0D6C2CAC828AAF1EEE56304FEC371DDF91EBB2B9EF0912F1038025857FEDEB3FF696F8B99FA4BB2C5812F6095A2E0004EC99CE18DE1E"
},
{
"aggnonce": "0224AFD36C902084058B51B5D36676BBA4DC97C775873768E58822F87FE437D792028CB15929099EEE2F5DAE404CD39357591BA32E9AF4E162B8D3E7CB5EFE31CB20",
"nonce_indices": [
0,
2
],
"key_indices": [
0,
2
],
"tweak_indices": [],
"is_xonly": [],
"psig_indices": [
2,
3
],
"expected": "1069B67EC3D2F3C7C08291ACCB17A9C9B8F2819A52EB5DF8726E17E7D6B52E9F01800260A7E9DAC450F4BE522DE4CE12BA91AEAF2B4279219EF74BE1D286ADD9"
},
{
"aggnonce": "0208C5C438C710F4F96A61E9FF3C37758814B8C3AE12BFEA0ED2C87FF6954FF186020B1816EA104B4FCA2D304D733E0E19CEAD51303FF6420BFD222335CAA402916D",
"nonce_indices": [
0,
3
],
"key_indices": [
0,
2
],
"tweak_indices": [
0
],
"is_xonly": [
false
],
"psig_indices": [
4,
5
],
"expected": "5C558E1DCADE86DA0B2F02626A512E30A22CF5255CAEA7EE32C38E9A71A0E9148BA6C0E6EC7683B64220F0298696F1B878CD47B107B81F7188812D593971E0CC"
},
{
"aggnonce": "02B5AD07AFCD99B6D92CB433FBD2A28FDEB98EAE2EB09B6014EF0F8197CD58403302E8616910F9293CF692C49F351DB86B25E352901F0E237BAFDA11F1C1CEF29FFD",
"nonce_indices": [
0,
4
],
"key_indices": [
0,
3
],
"tweak_indices": [
0,
1,
2
],
"is_xonly": [
true,
false,
true
],
"psig_indices": [
6,
7
],
"expected": "839B08820B681DBA8DAF4CC7B104E8F2638F9388F8D7A555DC17B6E6971D7426CE07BF6AB01F1DB50E4E33719295F4094572B79868E440FB3DEFD3FAC1DB589E"
}
],
"error_test_cases": [
{
"aggnonce": "02B5AD07AFCD99B6D92CB433FBD2A28FDEB98EAE2EB09B6014EF0F8197CD58403302E8616910F9293CF692C49F351DB86B25E352901F0E237BAFDA11F1C1CEF29FFD",
"nonce_indices": [
0,
4
],
"key_indices": [
0,
3
],
"tweak_indices": [
0,
1,
2
],
"is_xonly": [
true,
false,
true
],
"psig_indices": [
7,
8
],
"error": {
"type": "invalid_contribution",
"signer": 1,
"contrib": "psig"
},
"comment": "Partial signature is invalid because it exceeds group size"
}
]
}
================================================
FILE: bip-0327/vectors/sign_verify_vectors.json
================================================
{
"sk": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"pubkeys": [
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA661",
"020000000000000000000000000000000000000000000000000000000000000007"
],
"secnonces": [
"508B81A611F100A6B2B6B29656590898AF488BCF2E1F55CF22E5CFB84421FE61FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F703935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
],
"pnonces": [
"0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"032DE2662628C90B03F5E720284EB52FF7D71F4284F627B68A853D78C78E1FFE9303E4C5524E83FFE1493B9077CF1CA6BEB2090C93D930321071AD40B2F44E599046",
"0237C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0387BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"0200000000000000000000000000000000000000000000000000000000000000090287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480"
],
"aggnonces": [
"028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"048465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9",
"028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61020000000000000000000000000000000000000000000000000000000000000009",
"028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD6102FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"
],
"msgs": [
"F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF",
"",
"2626262626262626262626262626262626262626262626262626262626262626262626262626"
],
"valid_test_cases": [
{
"key_indices": [0, 1, 2],
"nonce_indices": [0, 1, 2],
"aggnonce_index": 0,
"msg_index": 0,
"signer_index": 0,
"expected": "012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB"
},
{
"key_indices": [1, 0, 2],
"nonce_indices": [1, 0, 2],
"aggnonce_index": 0,
"msg_index": 0,
"signer_index": 1,
"expected": "9FF2F7AAA856150CC8819254218D3ADEEB0535269051897724F9DB3789513A52"
},
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"aggnonce_index": 0,
"msg_index": 0,
"signer_index": 2,
"expected": "FA23C359F6FAC4E7796BB93BC9F0532A95468C539BA20FF86D7C76ED92227900"
},
{
"key_indices": [0, 1],
"nonce_indices": [0, 3],
"aggnonce_index": 1,
"msg_index": 0,
"signer_index": 0,
"expected": "AE386064B26105404798F75DE2EB9AF5EDA5387B064B83D049CB7C5E08879531",
"comment": "Both halves of aggregate nonce correspond to point at infinity"
},
{
"key_indices": [0, 1, 2],
"nonce_indices": [0, 1, 2],
"aggnonce_index": 0,
"msg_index": 1,
"signer_index": 0,
"expected": "D7D63FFD644CCDA4E62BC2BC0B1D02DD32A1DC3030E155195810231D1037D82D",
"comment": "Empty message"
},
{
"key_indices": [0, 1, 2],
"nonce_indices": [0, 1, 2],
"aggnonce_index": 0,
"msg_index": 2,
"signer_index": 0,
"expected": "E184351828DA5094A97C79CABDAAA0BFB87608C32E8829A4DF5340A6F243B78C",
"comment": "38-byte message"
}
],
"sign_error_test_cases": [
{
"key_indices": [1, 2],
"aggnonce_index": 0,
"msg_index": 0,
"secnonce_index": 0,
"error": {
"type": "value",
"message": "The signer's pubkey must be included in the list of pubkeys."
},
"comment": "The signers pubkey is not in the list of pubkeys. This test case is optional: it can be skipped by implementations that do not check that the signer's pubkey is included in the list of pubkeys."
},
{
"key_indices": [1, 0, 3],
"aggnonce_index": 0,
"msg_index": 0,
"secnonce_index": 0,
"error": {
"type": "invalid_contribution",
"signer": 2,
"contrib": "pubkey"
},
"comment": "Signer 2 provided an invalid public key"
},
{
"key_indices": [1, 2, 0],
"aggnonce_index": 2,
"msg_index": 0,
"secnonce_index": 0,
"error": {
"type": "invalid_contribution",
"signer": null,
"contrib": "aggnonce"
},
"comment": "Aggregate nonce is invalid due wrong tag, 0x04, in the first half"
},
{
"key_indices": [1, 2, 0],
"aggnonce_index": 3,
"msg_index": 0,
"secnonce_index": 0,
"error": {
"type": "invalid_contribution",
"signer": null,
"contrib": "aggnonce"
},
"comment": "Aggregate nonce is invalid because the second half does not correspond to an X coordinate"
},
{
"key_indices": [1, 2, 0],
"aggnonce_index": 4,
"msg_index": 0,
"secnonce_index": 0,
"error": {
"type": "invalid_contribution",
"signer": null,
"contrib": "aggnonce"
},
"comment": "Aggregate nonce is invalid because second half exceeds field size"
},
{
"key_indices": [0, 1, 2],
"aggnonce_index": 0,
"msg_index": 0,
"signer_index": 0,
"secnonce_index": 1,
"error": {
"type": "value",
"message": "first secnonce value is out of range."
},
"comment": "Secnonce is invalid which may indicate nonce reuse"
}
],
"verify_fail_test_cases": [
{
"sig": "FED54434AD4CFE953FC527DC6A5E5BE8F6234907B7C187559557CE87A0541C46",
"key_indices": [0, 1, 2],
"nonce_indices": [0, 1, 2],
"msg_index": 0,
"signer_index": 0,
"comment": "Wrong signature (which is equal to the negation of valid signature)"
},
{
"sig": "012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB",
"key_indices": [0, 1, 2],
"nonce_indices": [0, 1, 2],
"msg_index": 0,
"signer_index": 1,
"comment": "Wrong signer"
},
{
"sig": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
"key_indices": [0, 1, 2],
"nonce_indices": [0, 1, 2],
"msg_index": 0,
"signer_index": 0,
"comment": "Signature exceeds group size"
}
],
"verify_error_test_cases": [
{
"sig": "012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB",
"key_indices": [0, 1, 2],
"nonce_indices": [4, 1, 2],
"msg_index": 0,
"signer_index": 0,
"error": {
"type": "invalid_contribution",
"signer": 0,
"contrib": "pubnonce"
},
"comment": "Invalid pubnonce"
},
{
"sig": "012ABBCB52B3016AC03AD82395A1A415C48B93DEF78718E62A7A90052FE224FB",
"key_indices": [3, 1, 2],
"nonce_indices": [0, 1, 2],
"msg_index": 0,
"signer_index": 0,
"error": {
"type": "invalid_contribution",
"signer": 0,
"contrib": "pubkey"
},
"comment": "Invalid pubkey"
}
]
}
================================================
FILE: bip-0327/vectors/tweak_vectors.json
================================================
{
"sk": "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671",
"pubkeys": [
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"
],
"secnonce": "508B81A611F100A6B2B6B29656590898AF488BCF2E1F55CF22E5CFB84421FE61FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F703935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"pnonces": [
"0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA0287BF891D2A6DEAEBADC909352AA9405D1428C15F4B75F04DAE642A95C2548480",
"0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
"032DE2662628C90B03F5E720284EB52FF7D71F4284F627B68A853D78C78E1FFE9303E4C5524E83FFE1493B9077CF1CA6BEB2090C93D930321071AD40B2F44E599046"
],
"aggnonce": "028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9",
"tweaks": [
"E8F791FF9225A2AF0102AFFF4A9A723D9612A682A25EBE79802B263CDFCD83BB",
"AE2EA797CC0FE72AC5B97B97F3C6957D7E4199A167A58EB08BCAFFDA70AC0455",
"F52ECBC565B3D8BEA2DFD5B75A4F457E54369809322E4120831626F290FA87E0",
"1969AD73CC177FA0B4FCED6DF1F7BF9907E665FDE9BA196A74FED0A3CF5AEF9D",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
],
"msg": "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF",
"valid_test_cases": [
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"tweak_indices": [0],
"is_xonly": [true],
"signer_index": 2,
"expected": "E28A5C66E61E178C2BA19DB77B6CF9F7E2F0F56C17918CD13135E60CC848FE91",
"comment": "A single x-only tweak"
},
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"tweak_indices": [0],
"is_xonly": [false],
"signer_index": 2,
"expected": "38B0767798252F21BF5702C48028B095428320F73A4B14DB1E25DE58543D2D2D",
"comment": "A single plain tweak"
},
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"tweak_indices": [0, 1],
"is_xonly": [false, true],
"signer_index": 2,
"expected": "408A0A21C4A0F5DACAF9646AD6EB6FECD7F7A11F03ED1F48DFFF2185BC2C2408",
"comment": "A plain tweak followed by an x-only tweak"
},
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"tweak_indices": [0, 1, 2, 3],
"is_xonly": [false, false, true, true],
"signer_index": 2,
"expected": "45ABD206E61E3DF2EC9E264A6FEC8292141A633C28586388235541F9ADE75435",
"comment": "Four tweaks: plain, plain, x-only, x-only."
},
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"tweak_indices": [0, 1, 2, 3],
"is_xonly": [true, false, true, false],
"signer_index": 2,
"expected": "B255FDCAC27B40C7CE7848E2D3B7BF5EA0ED756DA81565AC804CCCA3E1D5D239",
"comment": "Four tweaks: x-only, plain, x-only, plain. If an implementation prohibits applying plain tweaks after x-only tweaks, it can skip this test vector or return an error."
}
],
"error_test_cases": [
{
"key_indices": [1, 2, 0],
"nonce_indices": [1, 2, 0],
"tweak_indices": [4],
"is_xonly": [false],
"signer_index": 2,
"error": {
"type": "value",
"message": "The tweak must be less than n."
},
"comment": "Tweak is invalid because it exceeds group size"
}
]
}
================================================
FILE: bip-0327.mediawiki
================================================
BIP: 327
Title: MuSig2 for BIP340-compatible Multi-Signatures
Authors: Jonas Nick
Tim Ruffing
Elliott Jin
Status: Deployed
Type: Informational
Assigned: 2022-03-22
License: BSD-3-Clause
Discussion: 2022-04-05: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-April/020198.html [bitcoin-dev] MuSig2 BIP
2022-10-11: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-October/021000.html [bitcoin-dev] MuSig2 BIP
Version: 1.0.3
== Introduction ==
=== Abstract ===
This document proposes a standard for the [https://eprint.iacr.org/2020/1261.pdf MuSig2] multi-signature scheme.
The standard is compatible with [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] public keys and signatures.
It supports ''tweaking'', which allows deriving [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32] child keys from aggregate public keys and creating [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] Taproot outputs with key and script paths.
=== Copyright ===
This document is licensed under the 3-clause BSD license.
=== Motivation ===
MuSig2 is a multi-signature scheme that allows multiple signers to create a single aggregate public key and cooperatively create ordinary Schnorr signatures valid under the aggregate public key.
Signing requires interaction between ''all'' signers involved in key aggregation.
(MuSig2 is a ''n-of-n'' multi-signature scheme and not a ''t-of-n'' threshold-signature scheme.)
The primary motivation is to create a standard that allows users of different software projects to jointly control Taproot outputs ([https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341]).
Such an output contains a public key which, in this case, would be the aggregate of all users' individual public keys.
It can be spent using MuSig2 to produce a signature for the key-based spending path.
The on-chain footprint of a MuSig2 Taproot output is essentially a single BIP340 public key, and a transaction spending the output only requires a single signature cooperatively produced by all signers. This is '''more compact''' and has '''lower verification cost''' than each signer providing an individual public key and signature, as would be required by an ''n-of-n'' policy implemented using OP_CHECKSIGADD as introduced in ([https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki BIP342]).
As a side effect, the number ''n'' of signers is not limited by any consensus rules when using MuSig2.
Moreover, MuSig2 offers a '''higher level of privacy''' than OP_CHECKSIGADD: MuSig2 Taproot outputs are indistinguishable for a blockchain observer from regular, single-signer Taproot outputs even though they are actually controlled by multiple signers. By tweaking an aggregate public key, the shared Taproot output can have script spending paths that are hidden unless used.
There are multi-signature schemes other than MuSig2 that are fully compatible with Schnorr signatures.
The MuSig2 variant proposed below stands out by combining all the following features:
* '''Simple Key Setup''': Key aggregation is non-interactive and fully compatible with BIP340 public keys.
* '''Two Communication Rounds''': MuSig2 is faster in practice than previous three-round multi-signature schemes such as [https://eprint.iacr.org/2018/068.pdf MuSig1], particularly when signers are connected through high-latency anonymous links. Moreover, the need for fewer communication rounds simplifies the algorithms and reduces the probability that implementations and users make security-relevant mistakes.
* '''Provable security''': MuSig2 has been [https://eprint.iacr.org/2020/1261.pdf proven existentially unforgeable] under the algebraic one-more discrete logarithm (AOMDL) assumption (instead of the discrete logarithm assumption required for single-signer Schnorr signatures). AOMDL is a falsifiable and weaker variant of the well-studied OMDL problem.
* '''Low complexity''': MuSig2 has a substantially lower computational and implementation complexity than alternative schemes like [https://eprint.iacr.org/2020/1057 MuSig-DN]. However, this comes at the cost of having no ability to generate nonces deterministically and the requirement to securely handle signing state.
=== Design ===
* '''Compatibility with BIP340''': In this proposal, the aggregate public key is a BIP340 X-only public key, and the signature output at the end of the signing protocol is a BIP340 signature that passes BIP340 verification for the aggregate public key and a message. The individual public keys that are input to the key aggregation algorithm are ''plain'' public keys in compressed format.
* '''Tweaking for BIP32 derivations and Taproot''': This proposal supports tweaking aggregate public keys and signing for tweaked aggregate public keys. We distinguish two modes of tweaking: ''Plain'' tweaking can be used to derive child aggregate public keys per [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]. ''X-only'' tweaking, on the other hand, allows creating a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] tweak to add script paths to a Taproot output. See [[#tweaking-the-aggregate-public-key|below]] for details.
* '''Non-interactive signing with preprocessing''': The first communication round, exchanging the nonces, can happen before the message or the exact set of signers is determined. Once the parameters of the signing session are finalized, the signers can send partial signatures without additional interaction.
* '''Key aggregation optionally independent of order''': The output of the key aggregation algorithm depends on the order in which the individual public keys are provided as input. Key aggregation does not sort the individual public keys by default because applications often already have a canonical order of signers. Nonetheless, applications can mandate sorting before aggregation,Applications that sort individual public keys before aggregation should ensure that the implementation of sorting is reasonably efficient, and in particular does not degenerate to quadratic runtime on pathological inputs. and this proposal specifies a canonical order to sort the individual public keys before key aggregation. Sorting will ensure the same output, independent of the initial order.
* '''Third-party nonce and partial signature aggregation''': Instead of every signer sending their nonce and partial signature to every other signer, it is possible to use an untrusted third-party ''aggregator'' in order to reduce the communication complexity from quadratic to linear in the number of signers. In each of the two rounds, the aggregator collects all signers' contributions (nonces or partial signatures), aggregates them, and broadcasts the aggregate back to the signers. A malicious aggregator can force the signing session to fail to produce a valid Schnorr signature but cannot negatively affect the unforgeability of the scheme.
* '''Partial signature verification''': If any signer sends a partial signature contribution that was not created by honestly following the signing protocol, the signing session will fail to produce a valid Schnorr signature. This proposal specifies a partial signature verification algorithm to identify disruptive signers. It is incompatible with third-party nonce aggregation because the individual nonce is required for partial verification.
* '''MuSig2* optimization''': This proposal uses an optimized scheme MuSig2*, which allows saving a point multiplication in key aggregation as compared to MuSig2. MuSig2* is proven secure in the appendix of the [https://eprint.iacr.org/2020/1261 MuSig2 paper]. The optimization consists of assigning the constant key aggregation coefficient ''1'' to the second distinct key in the list of individual public keys to be aggregated (as well as to any key identical to this key).
* '''Size of the nonce and security''': In this proposal, each signer's nonce consists of two elliptic curve points. The [https://eprint.iacr.org/2020/1261 MuSig2 paper] gives distinct security proofs depending on the number of points that constitute a nonce. See section [[#choosing-the-size-of-the-nonce|Choosing the Size of the Nonce]] for a discussion.
== Overview ==
Implementers must make sure to understand this section thoroughly to avoid subtle mistakes that may lead to catastrophic failure.
=== Optionality of Features ===
The goal of this proposal is to support a wide range of possible application scenarios.
Given a specific application scenario, some features may be unnecessary or not desirable, and implementers can choose not to support them.
Such optional features include:
* Applying plain tweaks after x-only tweaks.
* Applying tweaks at all.
* Dealing with messages that are not exactly 32 bytes.
* Identifying a disruptive signer after aborting (aborting itself remains mandatory).
* Dealing with duplicate individual public keys in key aggregation.
If applicable, the corresponding algorithms should simply fail when encountering inputs unsupported by a particular implementation. (For example, the signing algorithm may fail when given a message which is not 32 bytes.)
Similarly, the test vectors that exercise the unimplemented features should be re-interpreted to expect an error, or be skipped if appropriate.
=== General Signing Flow ===
The signers start by exchanging their individual public keys and computing an aggregate public key using the ''KeyAgg'' algorithm.
Whenever they want to sign a message, the basic order of operations to create a multi-signature is as follows:
'''First broadcast round:'''
The signers start the signing session by running ''NonceGen'' to compute ''secnonce'' and ''pubnonce''.We treat the ''secnonce'' and ''pubnonce'' as grammatically singular even though they include serializations of two scalars and two elliptic curve points, respectively. This treatment may be confusing for readers familiar with the MuSig2 paper. However, serialization is a technical detail that is irrelevant for users of MuSig2 interfaces.
Then, the signers broadcast their ''pubnonce'' to each other and run ''NonceAgg'' to compute an aggregate nonce.
'''Second broadcast round:'''
At this point, every signer has the required data to sign, which, in the algorithms specified below, is stored in a data structure called [[#session-context|Session Context]].
Every signer computes a partial signature by running ''Sign'' with the secret signing key, the ''secnonce'' and the session context.
Then, the signers broadcast their partial signatures to each other and run ''PartialSigAgg'' to obtain the final signature.
If all signers behaved honestly, the result passes [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] verification.
Both broadcast rounds can be optimized by using an aggregator who collects all signers' nonces or partial signatures, aggregates them using ''NonceAgg'' or ''PartialSigAgg'', respectively, and broadcasts the aggregate result back to the signers. A malicious aggregator can force the signing session to fail to produce a valid Schnorr signature but cannot negatively affect the unforgeability of the scheme, i.e., even a malicious aggregator colluding with all but one signer cannot forge a signature.
'''IMPORTANT''': The ''Sign'' algorithm must '''not''' be executed twice with the same ''secnonce''.
Otherwise, it is possible to extract the secret signing key from the two partial signatures output by the two executions of ''Sign''.
To avoid accidental reuse of ''secnonce'', an implementation may securely erase the ''secnonce'' argument by overwriting it with 64 zero bytes after it has been read by ''Sign''.
A ''secnonce'' consisting of only zero bytes is invalid for ''Sign'' and will cause it to fail.
To simplify the specification of the algorithms, some intermediary values are unnecessarily recomputed from scratch, e.g., when executing ''GetSessionValues'' multiple times.
Actual implementations can cache these values.
As a result, the [[#session-context|Session Context]] may look very different in implementations or may not exist at all.
However, computation of ''GetSessionValues'' and storage of the result must be protected against modification from an untrusted third party.
This party would have complete control over the aggregate public key and message to be signed.
=== Public Key Aggregation ===
We distinguish between two public key types, namely ''plain public keys'', the key type traditionally used in Bitcoin, and ''X-only public keys''.
Plain public keys are byte strings of length 33 (often called ''compressed'' format).
In contrast, X-only public keys are 32-byte strings defined in [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340].
The individual public keys of signers as input to the key aggregation algorithm ''KeyAgg'' (and to ''GetSessionValues'' and ''PartialSigVerify'') are plain public keys.
The output of ''KeyAgg'' is a [[#keyagg-context|KeyAgg Context]] which stores information required for tweaking the aggregate public key (see [[#tweaking-the-aggregate-public-key|below]]),
and it can be used to produce an X-only aggregate public key, or a plain aggregate public key.
In order to obtain an X-only public key compatible with BIP340 verification, implementations call the ''GetXonlyPubkey'' function with the KeyAgg Context.
To get the plain aggregate public key, which is required for some applications of [[#tweaking-the-aggregate-public-key|tweaking]], implementations call ''GetPlainPubkey'' instead.
The aggregate public key produced by ''KeyAgg'' (regardless of the type) depends on the order of the individual public keys.
If the application does not have a canonical order of the signers, the individual public keys can be sorted with the ''KeySort'' algorithm to ensure that the aggregate public key is independent of the order of signers.
The same individual public key is allowed to occur more than once in the input of ''KeyAgg'' and ''KeySort''.
This is by design: All algorithms in this proposal handle multiple signers who (claim to) have identical individual public keys properly,
and applications are not required to check for duplicate individual public keys.
In fact, applications are recommended to omit checks for duplicate individual public keys in order to simplify error handling.
Moreover, it is often impossible to tell at key aggregation which signer is to blame for the duplicate, i.e., which signer came up with an individual public key honestly and which disruptive signer copied it.
In contrast, MuSig2 is designed to identify disruptive signers at signing time (see [[#identifying-disruptive-signers|Identifying Disruptive Signers]]).
While the algorithms in this proposal are able to handle duplicate individual public keys, there are scenarios where applications may choose to abort when encountering duplicates.
For example, we can imagine a scenario where a single entity creates a MuSig2 setup with multiple signing devices.
In that case, duplicates may not result from a malicious signing device copying an individual public key of another signing device but from accidental initialization of two devices with the same seed.
Since MuSig2 key aggregation would accept the duplicate keys and not error out, which would in turn reduce the security compared to the intended key setup, applications may reject duplicate individual public keys before passing them to MuSig2 key aggregation and ask the user to investigate.
=== Nonce Generation ===
'''IMPORTANT''': ''NonceGen'' must have access to a high-quality random generator to draw an unbiased, uniformly random value ''rand' ''.
In contrast to BIP340 signing, the values ''k1'' and ''k2'' '''must not be derived deterministically''' from the session parameters because otherwise active adversaries can [https://medium.com/blockstream/musig-dn-schnorr-multisignatures-with-verifiably-deterministic-nonces-27424b5df9d6#e3b6 trick the victim into reusing a nonce].
The optional arguments to ''NonceGen'' enable a defense-in-depth mechanism that may prevent secret key exposure if ''rand' '' is accidentally not drawn uniformly at random.
If the value ''rand' '' was identical in two ''NonceGen'' invocations, but any other argument was different, the ''secnonce'' would still be guaranteed to be different as well (with overwhelming probability), and thus accidentally using the same ''secnonce'' for ''Sign'' in both sessions would be avoided.
Therefore, it is recommended to provide the optional arguments ''sk'', ''aggpk'', and ''m'' if these session parameters are already determined during nonce generation.
The auxiliary input ''extra_in'' can contain additional contextual data that has a chance of changing between ''NonceGen'' runs,
e.g., a supposedly unique session id (taken from the application), a session counter wide enough not to repeat in practice, any nonces by other signers (if already known), or the serialization of a data structure containing multiple of the above.
However, the protection provided by the optional arguments should only be viewed as a last resort.
In most conceivable scenarios, the assumption that the arguments are different between two executions of ''NonceGen'' is relatively strong, particularly when facing an active adversary.
In some applications, it is beneficial to generate and send a ''pubnonce'' before the other signers, their individual public keys, or the message to sign is known.
In this case, only the available arguments are provided to the ''NonceGen'' algorithm.
After this preprocessing phase, the ''Sign'' algorithm can be run immediately when the message and set of signers is determined.
This way, the final signature is created quicker and with fewer round trips.
However, applications that use this method presumably store the nonces for a longer time and must therefore be even more careful not to reuse them.
Moreover, this method is not compatible with the defense-in-depth mechanism described in the previous paragraph.
Instead of every signer broadcasting their ''pubnonce'' to every other signer, the signers can send their ''pubnonce'' to a single aggregator node that runs ''NonceAgg'' and sends the ''aggnonce'' back to the signers.
This technique reduces the overall communication.
A malicious aggregator can force the signing session to fail to produce a valid Schnorr signature but cannot negatively affect the unforgeability of the scheme.
In general, MuSig2 signers are stateful in the sense that they first generate ''secnonce'' and then need to store it until they receive the other signers' ''pubnonces'' or the ''aggnonce''.
However, it is possible for one of the signers to be stateless.
This signer waits until it receives the ''pubnonce'' of all the other signers and until session parameters such as a message to sign, individual public keys, and tweaks are determined.
Then, the signer can run ''NonceGen'', ''NonceAgg'' and ''Sign'' in sequence and send out its ''pubnonce'' along with its partial signature.
Stateless signers may want to consider signing deterministically (see [[#modifications-to-nonce-generation|Modifications to Nonce Generation]]) to remove the reliance on the random number generator in the ''NonceGen'' algorithm.
=== Identifying Disruptive Signers ===
The signing protocol makes it possible to identify malicious signers who send invalid contributions to a signing session in order to make the signing session abort and prevent the honest signers from obtaining a valid signature.
This property is called "identifiable aborts" and ensures that honest parties can assign blame to malicious signers who cause an abort in the signing protocol.
Aborts are identifiable for an honest party if the following conditions hold in a signing session:
* The contributions received from all signers have not been tampered with (e.g., because they were sent over authenticated connections).
* Nonce aggregation is performed honestly (e.g., because the honest signer performs nonce aggregation on its own or because the aggregator is trusted).
* The partial signatures received from all signers are verified using the algorithm ''PartialSigVerify''.
If these conditions hold and an honest party (signer or aggregator) runs an algorithm that fails due to invalid protocol contributions from malicious signers, then the algorithm run by the honest party will output the index of exactly one malicious signer.
Additionally, if the honest parties agree on the contributions sent by all signers in the signing session, all the honest parties who run the aborting algorithm will identify the same malicious signer.
==== Further Remarks ====
Some of the algorithms specified below may also assign blame to a malicious aggregator.
While this is possible for some particular misbehavior of the aggregator, it is not guaranteed that a malicious aggregator can be identified.
More specifically, a malicious aggregator (whose existence violates the second condition above) can always make signing abort and wrongly hold honest signers accountable for the abort (e.g., by claiming to have received an invalid contribution from a particular honest signer).
The only purpose of the algorithm ''PartialSigVerify'' is to ensure identifiable aborts, and it is not necessary to use it when identifiable aborts are not desired.
In particular, partial signatures are ''not'' signatures.
An adversary can forge a partial signature, i.e., create a partial signature without knowing the secret key for the claimed individual public key.Assume an adversary wants to forge a partial signature for individual public key ''P''. It joins the signing session pretending to be two different signers, one with individual public key ''P'' and one with another individual public key. The adversary can then set the second signer's nonce such that it will be able to produce a partial signature for ''P'' but not for the other claimed signer. An explanation of the individual steps required to create a partial signature forgery can be found in [https://gist.github.com/AdamISZ/ca974ed67889cedc738c4a1f65ff620b a write up by Adam Gibson].
However, if ''PartialSigVerify'' succeeds for all partial signatures then ''PartialSigAgg'' will return a valid Schnorr signature.Given a list of individual public keys, it is an open question whether a BIP-340 signature valid under the corresponding aggregate public key is a proof of knowledge of all secret keys of the individual public keys.
=== Tweaking the Aggregate Public Key ===
The aggregate public key can be ''tweaked'', which modifies the key as defined in the [[#tweaking-definition|Tweaking Definition]] subsection.
In order to apply a tweak, the KeyAgg Context output by ''KeyAgg'' is provided to the ''ApplyTweak'' algorithm with the ''is_xonly_t'' argument set to false for plain tweaking and true for X-only tweaking.
The resulting KeyAgg Context can be used to apply another tweak with ''ApplyTweak'' or obtain the aggregate public key with ''GetXonlyPubkey'' or ''GetPlainPubkey''.
The purpose of supporting tweaking is to ensure compatibility with existing uses of tweaking, i.e., that the result of signing is a valid signature for the tweaked public key.
The MuSig2 algorithms take arbitrary tweaks as input but accepting arbitrary tweaks may negatively affect the security of the scheme.It is an open question whether allowing arbitrary tweaks from an adversary affects the unforgeability of MuSig2.
Instead, signers should obtain the tweaks according to other specifications.
This typically involves deriving the tweaks from a hash of the aggregate public key and some other information.
Depending on the specific scheme that is used for tweaking, either the plain or the X-only aggregate public key is required.
For example, to do [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32] derivation, you call ''GetPlainPubkey'' to be able to compute the tweak, whereas [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] TapTweaks require X-only public keys that are obtained with ''GetXonlyPubkey''.
The tweak mode provided to ''ApplyTweak'' depends on the application:
Plain tweaking can be used to derive child public keys from an aggregate public key using [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32].
On the other hand, X-only tweaking is required for Taproot tweaking per [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341].
A Taproot-tweaked public key commits to a ''script path'', allowing users to create transaction outputs that are spendable either with a MuSig2 multi-signature or by providing inputs that satisfy the script path.
Script path spends require a control block that contains a parity bit for the tweaked X-only public key.
The bit can be obtained with ''GetPlainPubkey(keyagg_ctx)[0] & 1''.
== Algorithms ==
The following specification of the algorithms has been written with a focus on clarity.
As a result, the specified algorithms are not always optimal in terms of computation and space.
In particular, some values are recomputed but can be cached in actual implementations (see [[#general-signing-flow|General Signing Flow]]).
=== Notation ===
The following conventions are used, with constants as defined for [https://www.secg.org/sec2-v2.pdf secp256k1]. We note that adapting this proposal to other elliptic curves is not straightforward and can result in an insecure scheme.
* Lowercase variables represent integers or byte arrays.
** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''.
** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''.
* Uppercase variables refer to points on the curve with equation ''y2 = x3 + 7'' over the integers modulo ''p''.
** ''is_infinite(P)'' returns whether ''P'' is the point at infinity.
** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity).
** The constant ''G'' refers to the base point, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''.
** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation].
** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication (⋅) of an integer and a point] refers to the repeated application of the group operation.
* Functions and operations:
** ''||'' refers to byte array concatenation.
** The function ''x[i:j]'', where ''x'' is a byte array and ''i, j ≥ 0'', returns a ''(j - i)''-byte array with a copy of the ''i''-th byte (inclusive) to the ''j''-th byte (exclusive) of ''x''.
** The function ''bytes(n, x)'', where ''x'' is an integer, returns the n-byte encoding of ''x'', most significant byte first.
** The constant ''empty_bytestring'' refers to the empty byte array. It holds that ''len(empty_bytestring) = 0''.
** The function ''xbytes(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''bytes(32, x(P))''.
** The function ''len(x)'' where ''x'' is a byte array returns the length of the array.
** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 == 0''.
** The function ''with_even_y(P)'', where ''P'' is a point, returns ''P'' if ''is_infinite(P)'' or ''has_even_y(P)''. Otherwise, ''with_even_y(P)'' returns ''-P''.
** The function ''cbytes(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''a || xbytes(P)'' where ''a'' is a byte that is ''2'' if ''has_even_y(P)'' and ''3'' otherwise.
** The function ''cbytes_ext(P)'', where ''P'' is a point, returns ''bytes(33, 0)'' if ''is_infinite(P)''. Otherwise, it returns ''cbytes(P)''.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..2256-1'', returns the point ''P'' for which ''x(P) = x''
Given a candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''. and ''has_even_y(P)'', or fails if ''x'' is greater than ''p-1'' or no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Fail if ''x > p-1''.
*** Let ''c = x3 + 7 mod p''.
*** Let ''y' = c(p+1)/4 mod p''.
*** Fail if ''c ≠ y'2 mod p''.
*** Let ''y = y' '' if ''y' mod 2 = 0'', otherwise let ''y = p - y' ''.
*** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y''.
** The function ''cpoint(x)'', where ''x'' is a 33-byte array (compressed serialization), sets ''P = lift_x(int(x[1:33]))'' and fails if that fails. If ''x[0] = 2'' it returns ''P'' and if ''x[0] = 3'' it returns ''-P''. Otherwise, it fails.
** The function ''cpoint_ext(x)'', where ''x'' is a 33-byte array (compressed serialization), returns the point at infinity if ''x = bytes(33, 0)''. Otherwise, it returns ''cpoint(x)'' and fails if that fails.
** The function ''hashtag(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)''.
* Other:
** Tuples are written by listing the elements within parentheses and separated by commas. For example, ''(2, 3, 1)'' is a tuple.
=== Key Generation and Aggregation ===
==== Key Generation of an Individual Signer ====
Algorithm ''IndividualPubkey(sk)'':The ''IndividualPubkey'' algorithm matches the key generation procedure traditionally used for ECDSA in Bitcoin
* Inputs:
** The secret key ''sk'': a 32-byte array, freshly generated uniformly at random
* Let ''d' = int(sk)''.
* Fail if ''d' = 0'' or ''d' ≥ n''.
* Return ''cbytes(d'⋅G)''.
==== KeyAgg Context ====
The KeyAgg Context is a data structure consisting of the following elements:
* The point ''Q'' representing the potentially tweaked aggregate public key: an elliptic curve point
* The accumulated tweak ''tacc'': an integer with ''0 ≤ tacc < n''
* The value ''gacc'' : 1 or -1 mod n
We write "Let ''(Q, gacc, tacc) = keyagg_ctx''" to assign names to the elements of a KeyAgg Context.
Algorithm ''KeySort(pk1..u)'':
* Inputs:
** The number ''u'' of individual public keys with ''0 < u < 2^32''
** The individual public keys ''pk1..u'': ''u'' 33-byte arrays
* Return ''pk1..u'' sorted in lexicographical order.
==== Key Aggregation ====
Algorithm ''KeyAgg(pk1..u)'':
* Inputs:
** The number ''u'' of individual public keys with ''0 < u < 2^32''
** The individual public keys ''pk1..u'': ''u'' 33-byte arrays
* Let ''pk2 = GetSecondKey(pk1..u)''
* For ''i = 1 .. u'':
** Let ''Pi = cpoint(pki)''; fail if that fails and blame signer ''i'' for invalid individual public key.
** Let ''ai = KeyAggCoeffInternal(pk1..u, pki, pk2)''.
* Let ''Q = a1⋅P1 + a2⋅P2 + ... + au⋅Pu''
* Fail if ''is_infinite(Q)''.
* Let ''gacc = 1''
* Let ''tacc = 0''
* Return ''keyagg_ctx = (Q, gacc, tacc)''.
Internal Algorithm ''KeyAggCoeffInternal(pk1..u, pk', pk2)'':
* Let ''L = HashKeys(pk1..u)''
* If ''pk' = pk2'':
** Return 1
* Return ''int(hashKeyAgg coefficient(L || pk')) mod n''The key aggregation coefficient is computed by hashing the individual public key instead of its index, which requires one more invocation of the SHA-256 compression function. However, it results in significantly simpler implementations because signers do not need to translate between public key indices before and after sorting.
==== Applying Tweaks ====
Algorithm ''ApplyTweak(keyagg_ctx, tweak, is_xonly_t)'':
* Inputs:
** The ''keyagg_ctx'': a [[#keyagg-context|KeyAgg Context]] data structure
** The ''tweak'': a 32-byte array
** The tweak mode ''is_xonly_t'': a boolean
* Let ''(Q, gacc, tacc) = keyagg_ctx''
* If ''is_xonly_t'' and ''not has_even_y(Q)'':
** Let ''g = -1 mod n''
* Else:
** Let ''g = 1''
* Let ''t = int(tweak)''; fail if ''t ≥ n''
* Let ''Q' = g⋅Q + t⋅G''
** Fail if ''is_infinite(Q')''
* Let ''gacc' = g⋅gacc mod n''
* Let ''tacc' = t + g⋅tacc mod n''
* Return ''keyagg_ctx' = (Q', gacc', tacc')''
=== Nonce Generation ===
Algorithm ''NonceGen(sk, pk, aggpk, m, extra_in)'':
* Inputs:
** The secret signing key ''sk'': a 32-byte array (optional argument)
** The individual public key ''pk'': a 33-byte array (see [[#signing-with-tweaked-individual-keys|Signing with Tweaked Individual Keys]] for the reason that this argument is mandatory)
** The x-only aggregate public key ''aggpk'': a 32-byte array (optional argument)
** The message ''m'': a byte array (optional argument)In theory, the allowed message size is restricted because SHA256 accepts byte strings only up to size of 2^61-1 bytes (and because of the 8-byte length encoding).
** The auxiliary input ''extra_in'': a byte array with ''0 ≤ len(extra_in) ≤ 232-1'' (optional argument)
* Let ''rand' '' be a 32-byte array freshly drawn uniformly at random
* If the optional argument ''sk'' is present:
** Let ''rand'' be the byte-wise xor of ''sk'' and ''hashMuSig/aux(rand')''The random data is hashed (with a unique tag) as a precaution against situations where the randomness may be correlated with the secret signing key itself. It is xored with the secret key (rather than combined with it in a hash) to reduce the number of operations exposed to the actual secret key.
* Else:
** Let ''rand = rand' ''
* If the optional argument ''aggpk'' is not present:
** Let ''aggpk = empty_bytestring''
* If the optional argument ''m'' is not present:
** Let ''m_prefixed = bytes(1, 0)''
* Else:
** Let ''m_prefixed = bytes(1, 1) || bytes(8, len(m)) || m''
* If the optional argument ''extra_in'' is not present:
** Let ''extra_in = empty_bytestring''
* Let ''ki = int(hashMuSig/nonce(rand || bytes(1, len(pk)) || pk || bytes(1, len(aggpk)) || aggpk || m_prefixed || bytes(4, len(extra_in)) || extra_in || bytes(1, i - 1))) mod n'' for ''i = 1,2''
* Fail if ''k1 = 0'' or ''k2 = 0''
* Let ''R⁎,1 = k1⋅G, R⁎,2 = k2⋅G''
* Let ''pubnonce = cbytes(R⁎,1) || cbytes(R⁎,2)''
* Let ''secnonce = bytes(32, k1) || bytes(32, k2) || pk''The algorithms as specified here assume that the ''secnonce'' is stored as a 97-byte array using the serialization ''secnonce = bytes(32, k1) || bytes(32, k2) || pk''. The same format is used in the reference implementation and in the test vectors. However, since the ''secnonce'' is (obviously) not meant to be sent over the wire, compatibility between implementations is not a concern, and this method of storing the ''secnonce'' is merely a suggestion.
The ''secnonce'' is effectively a local data structure of the signer which comprises the value triple ''(k1, k2, pk)'', and implementations may choose any suitable method to carry it from ''NonceGen'' (first communication round) to ''Sign'' (second communication round). In particular, implementations may choose to hide the ''secnonce'' in internal state without exposing it in an API explicitly, e.g., in an effort to prevent callers from reusing a ''secnonce'' accidentally.
* Return ''(secnonce, pubnonce)''
=== Nonce Aggregation ===
Algorithm ''NonceAgg(pubnonce1..u)'':
* Inputs:
** The number ''u'' of ''pubnonces'' with ''0 < u < 2^32''
** The public nonces ''pubnonce1..u'': ''u'' 66-byte arrays
* For ''j = 1 .. 2'':
** For ''i = 1 .. u'':
*** Let ''Ri,j = cpoint(pubnoncei[(j-1)*33:j*33])''; fail if that fails and blame signer ''i'' for invalid ''pubnonce''.
** Let ''Rj = R1,j + R2,j + ... + Ru,j''
* Return ''aggnonce = cbytes_ext(R1) || cbytes_ext(R2)''
=== Session Context ===
The Session Context is a data structure consisting of the following elements:
* The aggregate public nonce ''aggnonce'': a 66-byte array
* The number ''u'' of individual public keys with ''0 < u < 2^32''
* The individual public keys ''pk1..u'': ''u'' 33-byte arrays
* The number ''v'' of tweaks with ''0 ≤ v < 2^32''
* The tweaks ''tweak1..v'': ''v'' 32-byte arrays
* The tweak modes ''is_xonly_t1..v'' : ''v'' booleans
* The message ''m'': a byte array
We write "Let ''(aggnonce, u, pk1..u, v, tweak1..v, is_xonly_t1..v, m) = session_ctx''" to assign names to the elements of a Session Context.
Algorithm ''GetSessionValues(session_ctx)'':
* Let ''(aggnonce, u, pk1..u, v, tweak1..v, is_xonly_t1..v, m) = session_ctx''
* Let ''keyagg_ctx0 = KeyAgg(pk1..u)''; fail if that fails
* For ''i = 1 .. v'':
** Let ''keyagg_ctxi = ApplyTweak(keyagg_ctxi-1, tweaki, is_xonly_ti)''; fail if that fails
* Let ''(Q, gacc, tacc) = keyagg_ctxv''
* Let ''b = int(hashMuSig/noncecoef(aggnonce || xbytes(Q) || m)) mod n''
* Let ''R1 = cpoint_ext(aggnonce[0:33]), R2 = cpoint_ext(aggnonce[33:66])''; fail if that fails and blame nonce aggregator for invalid ''aggnonce''.
* Let ''R' = R1 + b⋅R2''
* If ''is_infinite(R'):
** Let final nonce ''R = G'' (see [[#dealing-with-infinity-in-nonce-aggregation|Dealing with Infinity in Nonce Aggregation]])
* Else:
** Let final nonce ''R = R' ''
* Let ''e = int(hashBIP0340/challenge(xbytes(R) || xbytes(Q) || m)) mod n''
* Return ''(Q, gacc, tacc, b, R, e)''
Algorithm ''GetSessionKeyAggCoeff(session_ctx, P)'':
* Let ''(_, u, pk1..u, _, _, _, _) = session_ctx''
* Let ''pk = cbytes(P)''
* Fail if ''pk'' not in ''pk1..u''
* Return ''KeyAggCoeff(pk1..u, pk)''
=== Signing ===
Algorithm ''Sign(secnonce, sk, session_ctx)'':
* Inputs:
** The secret nonce ''secnonce'' that has never been used as input to ''Sign'' before: a 97-byte array
** The secret key ''sk'': a 32-byte array
** The ''session_ctx'': a [[#session-context|Session Context]] data structure
* Let ''(Q, gacc, _, b, R, e) = GetSessionValues(session_ctx)''; fail if that fails
* Let ''k1' = int(secnonce[0:32]), k2' = int(secnonce[32:64])''
* Fail if ''ki' = 0'' or ''ki' ≥ n'' for ''i = 1..2''
* Let ''k1 = k1', k2 = k2' '' if ''has_even_y(R)'', otherwise let ''k1 = n - k1', k2 = n - k2' ''
* Let ''d' = int(sk)''
* Fail if ''d' = 0'' or ''d' ≥ n''
* Let ''P = d'⋅G''
* Let ''pk = cbytes(P)''
* Fail if ''pk ≠ secnonce[64:97]''
* Let ''a = GetSessionKeyAggCoeff(session_ctx, P)''; fail if that failsFailing ''Sign'' when ''GetSessionKeyAggCoeff(session_ctx, P)'' fails is not necessary for unforgeability. It merely indicates to the caller that the scheme is not being used correctly.
* Let ''g = 1'' if ''has_even_y(Q)'', otherwise let ''g = -1 mod n''
* Let ''d = g⋅gacc⋅d' mod n'' (See [[#negation-of-the-secret-key-when-signing|Negation Of The Secret Key When Signing]])
* Let ''s = (k1 + b⋅k2 + e⋅a⋅d) mod n''
* Let ''psig = bytes(32, s)''
* Let ''pubnonce = cbytes(k1'⋅G) || cbytes(k2'⋅G)''
* If ''PartialSigVerifyInternal(psig, pubnonce, pk, session_ctx)'' (see below) returns failure, failVerifying the signature before leaving the signer prevents random or adversarially provoked computation errors. This prevents publishing invalid signatures which may leak information about the secret key. It is recommended but can be omitted if the computation cost is prohibitive.
* Return partial signature ''psig''
=== Partial Signature Verification ===
Algorithm ''PartialSigVerify(psig, pubnonce1..u, pk1..u, tweak1..v, is_xonly_t1..v, m, i)'':
* Inputs:
** The partial signature ''psig'': a 32-byte array
** The number ''u'' of public nonces and individual public keys with ''0 < u < 2^32''
** The public nonces ''pubnonce1..u'': ''u'' 66-byte arrays
** The individual public keys ''pk1..u'': ''u'' 33-byte arrays
** The number ''v'' of tweaks with ''0 ≤ v < 2^32''
** The tweaks ''tweak1..v'': ''v'' 32-byte arrays
** The tweak modes ''is_xonly_t1..v'' : ''v'' booleans
** The message ''m'': a byte array
** The index of the signer ''i'' in the of public nonces and individual public keys with ''0 < i ≤ u''
* Let ''aggnonce = NonceAgg(pubnonce1..u)''; fail if that fails
* Let ''session_ctx = (aggnonce, u, pk1..u, v, tweak1..v, is_xonly_t1..v, m)''
* Run ''PartialSigVerifyInternal(psig, pubnoncei, pki, session_ctx)''
* Return success iff no failure occurred before reaching this point.
Internal Algorithm ''PartialSigVerifyInternal(psig, pubnonce, pk, session_ctx)'':
* Let ''(Q, gacc, _, b, R, e) = GetSessionValues(session_ctx)''; fail if that fails
* Let ''s = int(psig)''; fail if ''s ≥ n''
* Let ''R⁎,1 = cpoint(pubnonce[0:33]), R⁎,2 = cpoint(pubnonce[33:66])''
* Let ''Re⁎' = R⁎,1 + b⋅R⁎,2''
* Let effective nonce ''Re⁎ = Re⁎' '' if ''has_even_y(R)'', otherwise let ''Re⁎ = -Re⁎' ''
* Let ''P = cpoint(pk)''; fail if that fails
* Let ''a = GetSessionKeyAggCoeff(session_ctx, P)''''GetSessionKeyAggCoeff(session_ctx, P)'' cannot fail when called from ''PartialSigVerifyInternal''.
* Let ''g = 1'' if ''has_even_y(Q)'', otherwise let ''g = -1 mod n''
* Let ''g' = g⋅gacc mod n'' (See [[#negation-of-the-individual-public-key-when-partially-verifying|Negation Of The Individual Public Key When Partially Verifying]])
* Fail if ''s⋅G ≠ Re⁎ + e⋅a⋅g'⋅P''
* Return success iff no failure occurred before reaching this point.
=== Partial Signature Aggregation ===
Algorithm ''PartialSigAgg(psig1..u, session_ctx)'':
* Inputs:
** The number ''u'' of signatures with ''0 < u < 2^32''
** The partial signatures ''psig1..u'': ''u'' 32-byte arrays
** The ''session_ctx'': a [[#session-context|Session Context]] data structure
* Let ''(Q, _, tacc, _, _, R, e) = GetSessionValues(session_ctx)''; fail if that fails
* For ''i = 1 .. u'':
** Let ''si = int(psigi)''; fail if ''si ≥ n'' and blame signer ''i'' for invalid partial signature.
* Let ''g = 1'' if ''has_even_y(Q)'', otherwise let ''g = -1 mod n''
* Let ''s = s1 + ... + su + e⋅g⋅tacc mod n''
* Return ''sig = ''xbytes(R) || bytes(32, s)''
=== Test Vectors and Reference Code ===
We provide a naive, highly inefficient, and non-constant time [[bip-0327/reference.py|pure Python 3 reference implementation of the key aggregation, partial signing, and partial signature verification algorithms]].
Standalone JSON test vectors are also available in the [[bip-0327|same directory]], to facilitate porting the test vectors into other implementations.
The reference implementation is for demonstration purposes only and not to be used in production environments.
== Remarks on Security and Correctness ==
=== Signing with Tweaked Individual Keys ===
The scheme in this proposal has been designed to be secure
even if signers tweak their individual secret keys with tweaks known to the adversary (e.g., as in BIP32 unhardened derivation)
before providing the corresponding individual public keys as input to key aggregation.
In particular, the scheme as specified above requires each signer to provide a final individual public key ''pk'' already to ''NonceGen'',
which writes it into the ''secnonce'' array
so that it can be checked against ''IndividualPubkey(sk)'' in the ''Sign'' algorithm.
The purpose of this check in ''Sign'' is to ensure that ''pk'',
and thus the secret key ''sk'' that will be provided to ''Sign'',
is determined before the signer sends out the ''pubnonce''.
If the check in ''Sign'' was omitted,
and a signer supported signing with at least two different secret keys ''sk1'' and ''sk2''
which have been obtained via tweaking another secret key with tweaks known to the adversary,
then the adversary could, after having seen the ''pubnonce'',
influence whether ''sk1'' or ''sk2'' is provided to ''Sign''.
This degree of freedom may allow the adversary to perform a generalized birthday attack and thereby forge a signature
(see [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-October/021000.html bitcoin-dev mailing list post] and [https://github.com/jonasnick/musig2-tweaking writeup] for details).
Checking ''pk'' against ''IndividualPubkey(sk)'' is a simple way to ensure
that the secret key provided to ''Sign'' is fully determined already when ''NonceGen'' is invoked.
This removes the adversary's ability to influence the secret key after having seen the ''pubnonce''
and thus rules out the attack.Ensuring that the secret key provided to ''Sign'' is fully determined already when ''NonceGen'' is invoked is a simple policy to rule out the attack,
but more flexible polices are conceivable.
In fact, if the signer uses nothing but the message to be signed and the list of the individual public keys of all signers to decide which secret key to use,
then it is not a problem that the adversary can influence this decision after having seen the ''pubnonce''.
More formally, consider modified algorithms ''NonceGen' '' and ''Sign' '', where ''NonceGen' '' does not take the individual public key of the signer as input and does not store it in pubnonce, and Sign' does not check read the individual public key from pubnonce and does not check it against the secret key taken as input.
Then it suffices that for each invocation of ''NonceGen' '' with output ''(secnonce, pubnonce)'',
a function ''fsk'' is determined before sending out ''pubnonce'',
where ''fsk'' maps a pair consisting of a list of individual public keys and a message to a secret key,
such that the secret key ''sk'' and the session context ''session_ctx = (_, _, pk1..u, _, _, _, m)''
provided to the corresponding invocation of ''Sign'(secnonce, sk, session_ctx)'',
adhere to the condition ''fsk(pk1..u, m) = sk''.
However, this requirement is complex and hard to enforce in implementations.
The algorithms ''NonceGen'' and ''Sign'' specified in this BIP are effectively restricted to constant functions ''fsk(_, _) = sk''.
In other words, their usage ensure that the secret key ''sk'' of the signers is determined entirely when invoking ''NonceGen'',
which is enforced easily by letting ''NonceGen'' take the corresponding individual public key ''pk'' as input and checking ''pk'' against ''IndividualPubKey(sk)'' in ''Sign''.
Note that the scheme as given in the [https://eprint.iacr.org/2020/1261 MuSig2 paper] does not perform the check in ''Sign''.
However, the security model in the paper does not cover tweaking at all and assumes a single fixed secret key.
=== Modifications to Nonce Generation ===
Implementers must avoid modifying the ''NonceGen'' algorithm without being fully aware of the implications.
We provide two modifications to ''NonceGen'' that are secure when applied correctly and may be useful in special circumstances, summarized in the following table.
{| class="wikitable" style="margin:auto"
! !! needs secure randomness !! needs secure counter !! needs to keep state securely !! needs aggregate nonce of all other signers (only possible for one signer)
|-
! NonceGen || ✓ || || ✓ ||
|-
! CounterNonceGen || || ✓ || ✓ ||
|-
! DeterministicSign || || || || ✓
|}
First, on systems where obtaining uniformly random values is much harder than maintaining a global atomic counter, it can be beneficial to modify ''NonceGen''.
The resulting algorithm ''CounterNonceGen'' does not draw ''rand' '' uniformly at random but instead sets ''rand' '' to the value of an atomic counter that is incremented whenever it is read.
With this modification, the secret signing key ''sk'' of the signer generating the nonce is '''not''' an optional argument and must be provided to ''NonceGen''.
The security of the resulting scheme then depends on the requirement that reading the counter must never yield the same counter value in two ''NonceGen'' invocations with the same ''sk''.
Second, if there is a unique signer who is supposed to send the ''pubnonce'' last, it is possible to modify nonce generation for this single signer to not require high-quality randomness.
Such a nonce generation algorithm ''DeterministicSign'' is specified below.
Note that the only optional argument is ''rand'', which can be omitted if randomness is entirely unavailable.
''DeterministicSign'' requires the argument ''aggothernonce'' which should be set to the output of ''NonceAgg'' run on the ''pubnonce'' value of '''all''' other signers (but can be provided by an untrusted party).
Hence, using ''DeterministicSign'' is only possible for the last signer to generate a nonce and makes the signer stateless, similar to the stateless signer described in the [[#nonce-generation|Nonce Generation]] section.
==== Deterministic and Stateless Signing for a Single Signer ====
Algorithm ''DeterministicSign(sk, aggothernonce, pk1..u, tweak1..v, is_xonly_t1..v, m, rand)'':
* Inputs:
** The secret signing key ''sk'': a 32-byte array
** The aggregate public nonce ''aggothernonce'' (see [[#modifications-to-nonce-generation|above]]): a 66-byte array
** The number ''u'' of individual public keys with ''0 < u < 2^32''
** The individual public keys ''pk1..u'': ''u'' 33-byte arrays
** The number ''v'' of tweaks with ''0 ≤ v < 2^32''
** The tweaks ''tweak1..v'': ''v'' 32-byte arrays
** The tweak methods ''is_xonly_t1..v'': ''v'' booleans
** The message ''m'': a byte array
** The auxiliary randomness ''rand'': a 32-byte array (optional argument)
* If the optional argument ''rand'' is present:
** Let ''sk' '' be the byte-wise xor of ''sk'' and ''hashMuSig/aux(rand)''
* Else:
** Let ''sk' = sk''
* Let ''keyagg_ctx0 = KeyAgg(pk1..u)''; fail if that fails
* For ''i = 1 .. v'':
** Let ''keyagg_ctxi = ApplyTweak(keyagg_ctxi-1, tweaki, is_xonly_ti)''; fail if that fails
* Let ''aggpk = GetXonlyPubkey(keyagg_ctxv)''
* Let ''ki = int(hashMuSig/deterministic/nonce(sk' || aggothernonce || aggpk || bytes(8, len(m)) || m || bytes(1, i - 1))) mod n'' for ''i = 1,2''
* Fail if ''k1 = 0'' or ''k2 = 0''
* Let ''R⁎,1 = k1⋅G, R⁎,2 = k2⋅G''
* Let ''pubnonce = cbytes(R⁎,1) || cbytes(R⁎,2)''
* Let ''d = int(sk)''
* Fail if ''d = 0'' or ''d ≥ n''
* Let ''pk = cbytes(d⋅G)''
* Let ''secnonce = bytes(32, k1) || bytes(32, k2) || pk''
* Let ''aggnonce = NonceAgg((pubnonce, aggothernonce))''; fail if that fails and blame nonce aggregator for invalid ''aggothernonce''.
* Let ''session_ctx = (aggnonce, u, pk1..u, v, tweak1..v, is_xonly_t1..v, m)''
* Return ''(pubnonce, Sign(secnonce, sk, session_ctx))''
=== Tweaking Definition ===
Two modes of tweaking the aggregate public key are supported. They correspond to the following algorithms:
Algorithm ''ApplyPlainTweak(P, t)'':
* Inputs:
** ''P'': a point
** The tweak ''t'': an integer with ''0 ≤ t < n ''
* Return ''P + t⋅G''
=== Negation Of The Secret Key When Signing ===
In order to produce a partial signature for an X-only aggregate public key that is an aggregate of ''u'' individual public keys and tweaked ''v'' times (X-only or plain), the ''[[#Sign negation|Sign]]'' algorithm may need to negate the secret key during the signing process.
The following elliptic curve points arise as intermediate steps when creating a signature:
• ''Pi'' as computed in ''KeyAgg'' is the point corresponding to the ''i''-th signer's individual public key. Defining ''di' '' to be the ''i''-th signer's secret key as an integer, i.e., the ''d' '' value as computed in the ''Sign'' algorithm of the ''i''-th signer, we have
''Pi = di'⋅G ''.
• ''Q0'' is the aggregate of the individual public keys. It is identical to value ''Q'' computed in ''KeyAgg'' and therefore defined as
''Q0 = a1⋅P1 + a2⋅P2 + ... + au⋅Pu''.
• ''Qi'' is the tweaked aggregate public key after the ''i''-th execution of ''ApplyTweak'' for ''1 ≤ i ≤ v''. It holds that
''Qi = f(i-1) + ti⋅G'' for ''i = 1, ..., v'' where
''f(i-1) := with_even_y(Qi-1)'' if ''is_xonly_ti'' and
''f(i-1) := Qi-1'' otherwise.
• ''with_even_y(Qv)'' is the final result of the key aggregation and tweaking operations. It corresponds to the output of ''GetXonlyPubkey'' applied on the final KeyAgg Context.
The signer's goal is to produce a partial signature corresponding to the final result of key aggregation and tweaking, i.e., the X-only public key ''with_even_y(Qv)''.
For ''1 ≤ i ≤ v'', we denote the value ''g'' computed in the ''i''-th execution of ''ApplyTweak'' by ''gi-1''. Therefore, ''gi-1'' is ''-1 mod n'' if and only if ''is_xonly_ti'' is true and ''Qi-1'' has an odd Y coordinate. In other words, ''gi-1'' indicates whether ''Qi-1'' needed to be negated to apply an X-only tweak:
''f(i-1) = gi-1⋅Qi-1'' for ''1 ≤ i ≤ v''.
Furthermore, the ''Sign'' and ''PartialSigVerify'' algorithms set value ''g'' depending on whether ''Qv'' needed to be negated to produce the (X-only) final output. For consistency, this value ''g'' is referred to as ''gv'' in this section.
''with_even_y(Qv) = gv⋅Qv''.
So, the (X-only) final public key is
''with_even_y(Qv)
= gv⋅Qv
= gv⋅(f(v-1) + tv⋅G)
= gv⋅(gv-1⋅(f(v-2) + tv-1⋅G) + tv⋅G)
= gv⋅gv-1⋅f(v-2) + gv⋅(tv + gv-1⋅tv-1)⋅G
= gv⋅gv-1⋅f(v-2) + (sumi=v-1..v ti⋅prodj=i..v gj)⋅G
= gv⋅gv-1⋅...⋅g1⋅f(0) + (sumi=1..v ti⋅prodj=i..v gj)⋅G
= gv⋅...⋅g0⋅Q0 + gv⋅taccv⋅G''
where ''tacci'' is computed by ''KeyAgg'' and ''ApplyTweak'' as follows:
''tacc0 = 0
tacci = ti + gi-1⋅tacci-1 for i=1..v mod n''
for which it holds that ''gv⋅taccv = sumi=1..v ti⋅prodj=i..v gj''.
''KeyAgg'' and ''ApplyTweak'' compute
''gacc0 = 1
gacci = gi-1⋅gacci-1 for i=1..v mod n''
So we can rewrite above equation for the final public key as
''with_even_y(Qv) = gv⋅gaccv⋅Q0 + gv⋅taccv⋅G''.
Then we have
''with_even_y(Qv) - gv⋅taccv⋅G
= gv⋅gaccv⋅Q0
= gv⋅gaccv⋅(a1⋅P1 + ... + au⋅Pu)
= gv⋅gaccv⋅(a1⋅d1'⋅G + ... + au⋅du'⋅G)
= sumi=1..u(gv⋅gaccv⋅ai⋅di')*G''.
Intuitively, ''gacci'' tracks accumulated sign flipping and ''tacci'' tracks the accumulated tweak value after applying the first ''i'' individual tweaks. Additionally, ''gv'' indicates whether ''Qv'' needed to be negated to produce the final X-only result. Thus, signer ''i'' multiplies its secret key ''di' '' with ''gv⋅gaccv'' in the ''[[#Sign negation|Sign]]'' algorithm.
==== Negation Of The Individual Public Key When Partially Verifying ====
As explained in [[#negation-of-the-secret-key-when-signing|Negation Of The Secret Key When Signing]] the signer uses a possibly negated secret key
''d = gv⋅gaccv⋅d' mod n''
when producing a partial signature to ensure that the aggregate signature will correspond to an aggregate public key with even Y coordinate.
The ''[[#SigVerify negation|PartialSigVerifyInternal]]'' algorithm is supposed to check
''s⋅G = Re⁎ + e⋅a⋅d⋅G''.
The verifier doesn't have access to ''d⋅G'' but can construct it using the individual public key ''pk'' as follows:
''d⋅G
= gv⋅gaccv⋅d'⋅G
= gv⋅gaccv⋅cpoint(pk)''
Note that the aggregate public key and list of tweaks are inputs to partial signature verification, so the verifier can also construct ''gv'' and ''gaccv''.
=== Dealing with Infinity in Nonce Aggregation ===
If the nonce aggregator provides ''aggnonce = bytes(33,0) || bytes(33,0)'', either the nonce aggregator is dishonest or there is at least one dishonest signer (except with negligible probability).
If signing aborted in this case, it would be impossible to determine who is dishonest.
Therefore, signing continues so that the culprit is revealed when collecting and verifying partial signatures.
However, the final nonce ''R'' of a BIP340 Schnorr signature cannot be the point at infinity.
If we would nonetheless allow the final nonce to be the point at infinity, then the scheme would lose the following property:
if ''PartialSigVerify'' succeeds for all partial signatures, then ''PartialSigAgg'' will return a valid Schnorr signature.
Since this is a valuable feature, we modify MuSig2* (which is defined in the appendix of the [https://eprint.iacr.org/2020/1261 MuSig2 paper]) to avoid producing an invalid Schnorr signature while still allowing detection of the dishonest signer: In ''GetSessionValues'', if the final nonce ''R'' would be the point at infinity, set it to the generator instead (an arbitrary choice).
This modification to ''GetSessionValues'' does not affect the unforgeability of the scheme.
Given a successful adversary against the unforgeability game (EUF-CMA) for the modified scheme, a reduction can win the unforgeability game for the original scheme by simulating the modification towards the adversary:
When the adversary provides ''aggnonce' = bytes(33, 0) || bytes(33, 0)'', the reduction sets ''aggnonce = cbytes_ext(G) || bytes(33, 0)''.
For any other ''aggnonce' '', the reduction sets ''aggnonce = aggnonce' ''.
(The case that the adversary provides an ''aggnonce' ≠ bytes(33, 0) || bytes(33, 0) '' but nevertheless ''R' '' in ''GetSessionValues'' is the point at infinity happens only with negligible probability.)
=== Choosing the Size of the Nonce ===
The [https://eprint.iacr.org/2020/1261 MuSig2 paper] contains two security proofs that apply to different variants of the scheme.
The first proof relies on the random oracle model (ROM) and applies to a scheme variant where each signer's nonce consists of four elliptic curve points.
The second proof requires a stronger model, namely the combination of the ROM and the algebraic group model (AGM),
and applies to an optimized scheme variant where the signers' nonces consist of only two points.
This proposal uses the latter, optimized scheme variant.
Relying on the stronger model is a legitimate choice for the following reasons:
First, an approach widely taken is interpreting a Forking Lemma proof in the ROM merely as design justification and ignoring the loss of security due to the Forking Lemma.
If one believes in this approach, then the ROM may not be the optimal model in the first place because some parts of the concrete security bound are arbitrarily ignored.
One may just as well move to the ROM+AGM model, which produces bounds close to the best-known attacks, e.g., for Schnorr signatures.
Second, as of this writing, there is no instance of a serious cryptographic scheme with a security proof in the AGM that is not secure in practice.
There are, however, insecure toy schemes with AGM security proofs, but those explicitly violate the requirements of the AGM.
[https://eprint.iacr.org/2022/226.pdf Broken AGM proofs of toy schemes] provide group elements to the adversary without declaring them as group element inputs.
In contrast, in MuSig2, all group elements that arise in the scheme are known to the adversary and declared as group element inputs.
A scheme very similar to MuSig2 and with two-point nonces was independently proven secure in the ROM and AGM by [https://eprint.iacr.org/2020/1245 Alper and Burdges].
== Backwards Compatibility ==
This document proposes a standard for the MuSig2 multi-signature scheme that is compatible with [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340].
MuSig2 is ''not'' compatible with ECDSA signatures traditionally used in Bitcoin.
== Changelog ==
To help implementers understand updates to this document, we attach a version number that resembles ''semantic versioning'' (MAJOR.MINOR.PATCH).
The MAJOR version is incremented if changes to the BIP are introduced that are incompatible with prior versions.
An exception to this rule is MAJOR version zero (0.y.z) which is for development and does not need to be incremented if backwards incompatible changes are introduced.
The MINOR version is incremented whenever the inputs or the output of an algorithm changes in a backward-compatible way or new backward-compatible functionality is added.
The PATCH version is incremented for other changes that are noteworthy (bug fixes, test vectors, important clarifications, etc.).
* '''1.0.3''' (2026-01-05):
** Fix minor bugs in the specification of ''DeterministicSign''.
* '''1.0.2''' (2024-07-22):
** Fix minor bug in the specification of ''DeterministicSign'' and add small improvement to a ''PartialSigAgg'' test vector.
* '''1.0.1''' (2024-05-14):
** Fix minor issue in ''PartialSigVerify'' vectors.
* '''1.0.0''' (2023-03-26):
** Number 327 was assigned to this BIP.
* '''1.0.0-rc.4''' (2023-03-02):
** Add expected value of ''pubnonce'' to ''NonceGen'' test vectors.
* '''1.0.0-rc.3''' (2023-02-28):
** Improve ''NonceGen'' test vectors by not using an all-zero hex string as ''rand_'' values. This change addresses potential issues in some implementations that interpret this as a special value indicating uninitialized memory or a broken random number generator and therefore return an error.
** Fix invalid length of a ''pubnonce'' in the ''PartialSigVerify'' test vectors.
** Improve ''KeySort'' test vector.
** Add explicit ''IndividualPubkey'' algorithm.
** Rename KeyGen Context to KeyAgg Context.
* '''1.0.0-rc.2''' (2022-10-28):
** Fix vulnerability that can occur in certain unusual scenarios (see [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-October/021000.html bitcoin-dev mailing list]: Add mandatory ''pk'' argument to ''NonceGen'', append ''pk'' to ''secnonce'' and check in ''Sign'' that the ''pk'' in ''secnonce'' matches. Update test vectors.
** Make sure that signer's key is in list of individual public keys by adding failure case to ''GetSessionKeyAggCoeff'' and add test vectors.
* '''1.0.0-rc.1''' (2022-10-03): Submit draft BIP to the BIPs repository
* '''0.8.6''' (2022-09-15): Clarify that implementations do not need to support every feature and add a test vector for signing with a tweaked key
* '''0.8.5''' (2022-09-05): Rename some functions to improve clarity.
* '''0.8.4''' (2022-09-02): Make naming of nonce variants ''R'' in specifications of the algorithms and reference code easier to read and more consistent.
* '''0.8.3''' (2022-09-01): Overwrite ''secnonce'' in ''sign'' reference implementation to help prevent accidental reuse and add test vector for invalid ''secnonce''.
* '''0.8.2''' (2022-08-30): Fix ''KeySort'' input length and add test vectors
* '''0.8.1''' (2022-08-26): Add ''DeterministicSign'' algorithm
* '''0.8.0''' (2022-08-26): Switch from X-only to plain public key for individual public keys. This requires updating a large portion of the test vectors.
* '''0.7.2''' (2022-08-17): Add ''NonceGen'' and ''Sign/PartialSigVerify'' test vectors for messages longer than 32 bytes.
* '''0.7.1''' (2022-08-10): Extract test vectors into separate JSON file.
* '''0.7.0''' (2022-07-31): Change ''NonceGen'' such that output when message is not present is different from when message is present but has length 0.
* '''0.6.0''' (2022-07-31): Allow variable length messages, change serialization of the message in the ''NonceGen'' hash function, and add test vectors
* '''0.5.2''' (2022-06-26): Fix ''aggpk'' in ''NonceGen'' test vectors.
* '''0.5.1''' (2022-06-22): Rename "ordinary" tweaking to "plain" tweaking.
* '''0.5.0''' (2022-06-21): Separate ApplyTweak from KeyAgg and introduce KeyGen Context.
* '''0.4.0''' (2022-06-20): Allow the output of NonceAgg to be infinity and add test vectors
* '''0.3.2''' (2022-06-02): Add a lot of test vectors and improve handling of invalid contributions in reference code.
* '''0.3.1''' (2022-05-24): Add ''NonceGen'' test vectors
* '''0.3.0''' (2022-05-24): Hash ''i - 1'' instead of ''i'' in ''NonceGen''
* '''0.2.0''' (2022-05-19): Change order of arguments in ''NonceGen'' hash function
* '''0.1.0''' (2022-05-19): Publication of draft BIP on the bitcoin-dev mailing list
== Footnotes ==
== Acknowledgements ==
We thank Brandon Black, Riccardo Casatta, Sivaram Dhakshinamoorthy, Lloyd Fournier, Russell O'Connor, and Pieter Wuille for their contributions to this document.
================================================
FILE: bip-0328/_base58.py
================================================
"""
Base 58 conversion utilities
****************************
"""
#
# base58.py
# Original source: git://github.com/joric/brutus.git
# which was forked from git://github.com/samrushing/caesure.git
#
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
from binascii import hexlify, unhexlify
from typing import List
from _common import hash256
b58_digits: str = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def encode(b: bytes) -> str:
"""
Encode bytes to a base58-encoded string
:param b: Bytes to encode
:return: Base58 encoded string of ``b``
"""
# Convert big-endian bytes to integer
n: int = int('0x0' + hexlify(b).decode('utf8'), 16)
# Divide that integer into base58
temp: List[str] = []
while n > 0:
n, r = divmod(n, 58)
temp.append(b58_digits[r])
res: str = ''.join(temp[::-1])
# Encode leading zeros as base58 zeros
czero: int = 0
pad: int = 0
for c in b:
if c == czero:
pad += 1
else:
break
return b58_digits[0] * pad + res
def decode(s: str) -> bytes:
"""
Decode a base58-encoding string, returning bytes
:param s: Base58 string to decode
:return: Bytes encoded by ``s``
"""
if not s:
return b''
# Convert the string to an integer
n: int = 0
for c in s:
n *= 58
if c not in b58_digits:
raise Exception('Character %r is not a valid base58 character' % c)
digit = b58_digits.index(c)
n += digit
# Convert the integer to bytes
h: str = '%x' % n
if len(h) % 2:
h = '0' + h
res = unhexlify(h.encode('utf8'))
# Add padding back.
pad = 0
for c in s[:-1]:
if c == b58_digits[0]:
pad += 1
else:
break
return b'\x00' * pad + res
def decode_check(s: str) -> bytes:
"""
Decode a Base58Check encoded string, returning bytes
:param s: Base58 string to decode
:return: Bytes encoded by ``s``
"""
data = decode(s)
payload = data[:-4]
checksum = data[-4:]
calc_checksum = hash256(payload)
if checksum != calc_checksum[:4]:
raise ValueError("Invalid checksum")
return payload
def encode_check(b: bytes) -> str:
checksum = hash256(b)[0:4]
data = b + checksum
return encode(data)
def get_xpub_fingerprint(s: str) -> bytes:
"""
Get the parent fingerprint from an extended public key
:param s: The extended pubkey
:return: The parent fingerprint bytes
"""
data = decode(s)
fingerprint = data[5:9]
return fingerprint
def get_xpub_fingerprint_hex(xpub: str) -> str:
"""
Get the parent fingerprint as a hex string from an extended public key
:param xpub: The extended pubkey
:return: The parent fingerprint as a hex string
"""
data = decode(xpub)
fingerprint = data[5:9]
return hexlify(fingerprint).decode()
def to_address(b: bytes, version: bytes) -> str:
"""
Base58 Check Encode the data with the version number.
Used to encode legacy style addresses.
:param b: The data to encode
:param version: The version number to encode with
:return: The Base58 Check Encoded string
"""
data = version + b
checksum = hash256(data)[0:4]
data += checksum
return encode(data)
def xpub_to_pub_hex(xpub: str) -> str:
"""
Get the public key as a string from the extended public key.
:param xpub: The extended pubkey
:return: The pubkey hex string
"""
data = decode(xpub)
pubkey = data[-37:-4]
return hexlify(pubkey).decode()
def xpub_to_xonly_pub_hex(xpub: str) -> str:
"""
Get the public key as a string from the extended public key.
:param xpub: The extended pubkey
:return: The pubkey hex string
"""
data = decode(xpub)
pubkey = data[-36:-4]
return hexlify(pubkey).decode()
def xpub_main_2_test(xpub: str) -> str:
"""
Convert an extended pubkey from mainnet version to testnet version.
:param xpub: The extended pubkey
:return: The extended pubkey re-encoded using testnet version bytes
"""
data = decode(xpub)
test_data = b'\x04\x35\x87\xCF' + data[4:-4]
checksum = hash256(test_data)[0:4]
return encode(test_data + checksum)
================================================
FILE: bip-0328/_common.py
================================================
"""
Common Classes and Utilities
****************************
"""
import hashlib
def sha256(s: bytes) -> bytes:
"""
Perform a single SHA256 hash.
:param s: Bytes to hash
:return: The hash
"""
return hashlib.new('sha256', s).digest()
def ripemd160(s: bytes) -> bytes:
"""
Perform a single RIPEMD160 hash.
:param s: Bytes to hash
:return: The hash
"""
return hashlib.new('ripemd160', s).digest()
def hash256(s: bytes) -> bytes:
"""
Perform a double SHA256 hash.
A SHA256 is performed on the input, and then a second
SHA256 is performed on the result of the first SHA256
:param s: Bytes to hash
:return: The hash
"""
return sha256(sha256(s))
def hash160(s: bytes) -> bytes:
"""
perform a single SHA256 hash followed by a single RIPEMD160 hash on the result of the SHA256 hash.
:param s: Bytes to hash
:return: The hash
"""
return ripemd160(sha256(s))
================================================
FILE: bip-0328/_xpub.py
================================================
#!/usr/bin/env python3
# Copyright (c) 2020 The HWI developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
Key Classes and Utilities
*************************
Classes and utilities for working with extended public keys, key origins, and other key related things.
"""
import _base58 as base58
from _common import (
hash256,
hash160,
)
import binascii
import hmac
import hashlib
import struct
from typing import (
Dict,
Optional,
Sequence,
Tuple,
)
HARDENED_FLAG = 1 << 31
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
Point = Optional[Tuple[int, int]]
def H_(x: int) -> int:
"""
Shortcut function that "hardens" a number in a BIP44 path.
"""
return x | HARDENED_FLAG
def is_hardened(i: int) -> bool:
"""
Returns whether an index is hardened
"""
return i & HARDENED_FLAG != 0
def point_add(p1: Point, p2: Point) -> Point:
if (p1 is None):
return p2
if (p2 is None):
return p1
if (p1[0] == p2[0] and p1[1] != p2[1]):
return None
if (p1 == p2):
lam = (3 * p1[0] * p1[0] * pow(2 * p1[1], p - 2, p)) % p
else:
lam = ((p2[1] - p1[1]) * pow(p2[0] - p1[0], p - 2, p)) % p
x3 = (lam * lam - p1[0] - p2[0]) % p
return (x3, (lam * (p1[0] - x3) - p1[1]) % p)
def point_mul(p: Point, n: int) -> Point:
r = None
for i in range(256):
if ((n >> i) & 1):
r = point_add(r, p)
p = point_add(p, p)
return r
def deserialize_point(b: bytes) -> Point:
x = int.from_bytes(b[1:], byteorder="big")
y = pow((x * x * x + 7) % p, (p + 1) // 4, p)
if (y & 1 != b[0] & 1):
y = p - y
return (x, y)
def bytes_to_point(point_bytes: bytes) -> Point:
header = point_bytes[0]
if header == 4:
x = point_bytes[1:33]
y = point_bytes[33:65]
return (int(binascii.hexlify(x), 16), int(binascii.hexlify(y), 16))
return deserialize_point(point_bytes)
def point_to_bytes(p: Point) -> bytes:
if p is None:
raise ValueError("Cannot convert None to bytes")
return (b'\x03' if p[1] & 1 else b'\x02') + p[0].to_bytes(32, byteorder="big")
# An extended public key (xpub) or private key (xprv). Just a data container for now.
# Only handles deserialization of extended keys into component data to be handled by something else
class ExtendedKey(object):
"""
A BIP 32 extended public key.
"""
MAINNET_PUBLIC = b'\x04\x88\xB2\x1E'
MAINNET_PRIVATE = b'\x04\x88\xAD\xE4'
TESTNET_PUBLIC = b'\x04\x35\x87\xCF'
TESTNET_PRIVATE = b'\x04\x35\x83\x94'
def __init__(self, version: bytes, depth: int, parent_fingerprint: bytes, child_num: int, chaincode: bytes, privkey: Optional[bytes], pubkey: bytes) -> None:
"""
:param version: The version bytes for this xpub
:param depth: The depth of this xpub as defined in BIP 32
:param parent_fingerprint: The 4 byte fingerprint of the parent xpub as defined in BIP 32
:param child_num: The number of this xpub as defined in BIP 32
:param chaincode: The chaincode of this xpub as defined in BIP 32
:param privkey: The private key for this xpub if available
:param pubkey: The public key for this xpub
"""
self.version: bytes = version
self.is_testnet: bool = version == ExtendedKey.TESTNET_PUBLIC or version == ExtendedKey.TESTNET_PRIVATE
self.is_private: bool = version == ExtendedKey.MAINNET_PRIVATE or version == ExtendedKey.TESTNET_PRIVATE
self.depth: int = depth
self.parent_fingerprint: bytes = parent_fingerprint
self.child_num: int = child_num
self.chaincode: bytes = chaincode
self.pubkey: bytes = pubkey
self.privkey: Optional[bytes] = privkey
@classmethod
def deserialize(cls, xpub: str) -> 'ExtendedKey':
"""
Create an :class:`~ExtendedKey` from a Base58 check encoded xpub
:param xpub: The Base58 check encoded xpub
"""
data = base58.decode(xpub)[:-4] # Decoded xpub without checksum
return cls.from_bytes(data)
@classmethod
def from_bytes(cls, data: bytes) -> 'ExtendedKey':
"""
Create an :class:`~ExtendedKey` from a serialized xpub
:param xpub: The serialized xpub
"""
version = data[0:4]
if version not in [ExtendedKey.MAINNET_PRIVATE, ExtendedKey.MAINNET_PUBLIC, ExtendedKey.TESTNET_PRIVATE, ExtendedKey.TESTNET_PUBLIC]:
raise Exception(f"Extended key magic of {version.hex()} is invalid")
is_private = version == ExtendedKey.MAINNET_PRIVATE or version == ExtendedKey.TESTNET_PRIVATE
depth = data[4]
parent_fingerprint = data[5:9]
child_num = struct.unpack('>I', data[9:13])[0]
chaincode = data[13:45]
if is_private:
privkey = data[46:]
pubkey = point_to_bytes(point_mul(G, int.from_bytes(privkey, byteorder="big")))
return cls(version, depth, parent_fingerprint, child_num, chaincode, privkey, pubkey)
else:
pubkey = data[45:78]
return cls(version, depth, parent_fingerprint, child_num, chaincode, None, pubkey)
def serialize(self) -> bytes:
"""
Serialize the ExtendedKey with the serialization format described in BIP 32.
Does not create an xpub string, but the bytes serialized here can be Base58 check encoded into one.
:return: BIP 32 serialized extended key
"""
r = self.version + struct.pack('B', self.depth) + self.parent_fingerprint + struct.pack('>I', self.child_num) + self.chaincode
if self.is_private:
if self.privkey is None:
raise ValueError("Somehow we are private but don't have a privkey")
r += b"\x00" + self.privkey
else:
r += self.pubkey
return r
def to_string(self) -> str:
"""
Serialize the ExtendedKey as a Base58 check encoded xpub string
:return: Base58 check encoded xpub
"""
data = self.serialize()
checksum = hash256(data)[0:4]
return base58.encode(data + checksum)
def get_printable_dict(self) -> Dict[str, object]:
"""
Get the attributes of this ExtendedKey as a dictionary that can be printed
:return: Dictionary containing ExtendedKey information that can be printed
"""
d: Dict[str, object] = {}
d['testnet'] = self.is_testnet
d['private'] = self.is_private
d['depth'] = self.depth
d['parent_fingerprint'] = binascii.hexlify(self.parent_fingerprint).decode()
d['child_num'] = self.child_num
d['chaincode'] = binascii.hexlify(self.chaincode).decode()
if self.is_private and isinstance(self.privkey, bytes):
d['privkey'] = binascii.hexlify(self.privkey).decode()
d['pubkey'] = binascii.hexlify(self.pubkey).decode()
return d
def derive_pub(self, i: int) -> 'ExtendedKey':
"""
Derive the public key at the given child index.
:param i: The child index of the pubkey to derive
"""
if is_hardened(i):
raise ValueError("Index cannot be larger than 2^31")
# Data to HMAC. Same as CKDpriv() for public child key.
data = self.pubkey + struct.pack(">L", i)
# Get HMAC of data
Ihmac = hmac.new(self.chaincode, data, hashlib.sha512).digest()
Il = Ihmac[:32]
Ir = Ihmac[32:]
# Construct curve point Il*G+K
Il_int = int(binascii.hexlify(Il), 16)
child_pubkey = point_add(point_mul(G, Il_int), bytes_to_point(self.pubkey))
# Construct and return a new BIP32Key
pubkey = point_to_bytes(child_pubkey)
chaincode = Ir
fingerprint = hash160(self.pubkey)[0:4]
return ExtendedKey(ExtendedKey.TESTNET_PUBLIC if self.is_testnet else ExtendedKey.MAINNET_PUBLIC, self.depth + 1, fingerprint, i, chaincode, None, pubkey)
def derive_pub_path(self, path: Sequence[int]) -> 'ExtendedKey':
"""
Derive the public key at the given path
:param path: Sequence of integers for the path of the pubkey to derive
"""
key = self
for i in path:
key = key.derive_pub(i)
return key
================================================
FILE: bip-0328/reference.py
================================================
#! /usr/bin/env python3
import json
import os
import sys
from _base58 import xpub_to_pub_hex
from _bip327 import cbytes, key_agg
from _xpub import ExtendedKey
CHAINCODE = bytes.fromhex("868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965")
def aggregate_to_xpub(aggregate: bytes) -> ExtendedKey:
return ExtendedKey(ExtendedKey.MAINNET_PUBLIC, 0, b"\x00\x00\x00\x00", 0, CHAINCODE, None, aggregate)
def test_aggregate_to_xpub():
with open(os.path.join(sys.path[0], "vectors.json"), "r") as f:
test_data = json.load(f)
for test_case in test_data:
keys = [bytes.fromhex(k) for k in test_case["keys"]]
agg_ctx = key_agg(keys)
pub = cbytes(agg_ctx.Q)
assert pub.hex() == test_case["aggregate_pubkey"]
xpub = aggregate_to_xpub(pub)
assert xpub.to_string() == test_case["xpub"]
if __name__ == "__main__":
test_aggregate_to_xpub()
================================================
FILE: bip-0328/vectors.json
================================================
[
{
"aggregate_pubkey": "0354240c76b8f2999143301a99c7f721ee57eee0bce401df3afeaa9ae218c70f23",
"keys": [
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"
],
"xpub": "xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwXEKGEouzXE6QLLRxjatMcLLzJ5LV5Nib1BN7vJg6yp45yHHRbm"
},
{
"aggregate_pubkey": "0290539eede565f5d054f32cc0c220126889ed1e5d193baf15aef344fe59d4610c",
"keys": [
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66"
],
"xpub": "xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwVk5TFJk8Tw5WAdV3DhrGfbFA216sE9BsQQiSFTdudkETnKdg8k"
},
{
"aggregate_pubkey": "022479f134cdb266141dab1a023cbba30a870f8995b95a91fc8464e56a7d41f8ea",
"keys": [
"02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
"023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66",
"02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
"03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9"
],
"xpub": "xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwUvaZYpysLX4wN59tjwU5pBuDjNrPEJbfxjLwn7ruzbXTcUTHkZ"
}
]
================================================
FILE: bip-0328.mediawiki
================================================
==Abstract==
This document specifies how BIP 32 extended public keys can be constructed from a BIP 327 MuSig2
aggregate public key and how such keys should be used for key derivation.
==Copyright==
This BIP is licensed under the Creative Commons CC0 1.0 Universal license.
==Motivation==
Multiple signers can create a single aggregate public key with MuSig2 that is indistinguishable
from a random public key. The cosigners need a method for generating additional aggregate pubkeys
to follow the best practice of using a new address for every payment.
The obvious method is for the cosigners to generate multiple public keys and produce a
new aggregate pubkey every time one is needed. This is similar to how multisig using Bitcoin script
works where all of the cosigners share their extended public keys and do derivation to produce
the multisig script. The same could be done with MuSig2 and instead of producing a multisig script,
the result would be a MuSig2 aggregate pubkey.
However, it is much simpler to be able to derive from a single extended public key instead of having
to derive from many extended public keys and aggregate them. As MuSig2 produces a normal looking
public key, the aggregate public can be used in this way. This reduces the storage and computation
requirements for generating new aggregate pubkeys.
==Specification==
A synthetic xpub can be created from a BIP 327 MuSig2 plain aggregate public key by setting
the depth to 0, the child number to 0, and attaching a chaincode with the byte string
868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965'''Where does this
constant chaincode come from?''' It is the SHA256 of the text MuSig2MuSig2MuSig2.
This fixed chaincode should be used by all such synthetic xpubs following this specification.
Unhardened child public keys can be derived from the synthetic xpub as with any other xpub. Since
the aggregate public key is all that is necessary to produce the synthetic xpub, any aggregate
public key that will be used in this way shares the same privacy concerns as typical xpubs.
Furthermore, as there is no aggregate private key, only unhardened derivation from the aggregate
public key is possible.
When signing, all signers must compute the tweaks used in the BIP 32 derivation for the child key
being signed for. The IL value computed in ''CKDpub'' is the tweak used at each
derivation step. These are provided in the session context, each with a tweak mode of plain
(''is_xonly_t = false''). When the ''Sign'' algorithm is used, the tweaks will be applied to the
partial signatures.
==Test Vectors==
* Aggregate pubkey 0354240c76b8f2999143301a99c7f721ee57eee0bce401df3afeaa9ae218c70f23
** Synthetic xpub xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwXEKGEouzXE6QLLRxjatMcLLzJ5LV5Nib1BN7vJg6yp45yHHRbm
** Keys:
*** 03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9
*** 02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9
* Aggregate pubkey 0290539eede565f5d054f32cc0c220126889ed1e5d193baf15aef344fe59d4610c
** Synthetic xpub xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwVk5TFJk8Tw5WAdV3DhrGfbFA216sE9BsQQiSFTdudkETnKdg8k
** Keys:
*** 02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9
*** 03DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659
*** 023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66
* Aggregate pubkey 022479f134cdb266141dab1a023cbba30a870f8995b95a91fc8464e56a7d41f8ea
** Synthetic xpub xpub661MyMwAqRbcFt6tk3uaczE1y6EvM1TqXvawXcYmFEWijEM4PDBnuCXwwUvaZYpysLX4wN59tjwU5pBuDjNrPEJbfxjLwn7ruzbXTcUTHkZ
** Keys:
*** 02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659
*** 023590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038CA66
*** 02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9
*** 03935F972DA013F80AE011890FA89B67A27B7BE6CCB24D3274D18B2D4067F261A9
==Backwards Compatibility==
Once a synthetic xpub is created, it is fully backwards compatible with BIP 32 - only unhardened
derivation can be done, and the signers will be able to produce a signature for any derived children.
==Rationale==
==Reference Implementation==
A Python reference implementation is available in this BIP's [[bip-0328|Auxiliary Files]].
==Acknowledgements==
Thanks to Pieter Wuille, Andrew Poelstra, Sanket Kanjalkar, Salvatore Ingala, and all others who
participated in discussions on this topic.
================================================
FILE: bip-0329.mediawiki
================================================
BIP: 329
Layer: Applications
Title: Wallet Labels Export Format
Authors: Craig Raw
Status: Draft
Type: Informational
Assigned: 2022-08-23
License: BSD-2-Clause
==Abstract==
This document specifies a format for the export of labels that may be attached to various common types of records in a wallet.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
The export and import of funds across different Bitcoin wallet applications is well defined through standards such as BIP39, BIP32, BIP44 etc.
These standards are well supported and allow users to move easily between different wallets.
There is, however, no defined standard to transfer any labels the user may have applied to the transactions, addresses, public keys, inputs, outputs or xpubs in their wallet.
The UTXO model that Bitcoin uses makes these labels particularly valuable as they may indicate the source of funds, whether received externally or as a result of change from a prior transaction.
In both cases, care must be taken when spending to avoid undesirable leaks of private information.
Labels provide valuable guidance in this regard, and have even become mandatory when spending in several Bitcoin wallets.
Allowing users to import and export their labels in a standardized way ensures that they do not experience lock-in to a particular wallet application.
In addition, many wallets allow unspent outputs to be frozen or made unspendable within the wallet. Since this wallet-related metadata is similar to labels and not captured elsewhere, it is also included in this format.
==Rationale==
While there is currently no widely accepted format for exporting and importing labels, there are existing formats in use.
SLIP-0015[https://github.com/satoshilabs/slips/blob/master/slip-0015.md SLIP-0015] defines a format for exporting address and output labels, but requires encryption using a private key associated with the wallet seed, and thus cannot be used independently by coordinator wallets which cannot access private keys.
The Electrum wallet imports and exports address and transaction labels in a JSON format which could be used with other record types, but the format used is not self describing making record type identification difficult.
==Specification==
In order to be lightweight, human readable and well structured, this BIP uses a JSON format.
Further, the JSON Lines format is used (also called newline-delimited JSON)[https://jsonlines.org/ jsonlines.org].
This allows a document to be split, streamed, or incrementally added to, and limits the potential for formatting errors to invalidate an entire import.
It is also a convenient format for command-line processing, which is often line-oriented.
Further to the JSON Lines specification, an export of labels from a wallet must be a UTF-8 encoded text file, containing one record per line consisting of a valid JSON object.
Lines are separated by \n. Multiline values are not permitted.
Each JSON object must contain 3 or 4 key/value pairs, defined as follows:
{| class="wikitable"
|-
! Key
! Description
|-
| type
| One of tx, addr, pubkey, input, output or xpub
|-
| ref
| Reference to the transaction, address, public key, input, output or extended public key
|-
| label
| The label applied to the reference
|-
| origin
| Optional key origin information referencing the wallet associated with the label
|-
| spendable
| One of true or false, denoting if an output should be spendable by the wallet
|}
The reference is defined for each type as follows:
{| class="wikitable"
|-
! Type
! Description
! Example
|-
| tx
| Transaction id in hexadecimal format
| f91d0a8a78462bc59398f2c5d7a84fcff491c26ba54c4833478b202796c8aafd
|-
| addr
| Address in base58 or bech32 format
| bc1q34aq5drpuwy3wgl9lhup9892qp6svr8ldzyy7c
|-
| pubkey
| 32, 33 or 65 byte public key in hexadecimal format
| 0283409659355b6d1cc3c32decd5d561abaac86c37a353b52895a5e6c196d6f448
|-
| input
| Transaction id and input index separated by a colon
| f91d0a8a78462bc59398f2c5d7a84fcff491c26ba54c4833478b202796c8aafd:0
|-
| output
| Transaction id and output index separated by a colon
| f91d0a8a78462bc59398f2c5d7a84fcff491c26ba54c4833478b202796c8aafd:1
|-
| xpub
| Extended public key as defined by BIP32
| xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8Nq...
|}
Each JSON object must contain both type and ref properties. The label, origin and spendable properties are optional. If the label or spendable properties are omitted, the importing wallet should not alter these values. The spendable property should only appear where type is output.
If present, the optional origin property must contain an abbreviated output descriptor (as defined by BIP380[https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki BIP-0380]) describing a BIP32 compatible originating wallet, including all key origin information but excluding any actual keys, any child path elements, or a checksum.
This property should be used to disambiguate transaction labels from different wallets contained in the same export, particularly when exporting multiple accounts derived from the same seed.
Care should be taken when exporting due to the privacy sensitive nature of the data.
Encryption in transit over untrusted networks is highly recommended, and encryption at rest should also be considered.
Unencrypted exports should be deleted as soon as possible.
For security reasons no private key types are defined.
==Importing==
* An importing wallet may ignore records it does not store, and truncate labels if necessary. A suggested default for maximum label length is 255 characters, and an importing wallet should consider warning the user if truncation is applied.
* Wallets importing public key records may derive addresses from them to match against known wallet addresses.
* Wallets importing extended public keys may match them against signers, for example in a multisig setup.
==Backwards Compatibility==
The nature of this format makes it naturally extensible to handle other record types.
However, importing wallets complying to this specification should ignore types not defined here.
==Test Vectors==
The following fragment represents a wallet label export:
==Additional Fields==
If the goal is solely to move labels between cooperating wallets,
then the above values are the minimum needed. However, wallet data
exports can serve other purposes. Many values associated with
addresses, transactions and outputs are already on hand for the
wallet generating the export, and yet would be hard or impossible
for importing tools to reconstruct.
All of the following values are optional for the exporter to provide,
but should be given if they are readily available.
=== Transactions ===
* height: An integer giving the block height where this fully confirmed transaction can be found. For transactions that are confirmed by less than 6 blocks, omit this field or provide a value of zero. (Background: Until it is fully confirmed, the "height" of a transaction is in flux and may vary due to chain reorgs. However, the consumer of the labels, may not know the current block height, so it cannot know if the height is "real" (firm, fixed) or just transitory. Therefore, it is important to omit the height unless the generating wallet considers the transaction to be confirmed.)
* time: ISO-8601 formatted timestamp of the block given by the "height" field, preferably in UTC, although ISO-8601 can represent local times. Example: 2025-01-23T11:40:35Z.
* fee: Integer giving the number of Satoshis that went to the miner for this transaction.
* value: Signed integer giving the number of Satoshis that came into the wallet by this transaction. Will be negative when sats leave the wallet. Could be zero if it is a consolidation transaction that moves from old UTXO to new.
* rate: Exchange rate at time of transaction. This is the value of a Bitcoin, expressed in another currency, at the time of the transaction, based on user preferences for data source. Multiple currencies can be given. Keys are ISO 4217 currency codes where possible. Example: "rate": { "USD": 105620.00 }
=== Address, Inputs, and Outputs ===
* keypath: The data needed to build full descriptor down to the specific address. This extends origin with the final two components that are unhardened (in the typical case, assuming BIP-84). Provide string /1/123 for wpkh([d34db33f/84'/0'/0'/1/123]). If the first character is not /, then it should be interpreted as a full descriptor, independent of origin (if any).
=== Inputs and Outputs ===
* value: Integer with the number of Satoshis (nValue) of the input or output.
* fmv: Fair market value of the input/output relative to some other currency, typically fiat. The value should be a mapping, from currency code to decimal number. Example: "fmv": { "USD": 1233.45 }. Most situations will have only a single currency value, and it represents the real price of the goods/services expressed in some fiat currency. This is not an exchange *rate*, but an absolute value. By dividing by the value (above), it is possible to calculate an effective change rate for the transaction.
* height and time: Same definition as defined in Transactions.
=== Address ===
* heights: a list of block heights that contain any activity related to this address, include outputs that deposit to the address, and transactions that spend UTXOs of this address. Omit heights for transactions that are not fully confirmed. An empty array indicates the address is unused for confirmed transactions.
== Comment on Types in JSON ==
JSON can serialize a number of basic types, including string, integer
and boolean (true/false). Decimal values (123.45) can
also be serialized, but some parsing libraries may interpret them as floating
point values, which is generally not what we want in financial applications.
When hand-crafting JSON data, be careful not to write "false" (with quotes),
since that is a string with 5 characters and not a boolean.
==Reference Implementation==
* [https://github.com/Labelbase/python-bip329 Python-BIP329 package]
==References==
================================================
FILE: bip-0330/minisketch.py
================================================
#!/usr/bin/env python3
import random
######## ENCODING and DECODING ########
FIELD_BITS = 32
FIELD_MODULUS = (1 << FIELD_BITS) + 0b10001101
def mul2(x):
"""Compute 2*x in GF(2^FIELD_BITS)"""
return (x << 1) ^ (FIELD_MODULUS if x.bit_length() >= FIELD_BITS else 0)
def mul(x, y):
"""Compute x*y in GF(2^FIELD_BITS)"""
ret = 0
for bit in [(x >> i) & 1 for i in range(x.bit_length())]:
ret ^= bit * y
y = mul2(y)
return ret
######## ENCODING only ########
def sketch(shortids, capacity):
"""Compute the bytes of a sketch for given shortids and given capacity."""
odd_sums = [0 for _ in range(capacity)]
for shortid in shortids:
squared = mul(shortid, shortid)
for i in range(capacity):
odd_sums[i] ^= shortid
shortid = mul(shortid, squared)
return b''.join(elem.to_bytes(4, 'little') for elem in odd_sums)
######## DECODING only ########
def inv(x):
"""Compute 1/x in GF(2^FIELD_BITS)"""
t = x
for i in range(FIELD_BITS - 2):
t = mul(mul(t, t), x)
return mul(t, t)
def berlekamp_massey(s):
"""Given a sequence of LFSR outputs, find the coefficients of the LFSR."""
C, B, L, m, b = [1], [1], 0, 1, 1
for n in range(len(s)):
d = s[n]
for i in range(1, L + 1):
d ^= mul(C[i], s[n - i])
if d == 0:
m += 1
else:
T = list(C)
while len(C) <= len(B) + m:
C += [0]
t = mul(d, inv(b))
for i in range(len(B)):
C[i + m] ^= mul(t, B[i])
if 2 * L <= n:
L, B, b, m = n + 1 - L, T, d, 1
else:
m += 1
return C[0:L + 1]
def poly_monic(p):
"""Return the monic multiple of p, or 0 if the input is 0."""
if len(p) == 0:
return []
i = inv(p[-1])
return [mul(v, i) for v in p]
def poly_divmod(m, p):
"""Compute the polynomial quotient p/m, and replace p with p mod m."""
assert(len(m) > 0 and m[-1] == 1)
div = [0 for _ in range(len(p) - len(m) + 1)]
while len(p) >= len(m):
div[len(p) - len(m)] = p[-1]
for i in range(len(m)):
p[len(p) - len(m) + i] ^= mul(p[-1], m[i])
assert(p[-1] == 0)
p.pop()
while (len(p) > 0 and p[-1] == 0):
p.pop()
return div
def poly_gcd(a, b):
"""Compute the GCD of a and b (destroys the inputs)."""
if len(a) < len(b):
a, b = b, a
while len(b):
if len(b) == 1:
return [1]
b = poly_monic(b)
poly_divmod(b, a)
a, b = b, a
return a
def poly_sqr(p):
"""Compute the coefficients of the square of polynomial with coefficients p."""
return [0 if i & 1 else mul(p[i // 2], p[i // 2]) for i in range(2 * len(p))]
def poly_trace(m, a):
"""Compute the coefficients of the trace polynomial of (a*x) mod m."""
out = [0, a]
for i in range(FIELD_BITS - 1):
out = poly_sqr(out)
while len(out) < 2:
out += [0]
out[1] = a
poly_divmod(m, out)
return out
def find_roots_inner(p, a):
"""Recursive helper function for find_roots (destroys p). a is randomizer."""
# p must be monic
assert(len(p) > 0 and p[-1] == 1)
# Deal with degree 0 and degree 1 inputs
if len(p) == 1:
return []
elif len(p) == 2:
return [p[0]]
# Otherwise, split p in left*right using parameter a_vals[0].
t = poly_monic(poly_trace(p, a))
left = poly_gcd(list(p), t)
right = poly_divmod(list(left), p)
# Invoke recursion with the remaining a_vals.
ret_right = find_roots_inner(right, mul2(a))
ret_left = find_roots_inner(left, mul2(a))
# Concatenate roots
return ret_left + ret_right
def find_roots(p):
"""Find the roots of polynomial with coefficients p."""
# Compute x^(2^FIELD_BITS)+x mod p in a roundabout way.
t = poly_trace(p, 1)
t2 = poly_sqr(t)
for i in range(len(t)):
t2[i] ^= t[i]
poly_divmod(p, t2)
# If distinct from 0, p is not fully factorizable into non-repeating roots.
if len(t2):
return None
# Invoke the recursive splitting algorithm
return find_roots_inner(list(p), random.randrange(1, 2**32-1))
def decode(sketch):
"""Recover the shortids from a sketch."""
odd_sums = [int.from_bytes(sketch[i*4:(i+1)*4], 'little') for i in range(len(sketch) // 4)]
sums = []
for i in range(len(odd_sums) * 2):
if i & 1:
sums.append(mul(sums[(i-1)//2], sums[(i-1)//2]))
else:
sums.append(odd_sums[(i+1)//2])
return find_roots(list(reversed(berlekamp_massey(sums))))
================================================
FILE: bip-0330.mediawiki
================================================
==Abstract==
This document specifies a P2P protocol extension for reconciliation of transaction announcements between 2 nodes, which is a building block for efficient transaction relay protocols (e.g., [https://arxiv.org/pdf/1905.10518.pdf Erlay]). This is a step towards increasing the connectivity of the network for almost no bandwidth cost.
==Motivation==
Currently in the Bitcoin network, every 32-byte transaction ID is announced in at least one direction between every pair of connected peers, via INV messages. This results in high cost of announcing transactions: ''O(nodes * connections_per_node)''.
A reconciliation-based protocol which uses the technique suggested in this document can have better scaling properties than INV-based flooding.
Increasing the connectivity of the network makes the network more robust to partitioning attacks; thus, improving the bandwidth scaling of transaction relay to ''O(nodes)'' (and without a high constant overhead) would allow us to improve the security of the network by increasing connectivity. It would also reduce the bandwidth required to run a Bitcoin node and potentially enable more users to run full nodes.
===Erlay===
[https://arxiv.org/pdf/1905.10518.pdf Erlay] is an example of a high-level transaction relay protocol which employs set reconciliation for bandwidth efficiency.
Note that what we are going to describe here is a modified version from the protocol (it is different from what is presented in the paper).
Erlay uses both flooding (announcing using INV messages to all peers) and reconciliation to announce transactions.
Flooding is expensive, so Erlay seeks to use it only when necessary to facilitate rapid relay over a small subset of connections.
Efficient set reconciliation is meant to deliver transactions to those nodes which didn't receive a transaction via flooding, and also just make sure remaining connections are in sync (directly connected pairs of nodes are aware they have nothing to learn from each other).
Efficient set reconciliation works as follows:
1) every node keeps a reconciliation set for each peer, in which transactions are placed which would have been announced using INV messages absent this protocol
2) once in a while every node chooses a peer from its reconciliation queue to reconcile with, resulting in both sides learning the transactions known to the other side
3) after every reconciliation round, the corresponding reconciliation set is cleared
A more detailed description of a set reconciliation round can be found below.
Erlay allows us to:
* save a significant portion of the bandwidth consumed by a node
* increase network connectivity for almost no bandwidth or latency cost
* keep transaction propagation latency at the same level
This document proposes a P2P-layer extension which is required to enable efficient reconciliation-based protocols (like Erlay) for transaction relay.
==Specification==
===New data structures===
Several new data structures are introduced to the P2P protocol first, to aid with efficient transaction relay.
====32-bit short transaction IDs====
=
Short IDs are computed as follows:
* Let ''salt1'' and ''salt2'' be the entropy contributed by both sides; see the "sendtxrcncl" message further for details how they are exchanged.
* Sort the two salts such that ''salt1 ≤ salt2'' (which side sent what doesn't matter).
* Compute ''h = TaggedHash("Tx Relay Salting", salt1, salt2)'', where the two salts are encoded in 64-bit little-endian byte order, and TaggedHash is specified by [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP-340].
* Let ''k0'' be the 64-bit integer obtained by interpreting the first 8 bytes of ''h'' in little-endian byte order.
* Let ''k1'' be the 64-bit integer obtained by interpreting the second 8 bytes of ''h'' in little-endian byte order.
* Let ''s = SipHash-2-4((k0,k1),wtxid)'', where ''wtxid'' is the transaction hash including witness data as defined by BIP141.
* The short ID is equal to ''1 + (s mod 0xFFFFFFFF)''.
This results in approximately uniformly distributed IDs in the range ''[1..0xFFFFFFFF]'', which is a requirement for using them as elements in 32-bit sketches. See the next paragraph for details.
====Short transaction ID sketches====
Reconciliation-based relay uses [https://www.cs.bu.edu/~reyzin/code/fuzzy.html PinSketch] BCH-based secure sketches as introduced by the [https://www.cs.bu.edu/~reyzin/fuzzy.html Fuzzy Extractors paper]. They are a form of set checksums with the following properties:
* Sketches have a predetermined capacity, and when the number of elements in the set does not exceed the capacity, it is always possible to recover the entire set from the sketch by decoding the sketch. A sketch of nonzero b-bit elements with capacity c can be stored in bc bits.
* A sketch of the [https://en.wikipedia.org/wiki/Symmetric_difference symmetric difference] between the two sets (i.e., all elements that occur in one but not both input sets), can be obtained by combining the sketches of those sets.
The sketches used here consists of elements of the [https://en.wikipedia.org/wiki/Finite_field finite field] ''GF(232)''. Specifically, we represent finite field elements as polynomials in ''x'' over ''GF(2)'' modulo ''x327 + x3 + x2 + 1''. To map integers to finite field elements, simply treat each bit ''i'' (with value ''2i'') in the integer as the coefficient of ''xi'' in the polynomial representation. For example the integer ''101 = 26 + 25 + 22 + 1'' is mapped to field element ''x6 + x5 + x2 + 1''. These field elements can be added and multiplied together, but the specifics of that are out of scope for this document.
A short ID sketch with capacity ''c'' consists of a sequence of ''c'' field elements. The first is the sum of all short IDs in the set, the second is the sum of the 3rd powers of all short IDs, the third is the sum of the 5th powers etc., up to the last element with is the sum of the ''(2c-1)''th powers. These elements are then encoded as 32-bit integers in little endian byte order, resulting in a ''4c''-byte serialization.
The following Python 3.2+ code implements the creation of sketches:
FIELD_BITS = 32
FIELD_MODULUS = (1 << FIELD_BITS) + 0b10001101
def mul2(x):
"""Compute 2*x in GF(2^FIELD_BITS)"""
return (x << 1) ^ (FIELD_MODULUS if x.bit_length() >= FIELD_BITS else 0)
def mul(x, y):
"""Compute x*y in GF(2^FIELD_BITS)"""
ret = 0
for bit in [(x >> i) & 1 for i in range(x.bit_length())]:
ret, y = ret ^ bit * y, mul2(y)
return ret
def create_sketch(shortids, capacity):
"""Compute the bytes of a sketch for given shortids and given capacity."""
odd_sums = [0 for _ in range(capacity)]
for shortid in shortids:
squared = mul(shortid, shortid)
for i in range(capacity):
odd_sums[i] ^= shortid
shortid = mul(shortid, squared)
return b''.join(elem.to_bytes(4, 'little') for elem in odd_sums)
The [https://github.com/sipa/minisketch/ minisketch] library implements the construction, merging, and decoding of these sketches efficiently.
===Intended Protocol Flow===
Set reconciliation primarily consists of the transmission and decoding of a reconciliation set sketch upon request.
Since sketches are based on the WTXIDs, the negotiation and support of Erlay should be enabled only if both peers signal [https://github.com/bitcoin/bips/blob/master/bip-0339.mediawiki BIP-339] support.
[[File:bip-0330/recon_scheme_merged.png|framed|center|Protocol flow]]
====Sketch extension====
If a node is unable to reconstruct the set difference from the received sketch, the node then makes a request for sketch extension. The peer would then send an extension, which is a sketch of a higher capacity (allowing to decode more differences) over the same transactions minus the sketch part which was already sent initially (to save bandwidth).
To allow this optimization, the initiator is supposed to locally store a sketch received initially.
This optimization is possible because extending a sketch is just concatenating new elements to an array.
===New messages===
Several new protocol messages are added: sendtxrcncl, reqrecon, sketch, reqsketchext, reconcildiff. This section describes their serialization, contents, and semantics.
In what follows, all integers are serialized in little-endian byte order. Boolean values are encoded as a single byte that must be 0 or 1 exactly. Arrays are serialized with the CompactSize prefix that encodes their length, as is common in other P2P messages.
====sendtxrcncl====
The sendtxrcncl message announces support for the reconciliation protocol. It is expected to be only sent once, and ignored by nodes that don't support it.
Should be sent before "verack" and accompanied by "wtxidrelay" (in any order).
If "sendtxrcncl" was sent after "verack", the sender should be disconnected.
If "sendtxrcncl" was sent before "verack", but by "verack" the "wtxidrelay" message was not received,
"sendtxrcncl" should be ignored. The connection should proceed normally, but as if reconciliation
was not supported.
Must not be sent if peer specified no support for transaction relay (fRelay=0) in "version".
Otherwise, the sender should be disconnected.
Its payload consists of:
{|class="wikitable"
! Data type !! Name !! Description
|-
| uint32 || version || Sender must set this to 1 currently, otherwise receiver should ignore the message. v1 is the lowest protocol version, everything below that is a protocol violation.
|-
| uint64 || salt || The salt used in the short transaction ID computation.
|}
After both peers have confirmed support by sending "sendtxrcncl", the initiator of the P2P connection assumes the role of reconciliation initiator (will send "reqrecon" messages) and the other peer assumes the role of reconciliation responder (will respond to "reqrecon" messages).
"reqrecon" messages can only be sent by the reconciliation initiator.
====reqrecon====
The reqrecon message initiates a reconciliation round.
{|class="wikitable"
! Data type !! Name !! Description
|-
| uint16 || set_size || Size of the sender's reconciliation set, used to estimate set difference.
|-
| uint16 || q || Coefficient used to estimate set difference. Multiplied by PRECISION=(2^15) - 1 and rounded up by the sender and divided by PRECISION by the receiver.
|}
Upon receipt of a "reqrecon" message, the receiver:
* Constructs and sends a "sketch" message (see below), with a sketch of certain ''capacity=f(set_size, local_set_size, q)'' (the exact function is suggested below), where ''local_set_size'' represents size of the receiver's reconciliation set.
* Makes a snapshot of their current reconciliation set, and clears the set itself. The snapshot is kept until a "reconcildiff" message is received by the node.
No new "reqrecon" message can be sent until a "reconcildiff" message is sent.
====sketch====
The sketch message is used to communicate a sketch required to perform set reconciliation.
{|class="wikitable"
! Data type !! Name !! Description
|-
| byte[] || skdata || The sketch of the sender's reconciliation snapshot
|}
The sketch message may be received in two cases.
1. Initial sketch. Upon receipt of a "sketch" message, a node computes the difference sketch by combining the received sketch with a sketch computed locally for a corresponding reconciliation set. The receiving node then tries to decode the difference sketch and based on the result:
* If the decoding failed, the receiving node requests an extension sketch by sending a "reqsketchext" message. Alternatively, the node may terminate the reconciliation right away by sending a "reconcildiff" message is sent with the failure flag set (success=false).
* If the decoding succeeded, a "reconcildiff" message with success=true.
The receiver also makes snapshot of their current reconciliation set, and clears the set itself. The snapshot is kept until a "reconcildiff" message is sent by the node. It is needed to enable sketch extension.
2. Sketch extension. By combining the sketch extension with the initially received sketch, an extended sketch is obtained. The receiving node then computes the extended difference sketch by combining the received extended sketch with an extended sketch computed locally over a corresponding reconciliation set snapshot. The receiving node then tries to decode the extended difference sketch and based on the result:
* If the decoding failed, the receiving node terminates the reconciliation right away by sending a "reconcildiff" message is sent with the failure flag set (success=false).
* If the decoding succeeded, a "reconcildiff" message with success=true.
In either cases, a "reconcildiff" with success=false should also be accompanied with announcing all transactions from the reconciliation set (or set snapshot if failed after extension) as a fallback to flooding.
A "reconcildiff" with success=true should contain unknown short IDs of the transactions from the decoded difference, corresponding to the transactions missing on the sender's side. Known short IDs from the difference correspond to what the receiver of the message is missing, and they should be announced via an "inv" message.
====reqsketchext====
The reqsketchext message is used by reconciliation initiator to signal that initial set reconciliation has failed and a sketch extension is needed to find set difference.
It has an empty payload.
Upon receipt of a "reqsketchext" message, a node responds to it with a "sketch" message, which contains a sketch extension: a sketch (of the same transactions sketched initially) of higher capacity without the part sent initially.
====reconcildiff====
The reconcildiff message is used by reconciliation initiator to announce transactions which are found to be missing during set reconciliation on the sender's side.
{|class="wikitable"
! Data type !! Name !! Description
|-
| uint8 || success || Indicates whether sender of the message succeeded at set difference decoding.
|-
| uint32[] || ask_shortids || The short IDs that the sender did not have.
|}
Upon receipt a "reconcildiff" message with ''success=1'' (reconciliation success), a node sends an "inv" message for the transactions requested by 32-bit IDs (first vector) containing their wtxids (with parent transactions occurring before their dependencies).
If ''success=0'' (reconciliation failure), receiver should announce all transactions from the reconciliation set via an "inv" message.
In both cases, transactions the sender of the message thinks the receiver is missing are announced via an "inv" message.
The regular "inv" deduplication should apply.
The snapshot of the corresponding reconciliation set is cleared by the sender and the receiver of the message.
The sender should also send their own "inv" message along with the reconcildiff message to announce transactions which are missing on the receiver's side.
==Local state==
This BIP suggests a stateful protocol and it requires storing several variables at every node to operate properly.
====Reconciliation salt====
When negotiating reconciliation support, peers send each other their contribution to the reconciliation salt (see how we construct short IDs above). These salts (or just the resulting salt) should be stored on both sides of the connection.
====Reconciliation sets====
Every node stores a set of wtxids for every peer which supports transaction reconciliation, representing the transactions which would have been sent according to the regular flooding protocol.
Incoming transactions are added to sets when those transactions are received (if they satisfy the policies such as minimum fee set by a peer).
A reconciliation set is moved to the corresponding set snapshot after the transmission of the initial sketch.
====Reconciliation set snapshot====
After transmitting the initial sketch (either sending or receiving of the reconcildiff message), every node should store the snapshot of the current reconciliation set, and clear the set.
This is important to make sketch extension more stable (extension should be computed over the set snapshot). Otherwise, extension would contain transactions received after sending out the initial sketch.
The snapshot is cleared after the end of the reconciliation round (sending or receiving of the reconcildiff message).
====Sketch capacity estimation and q-coefficient====
Earlier we suggested that upon receiving a reconciliation request, a node should estimate the sketch capacity it should send: ''capacity=f(set_size, local_set_size, q)''.
We suggest the following function: ''capacity=|set_size - local_set_size| + q * min(set_size, local_set_size) + c''.
Intuitively, ''q'' represents the discrepancy in sets: the closer the sets are, the lower optimal ''q'' is.
Per the Erlay paper, ''q'' should be derived as an optimal ''q'' value for the previous reconciliation with a given peer, once the actual set sizes and set difference are known.
For example, if in previous round ''set_size=30'' and ''local_set_size=20'', and the *actual* difference was ''12'', then a node should compute ''q'' as following:
''q=(12 - |30-20|) / min(30, 20)=0.1''
The derivation of ''q'' can be changed according to the version of the protocol. For example, a static value could be chosen for simplicity. However, we suggest that ''q'' remains a parameter sent in every reconciliation request to enable future compatibility with more sophisticated (non-static) choices of this parameter.
As for the ''c'' parameter, it is suggested to use ''c=1'' to avoid sending empty sketches and reduce the overhead caused by under-estimations.
==Backward compatibility==
Older clients remain fully compatible and interoperable after this change.
Clients which do not implement this protocol remain fully compatible after this change using existing protocols, because transaction announcement reconciliation is used only for peers that negotiate support for it.
==Rationale==
====Why use PinSketch for set reconciliation?====
PinSketch is more bandwidth efficient than IBLT, especially for the small differences in sets we expect to operate over.
PinSketch is as bandwidth efficient as CPISync, but PinSketch has quadratic decoding complexity, while CPISync have cubic decoding complexity. This makes PinSketch significantly faster.
====Why use 32-bit short transaction IDs?====
To use Minisketch in practice, transaction IDs should be shortened (ideally, not more than 64 bits per element).
A small number of bits per transaction also allows saving extra bandwidth and make operations over sketches faster.
According to our estimates, 32 bits provides low collision rate in a non-adversarial model (which is enabled by using independent salts per-link).
====Why use sketch extensions instead of bisection?====
Bisection is an alternative to sketch extensions, per which a second sketch with the same initial capacity is computed over half of the txID space.
Due to the linearity of sketches, transmitting just this one allows a reconciliation initiator to compute the sketch of the same capacity of another half. Two sketches allow the initiator to reconstruct twice as many differences as was allowed by an initial sketch.
In practice this allows the initiator to amortize the bandwidth overhead of initial reconciliation failure, similarly to extension sketches, making the overhead negligible.
The main benefit of sketch extensions is a much simpler implementation. Implementing bisection is hard (see [https://github.com/naumenkogs/bitcoin/commit/b5c92a41e4cc0599504cf838d20212f1a403e573 implementation]) because, in the end, we have to operate with two sketches and handle scenarios where one sketch decoded and another sketch failed.
It becomes even more difficult if in the future we decide to allow more than one extension/bisection. Bisection in this case have to be recursive (and spawn 4/8/16/... sketches), while for extensions we always end up with one extended sketch.
Sketch extensions are also more flexible: extending a sketch of capacity 10 with 4 more means just computing a sketch of capacity 14 and sending the extension, while for bisection increasing the capacity to something different than 10*2/10*4/10*8/... is sophisticated implementation-wise.
The only advantage of bisection is that it doesn't require computing sketches of higher capacities (exponential cost). We believe that since
the protocol is currently designed to operate in the conditions where sketches usually have at most the capacity of 20, this efficiency is not crucial.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/21515
==Acknowledgments==
A large fraction of this proposal was done during designing Erlay with Gregory Maxwell, Sasha Fedorova and Ivan Beschastnikh.
We would like to thank Suhas Daftuar for contributions to the design and BIP structure.
We would like to thank Ben Woosley for contributions to the high-level description of the idea.
==Copyright==
This document is licensed under the Creative Commons CC0 1.0 Universal license.
================================================
FILE: bip-0331.mediawiki
================================================
==Abstract==
Peer-to-peer protocol messages enabling nodes to request and relay the unconfirmed ancestor package
of a given transaction, and to request and relay transactions in batches.
==Motivation==
===Propagate High Feerate Transactions===
Since v0.13, Bitcoin Core has used ancestor packages instead of individual transactions to evaluate
the incentive compatibility of transactions in the mempool
[https://github.com/bitcoin/bitcoin/pull/7594 Add tracking of ancestor packages] and
selecting them for inclusion in blocks
[https://github.com/bitcoin/bitcoin/pull/7600 Select transactions using feerate-with-ancestors].
Incentive-compatible mempool and miner policies help create a fair, fee-based market for block
space. While miners maximize transaction fees in order to earn higher block rewards, non-mining
users participating in transaction relay reap many benefits from employing policies that result in a
mempool with similar contents, including faster compact block relay and more accurate fee
estimation. Additionally, users may take advantage of mempool and miner policy to bump the priority
of their transactions by attaching high-fee descendants (Child Pays for Parent or CPFP).
Only individually considering transactions for submission to the mempool creates a limitation in
the node's ability to determine which transactions to include in the mempool, since it cannot take
into account descendants until all the transactions are in the mempool. Similarly, it cannot use a
transaction's descendants when considering which of two conflicting transactions to keep (Replace by
Fee or RBF).
When a user's transaction does not meet a mempool's minimum feerate and they cannot create a
replacement transaction directly, their transaction will simply be rejected by this mempool or
evicted if already included. They also cannot attach a descendant to pay for replacing a conflicting
transaction; it would be rejected for spending inputs that do not exist.
This limitation harms users' ability to fee-bump their transactions. Further, it presents security and complexity
issues in contracting protocols which rely on presigned, time-sensitive transactions'''Examples of time-sensitive pre-signed transactions in L2 protocols.'''
* [https://github.com/lightning/bolts/blob/master/03-transactions.md#htlc-timeout-and-htlc-success-transactions HTCL-Timeout in LN Penalty]
* [https://github.com/revault/practical-revault/blob/master/transactions.md#cancel_tx Unvault Cancel in Revault]
* [https://github.com/discreetlogcontracts/dlcspecs/blob/master/Transactions.md#refund-transaction Refund Transaction in Discreet Log Contracts]
* [https://gist.github.com/instagibbs/60264606e181451e977e439a49f69fe1 Updates in Eltoo]
* [https://github.com/ElementsProject/peerswap/blob/master/docs/peer-protocol.md#claim-transaction Claim Transactions in PeerSwap]
to prevent cheating.
In other words, a key security assumption of many contracting protocols is that all parties can
propagate and confirm transactions in a timely manner. Increasing attention has been brought to
"pinning attacks," a type of censorship in which the attacker uses mempool policy restrictions to
prevent a transaction from being relayed or getting mined.
'''Concerns for pinning attacks in L2 protocols'''
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-May/020458.html Greg Sanders, "Bringing a nuke to a knife fight: Transaction introspection to stop RBF pinning"]
* [https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-April/002639.html Matt Corallo, "RBF Pinning with Counterparties and Competing Interest"]
* [https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-June/002758.html Antoine Riard, "Pinning : The Good, The Bad, The Ugly"]
* [https://github.com/t-bast/lightning-docs/blob/master/pinning-attacks.md Bastien Teinturier, "Pinning Attacks"]
* [https://gist.github.com/instagibbs/60264606e181451e977e439a49f69fe1 Greg Sanders, "Eltoo Pinning"]
These transactions must meet a certain confirmation target to be effective, but their feerates
are negotiated well ahead of broadcast time. If the forecast feerate was too low and no
fee-bumping options are available, attackers can steal money from their counterparties. Always
overestimating fees may sidestep this issue (but only while mempool traffic is low and
predictable), but this solution is not guaranteed to work and wastes users' money. For some attacks,
the available defenses require nodes to have a bird's-eye view of Bitcoin nodes' mempools, which is
an unreasonable security requirement.
Part of the solution is to enable nodes to consider packages of transactions as a unit, e.g. one or
more low-fee ancestor transactions with a high-fee descendant, instead of separately. A package-aware
mempool policy can help determine if it would actually be economically rational to accept a
transaction to the mempool if it doesn't meet fee requirements individually. Network-wide adoption
of these policies would create a more purely-feerate-based market for block space and allow
contracting protocols to adjust fees (and therefore mining priority) at broadcast time.
Theoretically, developing a safe and incentive-compatible package mempool acceptance policy is
sufficient to solve this issue. Nodes could opportunistically accept packages (e.g. by trying
combinations of transactions rejected from their mempools), but this practice would likely be
inefficient at best and open new Denial of Service attacks at worst. As such, this proposal
suggests adding new p2p messages enabling nodes to request and share package-validation-related
information with one another, resulting in a more efficient and reliable way to propagate packages.
===Handle Orphans Better===
Txid-based transaction relay is problematic since a transaction's witness may be malleated without
changing its txid; a node cannot use txid to deduplicate transactions it has already downloaded
or validated. Ideally, two nodes that both support BIP339 wtxid-based transaction relay shouldn't
ever need to use txid-based transaction relay.
A single use case of txid-based relay remains: handling "orphan" transactions that spend output(s)
from an unconfirmed transaction the receiving node is unaware of. Orphan transactions are very
common for new nodes that have just completed Initial Block Download and do not have an up-to-date
mempool. Nodes also download transactions from multiple peers. If the peer from which a child
transaction was requested responds faster than the peer from which its parent was requested, that
child is seen as an orphan transaction.
Nodes may handle orphans by storing them in a cache and requesting any missing parent(s) by txid
(prevouts specify txid, not wtxid). These parents may end up being orphans as well, if they also
spend unconfirmed inputs that the node is unaware of. This method of handling orphans is problematic
for two reasons: it requires nodes to allocate memory for unvalidated data received on the p2p
network and it relies on txid-based relay between two wtxid-relay peers.
This proposal makes orphan resolution more efficient and no longer require txid-based relay.
==Definitions==
Given any two transactions Tx0 and Tx1 where Tx1 spends an output of Tx0, Tx0 is a '''parent''' of
Tx1 and Tx1 is a '''child''' of Tx0.
A transaction's '''ancestors''' include, recursively, its parents, the parents of its parents, etc.
A transaction's '''descendants''' include, recursively, its children, the children of its children,
etc. A transaction's parent is its ancestor, but an ancestor is not necessarily a parent.
A '''package''' is a list of transactions, representable by a connected Directed Acyclic
Graph (a directed edge exists between a transaction that spends the output of another transaction).
In this proposal, a package is limited to unconfirmed transactions.
An '''ancestor package''' consists of an unconfirmed transaction with all of its unconfirmed
ancestors.
In a '''topologically sorted''' package, each parent appears somewhere in the list before its child.
==Specification==
Ancestor Package Relay includes two parts: a package information round and a transaction data
download round.
The package information round is used to help a receiver learn what transactions are in a package and
decide whether they want to download them. The transaction data round is used to help a node download
multiple transactions in one message instead of as separate messages.
'''Why are package information and transaction data rounds both necessary?'''
Several alternative designs were considered. One should measure alternative solutions based on the
resources used to communicate (not necessarily trustworthy) information: We would like to minimize
network bandwidth, avoid downloading a transaction more than once, avoid downloading transactions
that are eventually rejected, and minimize storage allocated for not-yet-validated transactions.
'''No Package Information Round:''' One proposal is to just use the child's wtxid to refer to the
package and always send the entire package together, skipping the package information round.
However, this protocol would make it very likely for honest nodes to redownload duplicate
transactions. See the following example, where the high-feerate ancestors were already downloaded
and accepted individually.
[[File:./bip-0331/no_package_info.png|600px]]
'''Package Information Only:''' Just having package information gives enough information for the
receiver to accept the packages. That is, rather than using "getpkgtxns" and "pkgtxns" messages,
send "getdata" and download the transactions individually. While this option is a potential fallback
if batched transaction download fails for some reason, it shouldn't be used as the default because
it always requires storage of unvalidated transactions.
[[File:./bip-0331/package_info_only.png|1000px]]
Package relay is negotiated between two peers during the version handshake using a "sendpackages"
message. The versions field within "sendpackages" is interpreted as a bitfield; peers may relay
multiple versions of packages. Package relay requires both peers to support wtxid-based relay
because package transactions are referenced by their wtxids.
'''Why do we need multiple versions? Why can't we just support arbitrary packages?'''
Attempting to support arbitrary packages in mempool validation may result in very complex logic, new
Denial of Service attack vectors, and policy limitations that could be leveraged to censor
transactions (aka "pinning attacks"). This protocol is extensible to support other types of
packages based on future desired use cases. Future package information messages may describe
different types of packages and/or contain more information than a list of wtxids, e.g. feerate or
relationships between transactions.'''Why use a bitfield instead of a numbering system?'''
It should be possible to support some subset of the existing package types.
[[File:./bip-0331/version_negotiation.png|400px]]
Nodes indicate support for batched transaction data round ("getpkgtxns", "pkgtxns", and
"MSG_PKGTXNS") using the PKG_RELAY_PKGTXNS = (1 << 0) bit in their "sendpackages"
messages during version handshake. They indicate support for the ancestor package information
round ("ancpkginfo", "MSG_ANCPKGINFO") using the PKG_RELAY_ANC = (1 << 1) bit in their
"sendpackages" messages during version handshake.
===Protocol Flow Examples===
This package relay protocol satisfies both use cases (orphan transaction handling and high-feerate
transaction paying for low-feerate ancestors).
====Orphan Transaction Handling====
Upon receiving an orphan transaction, a node may request ancestor package information delineating
the wtxids of the transaction's unconfirmed ancestors. This is done without using txid-based relay.
The package information can be used to request transaction data. As these transactions are dependent
upon one another to be valid, the transactions can be requested and sent as a batch.
Contrast this protocol with legacy orphan handling, which requires requesting the missing
transactions by their txids and may require new round trips for each generation of missing parents.
[[File:./bip-0331/orphan_handling_flow.png|1000px]]
====Fee-Bumped Transactions====
Too-low-feerate transactions (i.e. below the node's minimum mempool feerate) with high-feerate
descendants can also be relayed this way. If the peers are using BIP133 fee filters and a
low-feerate transaction is below the node's fee filter, the sender will not announce it. The
high-feerate transaction will be sent by the sender, and received and handled as an orphan by the
receiver, the transactions are validated as a package, and so the protocol naturally works for this
use case.
This does not mean BIP133 is required for package relay to work, provided that nodes do not
immediately reject transactions previously found to be too low feerate. If the low-feerate
transaction was sent and rejected, the receiver should later re-request and accept it after learning
that it is the ancestor of another transaction, and that they meet the receiver's mempool policy
requirements when validated together.
[[File:./bip-0331/package_cpfp_flow.png|600px]]
This protocol is receiver-initiated only; nodes do not proactively announce packages to their peers.
'''Why no sender-initiated protocol?''' Sender-initiated package
relay can, theoretically, save a round trip by notifying the receiver ahead of time that they will
probably need to request and validate a group of transactions together in order for them to be
accepted. As with any proactive communication, there is a chance that the receiver already knows
this information, so this network bandwidth may be wasted. Shortened latency is less significant
than wasted bandwidth.
The logic used to decide when to announce a package proactively determines whether it is a net
increase or decrease for overall bandwidth usage. However, it is difficult to design anything to
save bandwidth without any idea of what its bandwidth usage actually looks like in practice. No
historical data is available, as one of the primary goals of this protocol is to enable
currently-rejected transactions to propagate. After deploying receiver-initiated package relay, we
can observe its usage and then introduce a sender-initiated package relay protocol informed by data
collected from the p2p network.
===Combined Hash===
A "combined hash" serves as a unique "package id" for some list of transactions and helps provide a
meaningful but short "notfound" response to "getpkgtxns."
The combined hash of a package of transactions is equal to the sha256 hash of each transaction's
wtxid concatenated in lexicographical order.
===New Messages===
Four new protocol messages and two inv types are added.
====sendpackages====
{|
| Field Name || Type || Size || Purpose
|-
|versions || uint64_t || 8 || Bit field that is 64 bits wide, denoting the package versions supported by the sender.
|-
|}
# The "sendpackages" message has the structure defined above, with pchCommand == "sendpackages".
# During version handshake, nodes should send one "sendpackages" message indicating they support package relay, with the versions field indicating which versions they support.
# The "sendpackages" message MUST be sent before sending a "verack" message. If a "sendpackages" message is received after "verack", the sender may be disconnected.
# Upon successful connection ("verack" sent by both peers), a node may relay packages with the peer if they did not set "fRelay" to false in the "version" message, both peers sent "wtxidrelay", and both peers sent "sendpackages" for matching version bit(s). Unknown bits (including versions==0) should be ignored. Peers should relay packages corresponding to versions that both sent "sendpackages" for.'''Is it ok to send "sendpackages" to a peer that specified fRelay=false in their "version" message?'''
Yes, this is allowed in order to reduce the number of negotiation steps. This means nodes can
announce features without first checking what the other peer has sent, and then apply negotiation
logic at the end based on what was sent and received. See [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-May/020510.html this discussion].
====ancpkginfo====
{|
| Field Name || Type || Size || Purpose
|-
|txns_length||CompactSize||1 or 3 bytes|| The number of transactions provided.
|-
|txns||List of wtxids||txns_length * 32|| The wtxids of each transaction in the package.
|}
# The "ancpkginfo" message has the structure defined above, with pchCommand == "ancpkginfo".
# The "txns" field should contain a list of wtxids which constitute the ancestor package of the last wtxid. For the receiver's convenience, the sender should - but is not required to - sort the wtxids in topological order. The topological sort can be achieved by sorting the transactions by mempool acceptance order (if parents are always accepted before children). Apart from the last wtxid which is used to learn which transaction the message corresponds to, there is no enforced ordering. Nodes should not disconnect or punish a peer who provides a list not sorted in topological order.'''Why not include feerate information to help the receiver decide whether these transactions are worth downloading?'''
A simple feerate is typically insufficient; the receiver must also know the dependency
relationships between transactions and their respective sizes.
'''Should a peer be punished if they provide incorrect package info, e.g. a list of unrelated transactions?'''
Ideally, there should be a way to enforce that peers are providing correct information to each
other. However, two peers may have different views of what a transaction's unconfirmed ancestors
are based on their chainstate. For example, during a reorg or when two blocks are found at the same
time, one peer may see a transaction as confirmed while the other peer does not.
As such, it is impossible to accurately enforce this without also knowing the peer's chainstate.
It was [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-May/020493.html originally proposed]
to include a block hash in "ancpkginfo" to avoid unwarranted disconnections. However, it does not
make much sense to stop or delay transaction data requests due to mismatched chainstates, and the
chainstate may change again between package information and transaction data rounds. Instead,
differences in chainstate should be handled at the validation level. The node has already spent
network bandwidth downloading these transactions; it should make a best effort to validate them.
See [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-June/020558.html discussion].
'''Why not require topological order?'''
It is not possible to determine whether a list of transactions is topologically sorted without first
establishing that the list contains a full ancestor package. It is not possible to determine whether
a list of transactions contains a full ancestor package without knowing what the chainstate is.
# Upon receipt of a "ancpkginfo" message, the node may use it to request the transactions it does not already have (e.g. using "getpkgtxns" or "tx").
# Upon receipt of a malformed "ancpkginfo" message, the sender may be disconnected. An "ancpkginfo" message is malformed if it contains duplicate wtxids or conflicting transactions (spending the same inputs). The receiver may learn that a package info was malformed after downloading the transactions.
# A node MUST NOT send a "ancpkginfo" message that has not been requested by the recipient. Upon receipt of an unsolicited "ancpkginfo", a node may disconnect the sender.
# This message must only be used if both peers set PKG_RELAY_ANC in their "sendpackages" message. If an "ancpkginfo" message is received from a peer with which this type of package relay was not negotiated, no response should be sent and the sender may be disconnected.
====MSG_ANCPKGINFO====
# A new inv type (MSG_ANCPKGINFO == 0x7) is added, for use only in getdata requests pertaining to ancestor packages.
# As a getdata request type, it indicates that the sender wants an "ancpkginfo" containing all of the unconfirmed ancestors of a transaction, referenced by wtxid.
# Upon receipt of a "getdata(MSG_ANCPKGINFO)" request, the node should respond with an "ancpkginfo" message corresponding to the transaction's unconfirmed ancestor package, or with "notfound". The wtxid of the requested transaction must be the last item in the "ancpkginfo" response list, as the last item is used to determine which transaction the "ancpkginfo" pertains to.
# The inv type must only be used in a "getdata" message. An "inv(MSG_ANCPKGINFO)" must never be sent. If an "inv(MSG_ANCPKGINFO)" is received, the sender may be disconnected.
# This inv type must only be used if both peers set PKG_RELAY_ANC in their "sendpackages" message. If a "getdata" message with type MSG_ANCPKGINFO is received from a peer with which this type of package relay was not negotiated, no response should be sent and the sender may be disconnected.
====getpkgtxns====
{|
| Field Name || Type || Size || Purpose
|-
|txns_length||CompactSize||1 or 3 bytes|| The number of transactions requested.
|-
|txns||List of wtxids||txns_length * 32|| The wtxids of each transaction in the package.
|}
# The "getpkgtxns" message has the structure defined above, with pchCommand == "getpkgtxns".
# A "getpkgtxns" message should be used to request some list of transactions specified by witness transaction id. It indicates that the node wants to receive either all the specified transactions or none of them. This message is intended to allow nodes to avoid downloading and storing transactions that cannot be validated without each other. The list of transactions does not need to correspond to a previously-received ancpkginfo message.
# Upon receipt of a "getpkgtxns" message, a node should respond with either a "pkgtxns" containing all of the requested transactions in the same order specified in the "getpkgtxns" request or one "notfound" message of type MSG_PKGTXNS and combined hash of all of the wtxids in the "getpkgtxns" request (only one "notfound" message and nothing else), indicating one or more of the transactions is unavailable.
# A "getpkgtxns" message must contain at most 100 wtxids. Upon receipt of a "getpkgtxns" message with more than 100 wtxids, a node may ignore the message (to avoid calculating the combined hash) and disconnect the sender.
# This message must only be used if both peers set PKG_RELAY_PKGTXNS in their "sendpackages" message. If a "getpkgtxns" message is received from a peer with which this type of package relay was not negotiated, no response should be sent and the sender may be disconnected.
====pkgtxns====
{|
| Field Name || Type || Size || Purpose
|-
|txns_length||CompactSize||1 or 3 bytes|| The number of transactions provided.
|-
|txns||List of transactions||variable|| The transactions in the package.
|}
# The "pkgtxns" message has the structure defined above, with pchCommand == "pkgtxns".
# A "pkgtxns" message should contain the transaction data requested using "getpkgtxns".
# A "pkgtxns" message should only be sent to a peer that requested the package using "getpkgtxns". If a node receives an unsolicited package, it may choose to validate the transactions or not, and the sender may be disconnected.
# This message must only be used if both peers set PKG_RELAY_PKGTXNS in their "sendpackages" message. If a "pkgtxns" message is received from a peer with which this type of package relay was not negotiated, no response should be sent and the sender may be disconnected.
====MSG_PKGTXNS====
# A new inv type (MSG_PKGTXNS == 0x6) is added, for use only in "notfound" messages pertaining to package transactions.
# As a "notfound" type, it indicates that the sender is unable to send all the transactions requested in a prior "getpkgtxns" message. The hash used is equal to the combined hash of the wtxids in the getpkgtxns request.
# This inv type should only be used in "notfound" messages, i.e. "inv(MSG_PKGTXNS)" and "getdata(MSG_PKGTXNS)" must never be sent. Upon receipt of an "inv" or "getdata" message of this type, the sender may be disconnected.
# This inv type must only be used if both peers set PKG_RELAY_PKGTXNS in their "sendpackages" message.
==Compatibility==
Older clients remain fully compatible and interoperable after this change. Clients implementing this
protocol will only attempt to send and request packages if agreed upon during the version handshake.
'''Will package relay cause non-package relay nodes to waste bandwidth on low-feerate transactions?'''
If a node supports package relay, it may accept low-feerate transactions (e.g. paying zero fees)
into its mempool, but non-package relay nodes would most likely reject them. To mitigate bandwidth
waste, a package relay node should not announce descendants of below-fee-filter transactions to
non-package relay peers.
'''Is Package Erlay possible?'''
A client using BIP330 reconciliation-based transaction relay (Erlay) is able to use package relay
without interference. After reconciliation, any transaction with unconfirmed ancestors may have
those ancestors resolved using ancestor package relay.
[[File:./bip-0331/package_erlay.png|700px]]
==Extensibility==
This protocol can be extended to include more types of package information in the future, while
continuing to use the same messages for transaction data download. One would define a new package
information message (named "*pkginfo" in the diagram below), allocate its corresponding inv
type (named "*PKGINFO" in the diagram below), and specify how to signal support using the
versions field of "sendpackages" (an additional bit named "PKG_RELAY_*" in the diagram below). A
future version of package relay may allow a sender-initiated dialogue by specifying that the package
info type inv type can be used in an "inv" message.
[[File:./bip-0331/sender_init_future_version.png|700px]]
==Implementation==
Sample implementation for Bitcoin Core: https://github.com/bitcoin/bitcoin/pull/27742
A prerequisite for implementing a safe
package relay protocol is a mempool acceptance policy that safely validates packages of
transactions.
'''Package Mempool Acceptance Policy'''
Accepting packages from peers should not significantly increase a node's DoS attack surface;
processing packages should not permit waste or exhaustion of the node and network's resources.
Additionally, a sensible mempool acceptance policy should result in the most incentive-compatible
subset of the package in the mempool in order to avoid adding more pinning attacks or censorship
vectors. For example, It should not be assumed that packages are CPFPs. An ancestor package may
include a high-feerate parent and low-feerate child; the policy may choose to accept the parent but
not the child. If one or more transactions are policy-invalid, other transactions that are not
dependent upon them should still be considered.
==Acknowledgements==
Thank you to Suhas Daftuar, John Newbery, Anthony Towns, Martin Zumsande, and others for input on the design.
Thank you to Will Clark, Sergi Delgado, Fabian Jahr, John Newbery, Greg Sanders, Stéphan Vuylsteke, Pieter Wuille, and others for input on this document.
Much of this work is inspired by ideas and code by Suhas Daftuar and Antoine Riard.
'''Prior Work on Package Relay'''
* [https://gist.github.com/sdaftuar/8756699bfcad4d3806ba9f3396d4e66a Strawman Proposal]
* [https://github.com/bitcoin/bitcoin/issues/14895 Package relay design questions]
* [https://github.com/bitcoin/bitcoin/pull/16401 Add package acceptance logic to mempool]
* [https://github.com/bitcoin/bitcoin/pull/19621 [RFC] Package-relay: sender-initiated]
==References and Rationale==
================================================
FILE: bip-0337.mediawiki
================================================
== Introduction ==
=== Abstract ===
This document proposes a serialization scheme for compressing Bitcoin transactions. The compressed Bitcoin transactions can reach a serialized size of less than 50% of the original serialized transaction. One method for compressing involves reducing the transaction outpoints in a potentially lossy way. Therefore, it is an optional path for compression. Compressing the outpoints is necessary for compressed transactions to reach less than 70% of the original size.
=== Motivation ===
Typical Bitcoin transactions usually contain a large amount of white space and padding due to specific fields that are often one of a minimal number of possibilities. We can use this fact and a few similar methods to create an encoding for 90% of Bitcoin transactions that are roughly 25-50% smaller.
There exists a working-in-progress app that allows the use of steganography to encode data in images to be passed around via various social media groups. When used in conjunction with this compression scheme and an elligator squared encryption, this would allow for a very secure and private form of broadcasting bitcoin transactions.
=== Rationale ===
The four main methods to achieve a lower transaction size are:
1. Packing transaction metadata before it and each of its inputs and outputs to determine the following data structure.
2. Replacing 32-bit numeric values with either variable-length integers (VarInts) or compact integers (CompactSizes).
3. Using compressed signatures and public key recovery upon decompression.
4. Replacing the 36-byte Outpoint txid/vout pair with a block height and index.
=== Backwards Compatibility ===
There are no concerns with backwards compatibility.
=== Specification ===
==== Primitives ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| CompactSize || 1-5 Bytes || For 0-253, encode the value directly in one byte. For 254-65535, encode 254 followed by two little-endian bytes. For 65536-(2^32-1), encode 255 followed by four little-endian bytes.
|-
| CompactSize Flag || 2 Bits || 1, 2, or 3 indicate literal values. 0 indicates that a CompactSize encoding of the value will follow.
|-
| VarInt || 1+ Bytes || 7-bit little-endian encoding, with each 7-bit word encoded in a byte. The highest bit of each byte is one if more bytes follow, and 0 for the last byte.
|-
| VLP-Bytestream || 2+ Bytes || A VarInt Length Prefixed Bytestream. It uses the prefixed VarInt to determine the length of the following byte stream.
|}
==== General Schema ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Transaction metadata || 1 Bytes || Information on the structure of the transaction. See [[#transaction-metadata|Transaction Metadata]]
|-
| Version || 0-5 Bytes || If present according to the metadata field, a CompactSize encoding of the transaction version.
|-
| Input Count || 0-5 Bytes || If present according to the metadata field, a CompactSize encoding of the transaction input count.
|-
| Output Count || 0-5 Bytes || If present according to the metadata field, a CompactSize encoding of the transaction output count.
|-
| LockTime || 0-5 Bytes || If present according to the metadata field, a CompactSize encoding of the transaction LockTime.
|-
| Minimum Blockheight || 1-5 Bytes || If present according to the metadata field, a VarInt encoding of the minimum block height for transaction compressed inputs and LockTime.
|-
| Input Metadata+Output Metadata || 1+ Bytes || An encoding containing the metadata for all the inputs followed by all the outputs of the transaction. For each input, see [[#input-metadata|Input Metadata]], and for each output, see [[#output-metadata|Output Metadata]].
|-
| Input Data || 66+ Bytes || See [[#input-data|Input Data]].
|-
| Output Data || 3+ Bytes || See [[#output-data|Output Data]].
|}
==== Transaction Metadata ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Version || 2 Bits || A CompactSize flag for the transaction version.
|-
| Input Count || 2 Bits || A CompactSize flag for the transaction input count.
|-
| Output Count || 2 Bits || A CompactSize flag for the transaction output count.
|-
| LockTime || 1 Bit || A boolean to indicate if the transaction has a LockTime.
|-
| Minimum Blockheight || 1 Bit || A boolean to indicate if the transaction minimum block height is greater than zero.
|}
==== Input Metadata ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Compressed Signature || 1 Bit || A Boolean to determine if this input's signature is compressed. The signature is only compressed for P2TR on a key spend and for P2SH when it is a wrapped P2SH-WPKH.
|-
| Standard Hash || 1 Bit || A Boolean to determine if this input's signature hash type is standard (0x00 for Taproot, 0x01 for Legacy/Segwit).
|-
| Standard Sequence || 2 Bits || A CompactSize flag for this input's sequence. Encode literal values as follows: 1 = 0x00000000, 2 = 0xFFFFFFFE, 3 = 0xFFFFFFFF.
|-
| Compressed OutPoint || 1 bit || A Boolean to determine if the input's outpoint is compressed.
|}
==== Output Metadata ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Encoded Script Type || 3 Bits || [[#script-type-encoding|Encoded Script Type]].
|}
==== Script Type Encoding ====
{| class="wikitable" style="margin:auto"
|-
! Script Type !! Value
|-
| Uncompressed Custom Script || 0b000
|-
| Uncompressed P2PK || 0b001
|-
| Compressed P2PK || 0b010
|-
| P2PKH || 0b011
|-
| P2SH || 0b100
|-
| P2WPKH || 0b101
|-
| P2WSH || 0b110
|-
| P2TR || 0b111
|}
==== Input Data ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Outpoint || 2-37 Bytes || The Outpoint Txid/Vout are determined to be compressed or otherwise by the "Compressed Outpoint" Boolean in the input metadata. For each compressed outpoint see [[#compressed-outpoint|Compressed Outpoint]]. For each uncompressed outpoint see [[#uncompressed-outpoint|Uncompressed Outpoint]].
|-
| Signature || 64+ Bytes || The Signature is determined to be compressed or otherwise by the output script of the previous transaction. For each compressed signature see [[#compressed-signature|Compressed Signature]]. For each uncompressed signature see [[#uncompressed-signature|Uncompressed Signature]].
|-
| Sequence || 0-5 Bytes || If present due to a non-standard sequence, a VarInt encoding of the sequence.
|}
==== Compressed Outpoint ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Txid Block Height || 1-5 Bytes || A VarInt containing the offset from Minimum Blockheight for this Txid.
|-
| Txid Block Index || 1-5 Bytes || A VarInt containing the flattened index from the Txid block height for the Vout.
|}
==== Uncompressed Outpoint ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Txid || 32 Bytes || Contains the 32 Byte Txid.
|-
| Vout || 1-5 Bytes || A CompactSize Containing the Vout of the Txid.
|}
==== Compressed Signature ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Signature || 64 Bytes || Contains the 64 Byte signature.
|-
| Pubkey Hash || 0-20 Bytes || If input is P2SH-P2WPKH contains the 20 byte hash of the public key.
|-
| Hash Type || 0-1 Bytes || An Optional Byte containing the Hash Type if it was non-standard.
|}
==== Uncompressed Signature ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Signature || 2+ Bytes || A VLP-Bytestream containing the signature.
|}
==== Output Data ====
{| class="wikitable" style="margin:auto"
|-
! Name !! Width !! Description
|-
| Output Script || 2+ Bytes || A VLP-Bytestream containing the output script.
|-
| Amount || 1-9 Bytes || A VarInt containing the output amount.
|}
==== Ideal Transaction ====
The compression scheme was designed to be optimal for a "typical" transaction, spending a few close-in-age inputs and having one or two outputs. Here are size
values for such a transaction, which demonstrate the effectiveness of the compression.
{| class="wikitable" style="margin:auto"
|-
! Field !! Requirements !! Savings Up To
|-
| Version || Less than four || 30 Bits
|-
| Input Count || Less than four || 30 Bits
|-
| Output Count || Less than four || 30 Bits
|-
| LockTime || 0 || 30 Bits
|-
| Input Sequence || 0x00, 0xFFFFFFFE, or 0xFFFFFFFF || 62 Bits For Each Input
|-
| Input Txid || Compressed Outpoint || 23 - 31 Bytes For Each Input
|-
| Input Vout || Compressed Outpoint || (-1) - 3 Bytes For Each Input
|-
| Input Signature || Non-custom Script Signing || 40 - 72 Bytes For Each Legacy Input
|-
| Input Hash Type || 0x00 for Taproot, 0x01 for Legacy || 7 Bits For Each Input
|-
| Output Script || Non-custom Scripts || 2 - 5 Bytes For Each Output
|-
| Output Amount || No Restrictions || (-1) - 7 Bytes For Each Output
|}
=== Reference Implementation ===
This reference implementation adds two new RPC endpoints, compressrawtransaction and decompressrawtransaction. The first accepts a raw hex-encoded transaction and returns a compact hex-encoded transaction; also included in the output is a list of warnings to help ensure there are no unexpected uncompressed values. The second accepts a compact hex transaction and returns the uncompressed raw hex-encoded transaction.
https://github.com/bitcoin/bitcoin/pull/29134
=== Test Vectors ===
==== Taproot ====
===== Uncompressed =====
020000000001017ad1d0cc314504ec06f1b5c786c50cf3cda30bd5be88cf08ead571b0ce7481fb0000000000fdffffff0188130000000000001600142da377ed4978fefa043a58489912f8e28e16226201408ce65b3170d3fbc68e3b6980650514dc53565f915d14351f83050ff50c8609495b7aa96271c3c99cdac1a92b1b45e77a4a870251fc1673596793adf2494565e500000000
===== Compressed =====
96b1ec7f968001b0218ce65b3170d3fbc68e3b6980650514dc53565f915d14351f83050ff50c8609495b7aa96271c3c99cdac1a92b1b45e77a4a870251fc1673596793adf2494565e58efefefe7d2da377ed4978fefa043a58489912f8e28e162262a608
==== P2WPKH ====
===== Uncompressed =====
0200000000010144bcf05ab48b8789268a7ca07133241ad654c0739ac7165015b2d669eadb10ea0000000000fdffffff0188130000000000001600142da377ed4978fefa043a58489912f8e28e16226202473044022043ab639a98dfbc704f16a35bf25b8b72acb4cb928fd772285f1fcf63725caa85022001c9ff354504e7024708bce61f30370c8db13da8170cef4e8e4c4cdad0f71bfe0121030072484c24705512bfb1f7f866d95f808d81d343e552bc418113e1b9a1da0eb400000000
===== Compressed =====
96b1ec71968001932643ab639a98dfbc704f16a35bf25b8b72acb4cb928fd772285f1fcf63725caa8501c9ff354504e7024708bce61f30370c8db13da8170cef4e8e4c4cdad0f71bfe8efefefe7d2da377ed4978fefa043a58489912f8e28e162262a608
==== P2SH-P2WPKH ====
===== Uncompressed =====
0200000000010192fb2e4332b43dc9a73febba67f3b7d97ba890673cb08efde2911330f77bbdfc00000000171600147a1979232206857167b401fdac1ffbf33f8204fffdffffff0188130000000000001600142da377ed4978fefa043a58489912f8e28e16226202473044022041eb682e63c25b85a5a400b11d41cf4b9c25f309090a5f3e0b69dc15426da90402205644ddc3d5179bab49cce4bf69ebfaeab1afa34331c1a0a70be2927d2836b0e8012103c483f1b1bd24dd23b3255a68d87ef9281f9d080fd707032ccb81c1cc56c5b00200000000
===== Compressed =====
96b1ec7c9e8001981641eb682e63c25b85a5a400b11d41cf4b9c25f309090a5f3e0b69dc15426da9045644ddc3d5179bab49cce4bf69ebfaeab1afa34331c1a0a70be2927d2836b0e87a1979232206857167b401fdac1ffbf33f8204ff8efefefe7d2da377ed4978fefa043a58489912f8e28e162262a608
==== P2PKH ====
===== Uncompressed =====
02000000015f5be26862482fe2fcc900f06ef26ee256fb205bc4773e5a402d0c1b88b82043000000006a473044022031a20f5d9212023b510599c9d53d082f8e07faaa2d51482e078f8e398cb50d770220635abd99220ad713a081c4f20b83cb3f491ed8bd032cb151a3521ed144164d9c0121027977f1b6357cead2df0a0a19570088a1eb9115468b2dfa01439493807d8f1294fdffffff0188130000000000001600142da377ed4978fefa043a58489912f8e28e16226200000000
===== Compressed =====
96b1ec7c968001981431a20f5d9212023b510599c9d53d082f8e07faaa2d51482e078f8e398cb50d77635abd99220ad713a081c4f20b83cb3f491ed8bd032cb151a3521ed144164d9c8efefefe7d2da377ed4978fefa043a58489912f8e28e162262a608
== Acknowledgements ==
Thank you to Andrew Poelstra, who helped invent and develop the ideas in the proposal and the code for reference implementation.
================================================
FILE: bip-0338.mediawiki
================================================
==Abstract==
This BIP describes a change to the p2p protocol to allow a node to tell a peer
that a connection will not be used for transaction relay, to support
block-relay-only connections that are currently in use on the network.
==Motivation==
This proposal is part of an effort to increase the number of inbound
connections that a peer can service, by distinguishing peers which will not
relay transactions from those that do.
Since 2019, software has been deployed[1] which initiates
connections on the Bitcoin network and sets the transaction relay field
(introduced by BIP 37 and also defined in BIP 60) to false, to prevent
transaction relay from occurring on the connection. Additionally, addr messages
received from the peer are ignored by this software.
The purpose of these connections is two-fold: by making additional
low-bandwidth connections on which blocks can propagate, the robustness of a
node to network partitioning attacks is strengthened. Additionally, by not
relaying transactions and ignoring received addresses, the ability of an
adversary to learn the complete network graph (or a subgraph) is reduced[2],
which in turn increases the cost or difficulty to an attacker seeking to carry
out a network partitioning attack (when compared with having such knowledge).
The low-bandwidth / minimal-resource nature of these connections is currently
known only by the initiator of the connection; this is because the transaction
relay field in the version message is not a permanent setting for the lifetime
of the connection. Consequently, a node receiving an inbound connection with
transaction relay disabled cannot distinguish between a peer that will never
enable transaction relay (as described in BIP 37) and one that will. Moreover,
the node also cannot determine that the incoming connection will ignore relayed
addresses; with that knowledge a node would likely choose other peers to
receive announced addresses instead.
This proposal adds a new, optional message that a node can send a peer when
initiating a connection to that peer, to indicate that connection should not be
used for transaction relay for the connection's lifetime. In addition, without
a current mechanism to negotiate whether addresses should be relayed on a
connection, this BIP suggests that address messages not be sent on links where
transaction relay has been disabled.
After this BIP is deployed, nodes could more easily implement inbound
connection limiting that differentiates low-resource nodes (such as those
sending disabletx) from full-relay peers, potentially allowing for an increase
in the number of block-relay-only connections that can be made on the network.
==Specification==
# A new disabletx message is added, which is defined as an empty message with message type set to "disabletx".
# The protocol version of nodes implementing this BIP must be set to 70017 or higher.
# If a node sets the transaction relay field in the version message to a peer to false, then the disabletx message MAY also be sent in response to a version message from that peer if the peer's protocol version is >= 70017. If sent, the disabletx message MUST be sent prior to sending a verack.
# A node MUST NOT send the disabletx message if the transaction relay field in the version message is omitted or set to true.
# A node that has sent or received a disabletx message to/from a peer MUST NOT send any of these messages to the peer:
## inv messages for transactions
## notfound messages for transactions
## getdata messages for transactions
## getdata messages for merkleblock (BIP 37)
## filteradd/filterload/filterclear (BIP 37)
## feefilter (BIP 133)
## mempool (BIP 35)
## tx message
# It is RECOMMENDED that a node that has sent or received a disabletx message to/from a peer not send any of these messages to the peer:
## addr/getaddr
## addrv2 (BIP 155)
# The behavior regarding sending or processing other message types is not specified by this BIP.
# Nodes MAY decide to not remain connected to peers that send this message (for example, if trying to find a peer that will relay transactions).
==Compatibility==
Nodes with protocol version >= 70017 that do not implement this BIP, and nodes
with protocol version < 70017, will continue to remain compatible with
implementing software: transactions would not be relayed to peers sending the
disabletx message (provided that BIP 37 or BIP 60 has been implemented), and while
periodic address relay may still take place, software implementing this BIP
should not be disconnecting such peers solely for that reason.
Disabling address relay is suggested but not required by this BIP, to allow for
future protocol extensions that might specify more carefully how address relay
is to be negotiated. This BIP's recommendations for software to not relay
addresses is intended to be interpreted as guidance in the absence of any such
future protocol extension, to accommodate existing software behavior.
Note that all messages specified in BIP 152, including blocktxn and
getblocktxn, are permitted between peers that have sent/received a disabletx
message, subject to the feature negotiation of BIP 152.
This proposal is compatible with, but independent of, BIP 37.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/20726
==References==
# Bitcoin Core has [https://github.com/bitcoin/bitcoin/pull/15759 implemented this functionality] since version 0.19.0.1, released in November 2019.
# For example, see https://www.cs.umd.edu/projects/coinscope/coinscope.pdf and https://arxiv.org/pdf/1812.00942.pdf.
==Copyright==
This BIP is licensed under the 2-clause BSD license.
================================================
FILE: bip-0339.mediawiki
================================================
==Abstract==
This BIP describes two changes to the p2p protocol to support transaction relay
based on the BIP 141 wtxid of a transaction, rather than its txid.
==Motivation==
Historically, the inv messages sent on the Bitcoin peer-to-peer network to
announce transactions refer to transactions by their txid, which is a hash of
the transaction that does not include the witness (see BIP 141). This has been
the case even since Segregated Witness (BIP 141/143/144) has been adopted by
the network.
Not committing to the witness in transaction announcements creates
inefficiencies: because a transaction's witness can be malleated without
altering the txid, a node in receipt of a witness transaction that the node
does not accept will generally still download that same transaction when
announced by other peers. This is because the alternative -- of not downloading
a given txid after rejecting a transaction with that txid -- would allow a
third party to interfere with transaction relay by malleating a transaction's
witness and announcing the resulting invalid transaction to nodes, preventing
relay of the valid version of the transaction as well.
We can eliminate this concern by using the wtxid in place of the txid when
announcing and fetching transactions.
==Specification==
# A new wtxidrelay message is added, which is defined as an empty message where pchCommand == "wtxidrelay".
# The protocol version of nodes implementing this BIP must be set to 70016 or higher.
# The wtxidrelay message MUST be sent in response to a version message from a peer whose protocol version is >= 70016 and prior to sending a verack. A wtxidrelay message received after a verack message MUST be ignored or treated as invalid.
# A new inv type MSG_WTX (0x00000005) is added, for use in both inv messages and getdata requests, indicating that the hash being referenced is a transaction's wtxid. In the case of getdata requests, MSG_WTX implies that the transaction being requested should be serialized with witness as well, as described in BIP 144.
# After a node has received a wtxidrelay message from a peer, the node MUST use the MSG_WTX inv type when announcing transactions to that peer.
# After a node has received a wtxidrelay message from a peer, the node SHOULD use a MSG_WTX getdata message to request any announced transactions. A node MAY still request transactions from that peer using MSG_TX getdata messages, such as for transactions not recently announced by that peer (like the parents of recently announced transactions).
==Backward compatibility==
As wtxid-based transaction relay is only enabled between peers that both support it, older clients remain fully compatible and interoperable after this change.
==Implementation==
https://github.com/bitcoin/bitcoin/pull/18044
==Copyright==
This BIP is licensed under the 2-clause BSD license.
================================================
FILE: bip-0340/LICENSE
================================================
BSD-2-Clause OR MIT OR CC0-1.0
The contents of this directory are provided under one of the following sets of
terms, at your choice:
- The BSD-2-Clause License
https://opensource.org/license/BSD-2-Clause
- The MIT License
https://opensource.org/license/MIT
- CC0 1.0
https://creativecommons.org/publicdomain/zero/1.0/
================================================
FILE: bip-0340/reference.py
================================================
from typing import Tuple, Optional, Any
import hashlib
# Set DEBUG to True to get a detailed debug output including
# intermediate values during key generation, signing, and
# verification. This is implemented via calls to the
# debug_print_vars() function.
#
# If you want to print values on an individual basis, use
# the pretty() function, e.g., print(pretty(foo)).
DEBUG = False
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
# Points are tuples of X and Y coordinates and the point at infinity is
# represented by the None keyword.
G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8)
Point = Tuple[int, int]
# This implementation can be sped up by storing the midstate after hashing
# tag_hash instead of rehashing it all the time.
def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
def is_infinite(P: Optional[Point]) -> bool:
return P is None
def x(P: Point) -> int:
assert not is_infinite(P)
return P[0]
def y(P: Point) -> int:
assert not is_infinite(P)
return P[1]
def point_add(P1: Optional[Point], P2: Optional[Point]) -> Optional[Point]:
if P1 is None:
return P2
if P2 is None:
return P1
if (x(P1) == x(P2)) and (y(P1) != y(P2)):
return None
if P1 == P2:
lam = (3 * x(P1) * x(P1) * pow(2 * y(P1), p - 2, p)) % p
else:
lam = ((y(P2) - y(P1)) * pow(x(P2) - x(P1), p - 2, p)) % p
x3 = (lam * lam - x(P1) - x(P2)) % p
return (x3, (lam * (x(P1) - x3) - y(P1)) % p)
def point_mul(P: Optional[Point], n: int) -> Optional[Point]:
R = None
for i in range(256):
if (n >> i) & 1:
R = point_add(R, P)
P = point_add(P, P)
return R
def bytes_from_int(x: int) -> bytes:
return x.to_bytes(32, byteorder="big")
def bytes_from_point(P: Point) -> bytes:
return bytes_from_int(x(P))
def xor_bytes(b0: bytes, b1: bytes) -> bytes:
return bytes(x ^ y for (x, y) in zip(b0, b1))
def lift_x(x: int) -> Optional[Point]:
if x >= p:
return None
y_sq = (pow(x, 3, p) + 7) % p
y = pow(y_sq, (p + 1) // 4, p)
if pow(y, 2, p) != y_sq:
return None
return (x, y if y & 1 == 0 else p-y)
def int_from_bytes(b: bytes) -> int:
return int.from_bytes(b, byteorder="big")
def hash_sha256(b: bytes) -> bytes:
return hashlib.sha256(b).digest()
def has_even_y(P: Point) -> bool:
assert not is_infinite(P)
return y(P) % 2 == 0
def pubkey_gen(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= n - 1):
raise ValueError('The secret key must be an integer in the range 1..n-1.')
P = point_mul(G, d0)
assert P is not None
return bytes_from_point(P)
def schnorr_sign(msg: bytes, seckey: bytes, aux_rand: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= n - 1):
raise ValueError('The secret key must be an integer in the range 1..n-1.')
if len(aux_rand) != 32:
raise ValueError('aux_rand must be 32 bytes instead of %i.' % len(aux_rand))
P = point_mul(G, d0)
assert P is not None
d = d0 if has_even_y(P) else n - d0
t = xor_bytes(bytes_from_int(d), tagged_hash("BIP0340/aux", aux_rand))
k0 = int_from_bytes(tagged_hash("BIP0340/nonce", t + bytes_from_point(P) + msg)) % n
if k0 == 0:
raise RuntimeError('Failure. This happens only with negligible probability.')
R = point_mul(G, k0)
assert R is not None
k = n - k0 if not has_even_y(R) else k0
e = int_from_bytes(tagged_hash("BIP0340/challenge", bytes_from_point(R) + bytes_from_point(P) + msg)) % n
sig = bytes_from_point(R) + bytes_from_int((k + e * d) % n)
debug_print_vars()
if not schnorr_verify(msg, bytes_from_point(P), sig):
raise RuntimeError('The created signature does not pass verification.')
return sig
def schnorr_verify(msg: bytes, pubkey: bytes, sig: bytes) -> bool:
if len(pubkey) != 32:
raise ValueError('The public key must be a 32-byte array.')
if len(sig) != 64:
raise ValueError('The signature must be a 64-byte array.')
P = lift_x(int_from_bytes(pubkey))
r = int_from_bytes(sig[0:32])
s = int_from_bytes(sig[32:64])
if (P is None) or (r >= p) or (s >= n):
debug_print_vars()
return False
e = int_from_bytes(tagged_hash("BIP0340/challenge", sig[0:32] + pubkey + msg)) % n
R = point_add(point_mul(G, s), point_mul(P, n - e))
if (R is None) or (not has_even_y(R)) or (x(R) != r):
debug_print_vars()
return False
debug_print_vars()
return True
#
# The following code is only used to verify the test vectors.
#
import csv
import os
import sys
def test_vectors() -> bool:
all_passed = True
with open(os.path.join(sys.path[0], 'test-vectors.csv'), newline='') as csvfile:
reader = csv.reader(csvfile)
reader.__next__()
for row in reader:
(index, seckey_hex, pubkey_hex, aux_rand_hex, msg_hex, sig_hex, result_str, comment) = row
pubkey = bytes.fromhex(pubkey_hex)
msg = bytes.fromhex(msg_hex)
sig = bytes.fromhex(sig_hex)
result = result_str == 'TRUE'
print('\nTest vector', ('#' + index).rjust(3, ' ') + ':')
if seckey_hex != '':
seckey = bytes.fromhex(seckey_hex)
pubkey_actual = pubkey_gen(seckey)
if pubkey != pubkey_actual:
print(' * Failed key generation.')
print(' Expected key:', pubkey.hex().upper())
print(' Actual key:', pubkey_actual.hex().upper())
all_passed = False
aux_rand = bytes.fromhex(aux_rand_hex)
try:
sig_actual = schnorr_sign(msg, seckey, aux_rand)
if sig == sig_actual:
print(' * Passed signing test.')
else:
print(' * Failed signing test.')
print(' Expected signature:', sig.hex().upper())
print(' Actual signature:', sig_actual.hex().upper())
all_passed = False
except RuntimeError as e:
print(' * Signing test raised exception:', e)
all_passed = False
result_actual = schnorr_verify(msg, pubkey, sig)
if result == result_actual:
print(' * Passed verification test.')
else:
print(' * Failed verification test.')
print(' Expected verification result:', result)
print(' Actual verification result:', result_actual)
if comment:
print(' Comment:', comment)
all_passed = False
print()
if all_passed:
print('All test vectors passed.')
else:
print('Some test vectors failed.')
return all_passed
#
# The following code is only used for debugging
#
import inspect
def pretty(v: Any) -> Any:
if isinstance(v, bytes):
return '0x' + v.hex()
if isinstance(v, int):
return pretty(bytes_from_int(v))
if isinstance(v, tuple):
return tuple(map(pretty, v))
return v
def debug_print_vars() -> None:
if DEBUG:
current_frame = inspect.currentframe()
assert current_frame is not None
frame = current_frame.f_back
assert frame is not None
print(' Variables in function ', frame.f_code.co_name, ' at line ', frame.f_lineno, ':', sep='')
for var_name, var_val in frame.f_locals.items():
print(' ' + var_name.rjust(11, ' '), '==', pretty(var_val))
if __name__ == '__main__':
test_vectors()
================================================
FILE: bip-0340/test-vectors.csv
================================================
index,secret key,public key,aux_rand,message,signature,verification result,comment
0,0000000000000000000000000000000000000000000000000000000000000003,F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9,0000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000,E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0,TRUE,
1,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,0000000000000000000000000000000000000000000000000000000000000001,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A,TRUE,
2,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9,DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8,C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906,7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7,TRUE,
3,0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710,25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3,TRUE,test fails if msg is reduced modulo p or n
4,,D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9,,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4,TRUE,
5,,EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key not on the curve
6,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2,FALSE,has_even_y(R) is false
7,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD,FALSE,negated message
8,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6,FALSE,negated s value
9,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051,FALSE,sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0
10,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197,FALSE,sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1
11,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is not an X coordinate on the curve
12,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is equal to field size
13,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,sig[32:64] is equal to curve order
14,,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key is not a valid X coordinate because it exceeds the field size
15,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,,71535DB165ECD9FBBC046E5FFAEA61186BB6AD436732FCCC25291A55895464CF6069CE26BF03466228F19A3A62DB8A649F2D560FAC652827D1AF0574E427AB63,TRUE,message of size 0 (added 2022-12)
16,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,11,08A20A0AFEF64124649232E0693C583AB1B9934AE63B4C3511F3AE1134C6A303EA3173BFEA6683BD101FA5AA5DBC1996FE7CACFC5A577D33EC14564CEC2BACBF,TRUE,message of size 1 (added 2022-12)
17,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,0102030405060708090A0B0C0D0E0F1011,5130F39A4059B43BC7CAC09A19ECE52B5D8699D1A71E3C52DA9AFDB6B50AC370C4A482B77BF960F8681540E25B6771ECE1E5A37FD80E5A51897C5566A97EA5A5,TRUE,message of size 17 (added 2022-12)
18,0340034003400340034003400340034003400340034003400340034003400340,778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117,0000000000000000000000000000000000000000000000000000000000000000,99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999,403B12B0D8555A344175EA7EC746566303321E5DBFA8BE6F091635163ECA79A8585ED3E3170807E7C03B720FC54C7B23897FCBA0E9D0B4A06894CFD249F22367,TRUE,message of size 100 (added 2022-12)
================================================
FILE: bip-0340/test-vectors.py
================================================
import sys
from reference import *
def is_square(x):
return int(pow(x, (p - 1) // 2, p)) == 1
def has_square_y(P):
"""Determine if P has a square Y coordinate. Used in an earlier draft of BIP340."""
assert not is_infinite(P)
return is_square(P[1])
def vector0():
seckey = bytes_from_int(3)
msg = bytes_from_int(0)
aux_rand = bytes_from_int(0)
sig = schnorr_sign(msg, seckey, aux_rand)
pubkey = pubkey_gen(seckey)
# We should have at least one test vector where the seckey needs to be
# negated and one where it doesn't. In this one the seckey doesn't need to
# be negated.
x = int_from_bytes(seckey)
P = point_mul(G, x)
assert(y(P) % 2 == 0)
# For historical reasons (pubkey tiebreaker was squareness and not evenness)
# we should have at least one test vector where the point reconstructed
# from the public key has a square and one where it has a non-square Y
# coordinate. In this one Y is non-square.
pubkey_point = lift_x(int_from_bytes(pubkey))
assert(not has_square_y(pubkey_point))
# For historical reasons (R tiebreaker was squareness and not evenness)
# we should have at least one test vector where the point reconstructed
# from the R.x coordinate has a square and one where it has a non-square Y
# coordinate. In this one Y is non-square.
R = lift_x(int_from_bytes(sig[0:32]))
assert(not has_square_y(R))
return (seckey, pubkey, aux_rand, msg, sig, "TRUE", None)
def vector1():
seckey = bytes_from_int(0xB7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF)
msg = bytes_from_int(0x243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89)
aux_rand = bytes_from_int(1)
sig = schnorr_sign(msg, seckey, aux_rand)
# The point reconstructed from the R.x coordinate has a square Y coordinate.
R = lift_x(int_from_bytes(sig[0:32]))
assert(has_square_y(R))
return (seckey, pubkey_gen(seckey), aux_rand, msg, sig, "TRUE", None)
def vector2():
seckey = bytes_from_int(0xC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9)
msg = bytes_from_int(0x7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C)
aux_rand = bytes_from_int(0xC87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906)
sig = schnorr_sign(msg, seckey, aux_rand)
# The point reconstructed from the public key has a square Y coordinate.
pubkey = pubkey_gen(seckey)
pubkey_point = lift_x(int_from_bytes(pubkey))
assert(has_square_y(pubkey_point))
# This signature vector would not verify if the implementer checked the
# evenness of the X coordinate of R instead of the Y coordinate.
R = lift_x(int_from_bytes(sig[0:32]))
assert(R[0] % 2 == 1)
return (seckey, pubkey, aux_rand, msg, sig, "TRUE", None)
def vector3():
seckey = bytes_from_int(0x0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710)
# Need to negate this seckey before signing
x = int_from_bytes(seckey)
P = point_mul(G, x)
assert(y(P) % 2 != 0)
msg = bytes_from_int(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
aux_rand = bytes_from_int(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
sig = schnorr_sign(msg, seckey, aux_rand)
return (seckey, pubkey_gen(seckey), aux_rand, msg, sig, "TRUE", "test fails if msg is reduced modulo p or n")
# Signs with a given nonce. This can be INSECURE and is only INTENDED FOR
# GENERATING TEST VECTORS. Results in an invalid signature if y(kG) is not
# even.
def insecure_schnorr_sign_fixed_nonce(msg, seckey0, k):
if len(msg) != 32:
raise ValueError('The message must be a 32-byte array.')
seckey0 = int_from_bytes(seckey0)
if not (1 <= seckey0 <= n - 1):
raise ValueError('The secret key must be an integer in the range 1..n-1.')
P = point_mul(G, seckey0)
seckey = seckey0 if has_even_y(P) else n - seckey0
R = point_mul(G, k)
e = int_from_bytes(tagged_hash("BIP0340/challenge", bytes_from_point(R) + bytes_from_point(P) + msg)) % n
return bytes_from_point(R) + bytes_from_int((k + e * seckey) % n)
# Creates a signature with a small x(R) by using k = -1/2
def vector4():
one_half = n - 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0
seckey = bytes_from_int(0x763758E5CBEEDEE4F7D3FC86F531C36578933228998226672F13C4F0EBE855EB)
msg = bytes_from_int(0x4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703)
sig = insecure_schnorr_sign_fixed_nonce(msg, seckey, one_half)
return (None, pubkey_gen(seckey), None, msg, sig, "TRUE", None)
default_seckey = bytes_from_int(0xB7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF)
default_msg = bytes_from_int(0x243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89)
default_aux_rand = bytes_from_int(0xC87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906)
# Public key is not on the curve
def vector5():
# This creates a dummy signature that doesn't have anything to do with the
# public key.
seckey = default_seckey
msg = default_msg
sig = schnorr_sign(msg, seckey, default_aux_rand)
pubkey_int = 0xEEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34
pubkey = bytes_from_int(pubkey_int)
assert(lift_x(pubkey_int) is None)
return (None, pubkey, None, msg, sig, "FALSE", "public key not on the curve")
def vector6():
seckey = default_seckey
msg = default_msg
k = 6
sig = insecure_schnorr_sign_fixed_nonce(msg, seckey, k)
# Y coordinate of R is not even
R = point_mul(G, k)
assert(not has_even_y(R))
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "has_even_y(R) is false")
def vector7():
seckey = default_seckey
msg = int_from_bytes(default_msg)
neg_msg = bytes_from_int(n - msg)
sig = schnorr_sign(neg_msg, seckey, default_aux_rand)
return (None, pubkey_gen(seckey), None, bytes_from_int(msg), sig, "FALSE", "negated message")
def vector8():
seckey = default_seckey
msg = default_msg
sig = schnorr_sign(msg, seckey, default_aux_rand)
sig = sig[0:32] + bytes_from_int(n - int_from_bytes(sig[32:64]))
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "negated s value")
def bytes_from_point_inf0(P):
if P == None:
return bytes_from_int(0)
return bytes_from_int(P[0])
def vector9():
seckey = default_seckey
msg = default_msg
# Override bytes_from_point in schnorr_sign to allow creating a signature
# with k = 0.
k = 0
bytes_from_point_tmp = bytes_from_point.__code__
bytes_from_point.__code__ = bytes_from_point_inf0.__code__
sig = insecure_schnorr_sign_fixed_nonce(msg, seckey, k)
bytes_from_point.__code__ = bytes_from_point_tmp
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0")
def bytes_from_point_inf1(P):
if P == None:
return bytes_from_int(1)
return bytes_from_int(P[0])
def vector10():
seckey = default_seckey
msg = default_msg
# Override bytes_from_point in schnorr_sign to allow creating a signature
# with k = 0.
k = 0
bytes_from_point_tmp = bytes_from_point.__code__
bytes_from_point.__code__ = bytes_from_point_inf1.__code__
sig = insecure_schnorr_sign_fixed_nonce(msg, seckey, k)
bytes_from_point.__code__ = bytes_from_point_tmp
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1")
# It's cryptographically impossible to create a test vector that fails if run
# in an implementation which merely misses the check that sig[0:32] is an X
# coordinate on the curve. This test vector just increases test coverage.
def vector11():
seckey = default_seckey
msg = default_msg
sig = schnorr_sign(msg, seckey, default_aux_rand)
# Replace R's X coordinate with an X coordinate that's not on the curve
x_not_on_curve = 0x4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D
assert(lift_x(x_not_on_curve) is None)
sig = bytes_from_int(x_not_on_curve) + sig[32:64]
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "sig[0:32] is not an X coordinate on the curve")
# It's cryptographically impossible to create a test vector that fails if run
# in an implementation which merely misses the check that sig[0:32] is smaller
# than the field size. This test vector just increases test coverage.
def vector12():
seckey = default_seckey
msg = default_msg
sig = schnorr_sign(msg, seckey, default_aux_rand)
# Replace R's X coordinate with an X coordinate that's equal to field size
sig = bytes_from_int(p) + sig[32:64]
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "sig[0:32] is equal to field size")
# It's cryptographically impossible to create a test vector that fails if run
# in an implementation which merely misses the check that sig[32:64] is smaller
# than the curve order. This test vector just increases test coverage.
def vector13():
seckey = default_seckey
msg = default_msg
sig = schnorr_sign(msg, seckey, default_aux_rand)
# Replace s with a number that's equal to the curve order
sig = sig[0:32] + bytes_from_int(n)
return (None, pubkey_gen(seckey), None, msg, sig, "FALSE", "sig[32:64] is equal to curve order")
# Test out of range pubkey
# It's cryptographically impossible to create a test vector that fails if run
# in an implementation which accepts out of range pubkeys because we can't find
# a secret key for such a public key and therefore can not create a signature.
# This test vector just increases test coverage.
def vector14():
# This creates a dummy signature that doesn't have anything to do with the
# public key.
seckey = default_seckey
msg = default_msg
sig = schnorr_sign(msg, seckey, default_aux_rand)
pubkey_int = p + 1
pubkey = bytes_from_int(pubkey_int)
assert(lift_x(pubkey_int) is None)
# If an implementation would reduce a given public key modulo p then the
# pubkey would be valid
assert(lift_x(pubkey_int % p) is not None)
return (None, pubkey, None, msg, sig, "FALSE", "public key is not a valid X coordinate because it exceeds the field size")
def varlen_vector(msg_int):
seckey = bytes_from_int(int(16 * "0340", 16))
pubkey = pubkey_gen(seckey)
aux_rand = bytes_from_int(0)
msg = msg_int.to_bytes((msg_int.bit_length() + 7) // 8, "big")
sig = schnorr_sign(msg, seckey, aux_rand)
comment = "message of size %d (added 2022-12)"
return (seckey, pubkey, aux_rand, msg, sig, "TRUE", comment % len(msg))
vector15 = lambda : varlen_vector(0)
vector16 = lambda : varlen_vector(0x11)
vector17 = lambda : varlen_vector(0x0102030405060708090A0B0C0D0E0F1011)
vector18 = lambda : varlen_vector(int(100 * "99", 16))
vectors = [
vector0(),
vector1(),
vector2(),
vector3(),
vector4(),
vector5(),
vector6(),
vector7(),
vector8(),
vector9(),
vector10(),
vector11(),
vector12(),
vector13(),
vector14(),
vector15(),
vector16(),
vector17(),
vector18(),
]
# Converts the byte strings of a test vector into hex strings
def bytes_to_hex(seckey, pubkey, aux_rand, msg, sig, result, comment):
return (seckey.hex().upper() if seckey is not None else None, pubkey.hex().upper(), aux_rand.hex().upper() if aux_rand is not None else None, msg.hex().upper(), sig.hex().upper(), result, comment)
vectors = list(map(lambda vector: bytes_to_hex(vector[0], vector[1], vector[2], vector[3], vector[4], vector[5], vector[6]), vectors))
def print_csv(vectors):
writer = csv.writer(sys.stdout)
writer.writerow(("index", "secret key", "public key", "aux_rand", "message", "signature", "verification result", "comment"))
for (i,v) in enumerate(vectors):
writer.writerow((i,)+v)
print_csv(vectors)
================================================
FILE: bip-0340.mediawiki
================================================
BIP: 340
Title: Schnorr Signatures for secp256k1
Authors: Pieter Wuille
Jonas Nick
Tim Ruffing
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0340
Status: Deployed
Type: Specification
Assigned: 2020-01-19
License: BSD-2-Clause
License-Code: BSD-2-Clause OR MIT OR CC0-1.0
Discussion: 2018-07-06: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-July/016203.html [bitcoin-dev] Schnorr signatures BIP
== Introduction ==
=== Abstract ===
This document proposes a standard for 64-byte Schnorr signatures over the elliptic curve ''secp256k1''.
=== Copyright ===
This document is licensed under the 2-clause BSD license.
=== Motivation ===
Bitcoin has traditionally used
[https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm ECDSA] signatures over the [https://www.secg.org/sec2-v2.pdf secp256k1 curve] with [https://en.wikipedia.org/wiki/SHA-2 SHA256] hashes for authenticating
transactions. These are [https://www.secg.org/sec1-v2.pdf standardized], but have a number of downsides
compared to [http://publikationen.ub.uni-frankfurt.de/opus4/files/4280/schnorr.pdf Schnorr signatures] over the same curve:
* '''Provable security''': Schnorr signatures are provably secure. In more detail, they are ''strongly unforgeable under chosen message attack (SUF-CMA)''Informally, this means that without knowledge of the secret key but given valid signatures of arbitrary messages, it is not possible to come up with further valid signatures. [https://www.di.ens.fr/~pointche/Documents/Papers/2000_joc.pdf in the random oracle model assuming the hardness of the elliptic curve discrete logarithm problem (ECDLP)] and [http://www.neven.org/papers/schnorr.pdf in the generic group model assuming variants of preimage and second preimage resistance of the used hash function]A detailed security proof in the random oracle model, which essentially restates [https://www.di.ens.fr/~pointche/Documents/Papers/2000_joc.pdf the original security proof by Pointcheval and Stern] more explicitly, can be found in [https://eprint.iacr.org/2016/191 a paper by Kiltz, Masny and Pan]. All these security proofs assume a variant of Schnorr signatures that use ''(e,s)'' instead of ''(R,s)'' (see Design above). Since we use a unique encoding of ''R'', there is an efficiently computable bijection that maps ''(R,s)'' to ''(e,s)'', which allows to convert a successful SUF-CMA attacker for the ''(e,s)'' variant to a successful SUF-CMA attacker for the ''(R,s)'' variant (and vice-versa). Furthermore, the proofs consider a variant of Schnorr signatures without key prefixing (see Design above), but it can be verified that the proofs are also correct for the variant with key prefixing. As a result, all the aforementioned security proofs apply to the variant of Schnorr signatures proposed in this document.. In contrast, the [https://nbn-resolving.de/urn:nbn:de:hbz:294-60803 best known results for the provable security of ECDSA] rely on stronger assumptions.
* '''Non-malleability''': The SUF-CMA security of Schnorr signatures implies that they are non-malleable. On the other hand, ECDSA signatures are inherently malleableIf ''(r,s)'' is a valid ECDSA signature for a given message and key, then ''(r,n-s)'' is also valid for the same message and key. If ECDSA is restricted to only permit one of the two variants (as Bitcoin does through a policy rule on the network), it can be [https://nbn-resolving.de/urn:nbn:de:hbz:294-60803 proven] non-malleable under stronger than usual assumptions.; a third party without access to the secret key can alter an existing valid signature for a given public key and message into another signature that is valid for the same key and message. This issue is discussed in [[bip-0062.mediawiki|BIP62]] and [[bip-0146.mediawiki|BIP146]].
* '''Linearity''': Schnorr signatures provide a simple and efficient method that enables multiple collaborating parties to produce a signature that is valid for the sum of their public keys. This is the building block for various higher-level constructions that improve efficiency and privacy, such as multisignatures and others (see Applications below).
For all these advantages, there are virtually no disadvantages, apart
from not being standardized. This document seeks to change that. As we
propose a new standard, a number of improvements not specific to Schnorr signatures can be
made:
* '''Signature encoding''': Instead of using [https://en.wikipedia.org/wiki/X.690#DER_encoding DER]-encoding for signatures (which are variable size, and up to 72 bytes), we can use a simple fixed 64-byte format.
* '''Public key encoding''': Instead of using [https://www.secg.org/sec1-v2.pdf ''compressed''] 33-byte encodings of elliptic curve points which are common in Bitcoin today, public keys in this proposal are encoded as 32 bytes.
* '''Batch verification''': The specific formulation of ECDSA signatures that is standardized cannot be verified more efficiently in batch compared to individually, unless additional witness data is added. Changing the signature scheme offers an opportunity to address this.
* '''Completely specified''': To be safe for usage in consensus systems, the verification algorithm must be completely specified at the byte level. This guarantees that nobody can construct a signature that is valid to some verifiers but not all. This is traditionally not a requirement for digital signature schemes, and the lack of exact specification for the DER parsing of ECDSA signatures has caused problems for Bitcoin [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-July/009697.html in the past], needing [[bip-0066.mediawiki|BIP66]] to address it. In this document we aim to meet this property by design. For batch verification, which is inherently non-deterministic as the verifier can choose their batches, this property implies that the outcome of verification may only differ from individual verifications with negligible probability, even to an attacker who intentionally tries to make batch- and non-batch verification differ.
By reusing the same curve and hash function as Bitcoin uses for ECDSA, we are able to retain existing mechanisms for choosing secret and public keys, and we avoid introducing new assumptions about the security of elliptic curves and hash functions.
== Description ==
We first build up the algebraic formulation of the signature scheme by
going through the design choices. Afterwards, we specify the exact
encodings and operations.
=== Design ===
'''Schnorr signature variant''' Elliptic Curve Schnorr signatures for message ''m'' and public key ''P'' generally involve a point ''R'', integers ''e'' and ''s'' picked by the signer, and the base point ''G'' which satisfy ''e = hash(R || m)'' and ''s⋅G = R + e⋅P''. Two formulations exist, depending on whether the signer reveals ''e'' or ''R'':
# Signatures are pairs ''(e, s)'' that satisfy ''e = hash(s⋅G - e⋅P || m)''. This variant avoids minor complexity introduced by the encoding of the point ''R'' in the signature (see paragraphs "Encoding R and public key point P" and "Implicit Y coordinates" further below in this subsection). Moreover, revealing ''e'' instead of ''R'' allows for potentially shorter signatures: Whereas an encoding of ''R'' inherently needs about 32 bytes, the hash ''e'' can be tuned to be shorter than 32 bytes, and [http://www.neven.org/papers/schnorr.pdf a short hash of only 16 bytes suffices to provide SUF-CMA security at the target security level of 128 bits]. However, a major drawback of this optimization is that finding collisions in a short hash function is easy. This complicates the implementation of secure signing protocols in scenarios in which a group of mutually distrusting signers work together to produce a single joint signature (see Applications below). In these scenarios, which are not captured by the SUF-CMA model due its assumption of a single honest signer, a promising attack strategy for malicious co-signers is to find a collision in the hash function in order to obtain a valid signature on a message that an honest co-signer did not intend to sign.
# Signatures are pairs ''(R, s)'' that satisfy ''s⋅G = R + hash(R || m)⋅P''. This supports batch verification, as there are no elliptic curve operations inside the hashes. Batch verification enables significant speedups.The speedup that results from batch verification can be demonstrated with the cryptography library [https://github.com/jonasnick/secp256k1/blob/schnorrsig-batch-verify/doc/speedup-batch.md libsecp256k1].
Since we would like to avoid the fragility that comes with short hashes, the ''e'' variant does not provide significant advantages. We choose the ''R''-option, which supports batch verification.
'''Key prefixing''' Using the verification rule above directly makes Schnorr signatures vulnerable to "related-key attacks" in which a third party can convert a signature ''(R, s)'' for public key ''P'' into a signature ''(R, s + a⋅hash(R || m))'' for public key ''P + a⋅G'' and the same message ''m'', for any given additive tweak ''a'' to the signing key. This would render signatures insecure when keys are generated using [[bip-0032.mediawiki#public-parent-key--public-child-key|BIP32's unhardened derivation]] and other methods that rely on additive tweaks to existing keys such as Taproot.
To protect against these attacks, we choose ''key prefixed''A limitation of committing to the public key (rather than to a short hash of it, or not at all) is that it removes the ability for public key recovery or verifying signatures against a short public key hash. These constructions are generally incompatible with batch verification. Schnorr signatures which means that the public key is prefixed to the message in the challenge hash input. This changes the equation to ''s⋅G = R + hash(R || P || m)⋅P''. [https://eprint.iacr.org/2015/1135.pdf It can be shown] that key prefixing protects against related-key attacks with additive tweaks. In general, key prefixing increases robustness in multi-user settings, e.g., it seems to be a requirement for proving multiparty signing protocols (such as MuSig, MuSig2, and FROST) secure (see Applications below).
We note that key prefixing is not strictly necessary for transaction signatures as used in Bitcoin currently, because signed transactions indirectly commit to the public keys already, i.e., ''m'' contains a commitment to ''pk''. However, this indirect commitment should not be relied upon because it may change with proposals such as SIGHASH_NOINPUT ([[bip-0118.mediawiki|BIP118]]), and would render the signature scheme unsuitable for other purposes than signing transactions, e.g., [https://bitcoin.org/en/developer-reference#signmessage signing ordinary messages].
'''Encoding R and public key point P''' There exist several possibilities for encoding elliptic curve points:
# Encoding the full X and Y coordinates of ''P'' and ''R'', resulting in a 64-byte public key and a 96-byte signature.
# Encoding the full X coordinate and one bit of the Y coordinate to determine one of the two possible Y coordinates. This would result in 33-byte public keys and 65-byte signatures.
# Encoding only the X coordinate, resulting in 32-byte public keys and 64-byte signatures.
Using the first option would be slightly more efficient for verification (around 10%), but we prioritize compactness, and therefore choose option 3.
'''Implicit Y coordinates''' In order to support efficient verification and batch verification, the Y coordinate of ''P'' and of ''R'' cannot be ambiguous (every valid X coordinate has two possible Y coordinates). We have a choice between several options for symmetry breaking:
# Implicitly choosing the Y coordinate that is in the lower half.
# Implicitly choosing the Y coordinate that is evenSince ''p'' is odd, negation modulo ''p'' will map even numbers to odd numbers and the other way around. This means that for a valid X coordinate, one of the corresponding Y coordinates will be even, and the other will be odd..
# Implicitly choosing the Y coordinate that is a quadratic residue (i.e. has a square root modulo ''p'').
The second option offers the greatest compatibility with existing key generation systems, where the standard 33-byte compressed public key format consists of a byte indicating the oddness of the Y coordinate, plus the full X coordinate. To avoid gratuitous incompatibilities, we pick that option for ''P'', and thus our X-only public keys become equivalent to a compressed public key that is the X-only key prefixed by the byte 0x02. For consistency, the same is done for ''R''An earlier version of this draft used the third option instead, based on a belief that this would in general trade signing efficiency for verification efficiency. When using Jacobian coordinates, a common optimization in ECC implementations, it is possible to determine if a Y coordinate is a quadratic residue by computing the Legendre symbol, without converting to affine coordinates first (which needs a modular inversion). As modular inverses and Legendre symbols have similar [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-August/018081.html performance] in practice, this trade-off is not worth it..
Despite halving the size of the set of valid public keys, implicit Y coordinates are not a reduction in security. Informally, if a fast algorithm existed to compute the discrete logarithm of an X-only public key, then it could also be used to compute the discrete logarithm of a full public key: apply it to the X coordinate, and then optionally negate the result. This shows that breaking an X-only public key can be at most a small constant term faster than breaking a full one.This can be formalized by a simple reduction that reduces an attack on Schnorr signatures with implicit Y coordinates to an attack to Schnorr signatures with explicit Y coordinates. The reduction works by reencoding public keys and negating the result of the hash function, which is modeled as random oracle, whenever the challenge public key has an explicit Y coordinate that is odd. A proof sketch can be found [https://medium.com/blockstream/reducing-bitcoin-transaction-sizes-with-x-only-pubkeys-f86476af05d7 here]..
'''Tagged Hashes''' Cryptographic hash functions are used for multiple purposes in the specification below and in Bitcoin in general. To make sure hashes used in one context can't be reinterpreted in another one, hash functions can be tweaked with a context-dependent tag name, in such a way that collisions across contexts can be assumed to be infeasible. Such collisions obviously can not be ruled out completely, but only for schemes using tagging with a unique name. As for other schemes collisions are at least less likely with tagging than without.
For example, without tagged hashing a BIP340 signature could also be valid for a signature scheme where the only difference is that the arguments to the hash function are reordered. Worse, if the BIP340 nonce derivation function was copied or independently created, then the nonce could be accidentally reused in the other scheme leaking the secret key.
This proposal suggests to include the tag by prefixing the hashed data with ''SHA256(tag) || SHA256(tag)''. Because this is a 64-byte long context-specific constant and the ''SHA256'' block size is also 64 bytes, optimized implementations are possible (identical to SHA256 itself, but with a modified initial state). Using SHA256 of the tag name itself is reasonably simple and efficient for implementations that don't choose to use the optimization. In general, tags can be arbitrary byte arrays, but are suggested to be textual descriptions in UTF-8 encoding.
'''Final scheme''' As a result, our final scheme ends up using public key ''pk'' which is the X coordinate of a point ''P'' on the curve whose Y coordinate is even and signatures ''(r,s)'' where ''r'' is the X coordinate of a point ''R'' whose Y coordinate is even. The signature satisfies ''s⋅G = R + tagged_hash(r || pk || m)⋅P''.
=== Specification ===
The following conventions are used, with constants as defined for [https://www.secg.org/sec2-v2.pdf secp256k1]. We note that adapting this specification to other elliptic curves is not straightforward and can result in an insecure schemeAmong other pitfalls, using the specification with a curve whose order is not close to the size of the range of the nonce derivation function is insecure..
* Lowercase variables represent integers or byte arrays.
** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''.
** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''.
* Uppercase variables refer to points on the curve with equation ''y2 = x3 + 7'' over the integers modulo ''p''.
** ''is_infinite(P)'' returns whether or not ''P'' is the point at infinity.
** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity).
** The constant ''G'' refers to the base point, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''.
** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation].
** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication (⋅) of an integer and a point] refers to the repeated application of the group operation.
* Functions and operations:
** ''||'' refers to byte array concatenation.
** The function ''x[i:j]'', where ''x'' is a byte array and ''i, j ≥ 0'', returns a ''(j - i)''-byte array with a copy of the ''i''-th byte (inclusive) to the ''j''-th byte (exclusive) of ''x''.
** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first.
** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))''.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 = 0''.
** The function ''lift_x(x)'', where ''x'' is a 256-bit unsigned integer, returns the point ''P'' for which ''x(P) = x''
Given a candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x3 + 7 mod p'' and they can be computed as ''y = ±c(p+1)/4 mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''. and ''has_even_y(P)'', or fails if ''x'' is greater than ''p-1'' or no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Fail if ''x ≥ p''.
*** Let ''c = x3 + 7 mod p''.
*** Let ''y = c(p+1)/4 mod p''.
*** Fail if ''c ≠ y2 mod p''.
*** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y'' if ''y mod 2 = 0'' or ''y(P) = p-y'' otherwise.
** The function ''hashname(x)'' where ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)'', where ''tag'' is the UTF-8 encoding of ''name''.
==== Public Key Generation ====
Input:
* The secret key ''sk'': a 32-byte array, freshly generated uniformly at random
The algorithm ''PubKey(sk)'' is defined as:
* Let ''d' = int(sk)''.
* Fail if ''d' = 0'' or ''d' ≥ n''.
* Return ''bytes(d'⋅G)''.
Note that we use a very different public key format (32 bytes) than the ones used by existing systems (which typically use elliptic curve points as public keys, or 33-byte or 65-byte encodings of them). A side effect is that ''PubKey(sk) = PubKey(bytes(n - int(sk))'', so every public key has two corresponding secret keys.
==== Public Key Conversion ====
As an alternative to generating keys randomly, it is also possible and safe to repurpose existing key generation algorithms for ECDSA in a compatible way. The secret keys constructed by such an algorithm can be used as ''sk'' directly. The public keys constructed by such an algorithm (assuming they use the 33-byte compressed encoding) need to be converted by dropping the first byte. Specifically, [[bip-0032.mediawiki|BIP32]] and schemes built on top of it remain usable.
==== Default Signing ====
Input:
* The secret key ''sk'': a 32-byte array
* The message ''m'': a byte array
* Auxiliary random data ''a'': a 32-byte array
The algorithm ''Sign(sk, m)'' is defined as:
* Let ''d' = int(sk)''
* Fail if ''d' = 0'' or ''d' ≥ n''
* Let ''P = d'⋅G''
* Let ''d = d' '' if ''has_even_y(P)'', otherwise let ''d = n - d' ''.
* Let ''t'' be the byte-wise xor of ''bytes(d)'' and ''hashBIP0340/aux(a)''The auxiliary random data is hashed (with a unique tag) as a precaution against situations where the randomness may be correlated with the private key itself. It is xored with the private key (rather than combined with it in a hash) to reduce the number of operations exposed to the actual secret key..
* Let ''rand = hashBIP0340/nonce(t || bytes(P) || m)''Including the [https://moderncrypto.org/mail-archive/curves/2020/001012.html public key as input to the nonce hash] helps ensure the robustness of the signing algorithm by preventing leakage of the secret key if the calculation of the public key ''P'' is performed incorrectly or maliciously, for example if it is left to the caller for performance reasons..
* Let ''k' = int(rand) mod n''Note that in general, taking a uniformly random 256-bit integer modulo the curve order will produce an unacceptably biased result. However, for the secp256k1 curve, the order is sufficiently close to ''2256'' that this bias is not observable (''1 - n / 2256'' is around ''1.27 * 2-128'')..
* Fail if ''k' = 0''.
* Let ''R = k'⋅G''.
* Let ''k = k' '' if ''has_even_y(R)'', otherwise let ''k = n - k' ''.
* Let ''e = int(hashBIP0340/challenge(bytes(R) || bytes(P) || m)) mod n''.
* Let ''sig = bytes(R) || bytes((k + ed) mod n)''.
* If ''Verify(bytes(P), m, sig)'' (see below) returns failure, abortVerifying the signature before leaving the signer prevents random or attacker provoked computation errors. This prevents publishing invalid signatures which may leak information about the secret key. It is recommended, but can be omitted if the computation cost is prohibitive..
* Return the signature ''sig''.
The auxiliary random data should be set to fresh randomness generated at signing time, resulting in what is called a ''synthetic nonce''. Using 32 bytes of randomness is optimal. If obtaining randomness is expensive, 16 random bytes can be padded with 16 null bytes to obtain a 32-byte array. If randomness is not available at all at signing time, a simple counter wide enough to not repeat in practice (e.g., 64 bits or wider) and padded with null bytes to a 32 byte-array can be used, or even the constant array with 32 null bytes. Using any non-repeating value increases protection against [https://moderncrypto.org/mail-archive/curves/2017/000925.html fault injection attacks]. Using unpredictable randomness additionally increases protection against other side-channel attacks, and is '''recommended whenever available'''. Note that while this means the resulting nonce is not deterministic, the randomness is only supplemental to security. The normal security properties (excluding side-channel attacks) do not depend on the quality of the signing-time RNG.
==== Alternative Signing ====
It should be noted that various alternative signing algorithms can be used to produce equally valid signatures. The 32-byte ''rand'' value may be generated in other ways, producing a different but still valid signature (in other words, this is not a ''unique'' signature scheme). '''No matter which method is used to generate the ''rand'' value, the value must be a fresh uniformly random 32-byte string which is not even partially predictable for the attacker.''' For nonces without randomness, this implies that the same inputs must not be presented in another context. This can be most reliably accomplished by not reusing the same private key across different signing schemes. For example, if the ''rand'' value was computed as per RFC6979 and the same secret key is used in deterministic ECDSA with RFC6979, the signatures can leak the secret key through nonce reuse.
'''Nonce exfiltration protection''' It is possible to strengthen the nonce generation algorithm using a second device. In this case, the second device contributes randomness which the actual signer provably incorporates into its nonce. This prevents certain attacks where the signer's device is compromised and intentionally tries to leak the secret key through its nonce selection.
'''Multisignatures''' This signature scheme is compatible with various types of multisignature and threshold schemes such as [https://eprint.iacr.org/2020/1261.pdf MuSig2], where a single public key requires holders of multiple secret keys to participate in signing (see Applications below).
'''It is important to note that multisignature signing schemes in general are insecure with the ''rand'' generation from the default signing algorithm above (or any other deterministic method).'''
'''Precomputed public key data''' For many uses, the compressed 33-byte encoding of the public key corresponding to the secret key may already be known, making it easy to evaluate ''has_even_y(P)'' and ''bytes(P)''. As such, having signers supply this directly may be more efficient than recalculating the public key from the secret key. However, if this optimization is used and additionally the signature verification at the end of the signing algorithm is dropped for increased efficiency, signers must ensure the public key is correctly calculated and not taken from untrusted sources.
==== Verification ====
Input:
* The public key ''pk'': a 32-byte array
* The message ''m'': a byte array
* A signature ''sig'': a 64-byte array
The algorithm ''Verify(pk, m, sig)'' is defined as:
* Let ''P = lift_x(int(pk))''; fail if that fails.
* Let ''r = int(sig[0:32])''; fail if ''r ≥ p''.
* Let ''s = int(sig[32:64])''; fail if ''s ≥ n''.
* Let ''e = int(hashBIP0340/challenge(bytes(r) || bytes(P) || m)) mod n''.
* Let ''R = s⋅G - e⋅P''.
* Fail if ''is_infinite(R)''.
* Fail if ''not has_even_y(R)''.
* Fail if ''x(R) ≠ r''.
* Return success iff no failure occurred before reaching this point.
For every valid secret key ''sk'' and message ''m'', ''Verify(PubKey(sk),m,Sign(sk,m))'' will succeed.
Note that the correctness of verification relies on the fact that ''lift_x'' always returns a point with an even Y coordinate. A hypothetical verification algorithm that treats points as public keys, and takes the point ''P'' directly as input would fail any time a point with odd Y is used. While it is possible to correct for this by negating points with odd Y coordinate before further processing, this would result in a scheme where every (message, signature) pair is valid for two public keys (a type of malleability that exists for ECDSA as well, but we don't wish to retain). We avoid these problems by treating just the X coordinate as public key.
==== Batch Verification ====
Input:
* The number ''u'' of signatures
* The public keys ''pk1..u'': ''u'' 32-byte arrays
* The messages ''m1..u'': ''u'' byte arrays
* The signatures ''sig1..u'': ''u'' 64-byte arrays
The algorithm ''BatchVerify(pk1..u, m1..u, sig1..u)'' is defined as:
* Generate ''u-1'' random integers ''a2...u'' in the range ''1...n-1''. They are generated deterministically using a [https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator CSPRNG] seeded by a cryptographic hash of all inputs of the algorithm, i.e. ''seed = seed_hash(pk1..pku || m1..mu || sig1..sigu )''. A safe choice is to instantiate ''seed_hash'' with SHA256 and use [https://tools.ietf.org/html/rfc8439 ChaCha20] with key ''seed'' as a CSPRNG to generate 256-bit integers, skipping integers not in the range ''1...n-1''.
* For ''i = 1 .. u'':
** Let ''Pi = lift_x(int(pki))''; fail if it fails.
** Let ''ri = int(sigi[0:32])''; fail if ''ri ≥ p''.
** Let ''si = int(sigi[32:64])''; fail if ''si ≥ n''.
** Let ''ei = int(hashBIP0340/challenge(bytes(ri) || bytes(Pi) || mi)) mod n''.
** Let ''Ri = lift_x(ri)''; fail if ''lift_x(ri)'' fails.
* Fail if ''(s1 + a2s2 + ... + ausu)⋅G ≠ R1 + a2⋅R2 + ... + au⋅Ru + e1⋅P1 + (a2e2)⋅P2 + ... + (aueu)⋅Pu''.
* Return success iff no failure occurred before reaching this point.
If all individual signatures are valid (i.e., ''Verify'' would return success for them), ''BatchVerify'' will always return success. If at least one signature is invalid, ''BatchVerify'' will return success with at most a negligible probability.
=== Usage Considerations ===
==== Messages of Arbitrary Size ====
The signature scheme specified in this BIP accepts byte strings of arbitrary size as input messages.In theory, the message size is restricted due to the fact that SHA256 accepts byte strings only up to size of 2^61-1 bytes.
It is understood that implementations may reject messages which are too large in their environment or application context,
e.g., messages which exceed predefined buffers or would otherwise cause resource exhaustion.
Earlier revisions of this BIP required messages to be exactly 32 bytes.
This restriction puts a burden on callers
who typically need to perform pre-hashing of the actual input message by feeding it through SHA256 (or another collision-resistant cryptographic hash function)
to create a 32-byte digest which can be passed to signing or verification
(as for example done in [[bip-0341.mediawiki|BIP341]].)
Since pre-hashing may not always be desirable,
e.g., when actual messages are shorter than 32 bytes,Another reason to omit pre-hashing is to protect against certain types of cryptanalytic advances against the hash function used for pre-hashing: If pre-hashing is used, an attacker that can find collisions in the pre-hashing function can necessarily forge signatures under chosen-message attacks. If pre-hashing is not used, an attacker that can find collisions in SHA256 (as used inside the signature scheme) may not be able to forge signatures. However, this seeming advantage is mostly irrelevant in the context of Bitcoin, which already relies on collision resistance of SHA256 in other places, e.g., for transaction hashes.
the restriction to 32-byte messages has been lifted.
We note that pre-hashing is recommended for performance reasons in applications that deal with large messages.
If large messages are not pre-hashed,
the algorithms of the signature scheme will perform more hashing internally.
In particular, the signing algorithm needs two sequential hashing passes over the message,
which means that the full message must necessarily be kept in memory during signing,
and large messages entail a runtime penalty.Typically, messages of 56 bytes or longer enjoy a performance benefit from pre-hashing, assuming the speed of SHA256 inside the signing algorithm matches that of the pre-hashing done by the calling application.
==== Domain Separation ====
It is good cryptographic practice to use a key pair only for a single purpose.
Nevertheless, there may be situations in which it may be desirable to use the same key pair in multiple contexts,
i.e., to sign different types of messages within the same application
or even messages in entirely different applications
(e.g., a secret key may be used to sign Bitcoin transactions as well plain text messages).
As a consequence, applications should ensure that a signed application message intended for one context is never deemed valid in a different context
(e.g., a signed plain text message should never be misinterpreted as a signed Bitcoin transaction, because this could cause unintended loss of funds).
This is called "domain separation" and it is typically realized by partitioning the message space.
Even if key pairs are intended to be used only within a single context,
domain separation is a good idea because it makes it easy to add more contexts later.
As a best practice, we recommend applications to use exactly one of the following methods to pre-process application messages before passing it to the signature scheme:
* Either, pre-hash the application message using ''hashname'', where ''name'' identifies the context uniquely (e.g., "foo-app/signed-bar"),
* or prefix the actual message with a 33-byte string that identifies the context uniquely (e.g., the UTF-8 encoding of "foo-app/signed-bar", padded with null bytes to 33 bytes).
As the two pre-processing methods yield different message sizes (32 bytes vs. at least 33 bytes), there is no risk of collision between them.
== Applications ==
There are several interesting applications beyond simple signatures.
While recent academic papers claim that they are also possible with ECDSA, consensus support for Schnorr signature verification would significantly simplify the constructions.
=== Multisignatures and Threshold Signatures ===
By means of an interactive scheme such as [https://eprint.iacr.org/2020/1261.pdf MuSig2] ([[bip-0327.mediawiki|BIP327]]), participants can aggregate their public keys into a single public key which they can jointly sign for. This allows ''n''-of-''n'' multisignatures which, from a verifier's perspective, are no different from ordinary signatures, giving improved privacy and efficiency versus ''CHECKMULTISIG'' or other means.
Moreover, Schnorr signatures are compatible with [https://en.wikipedia.org/wiki/Distributed_key_generation distributed key generation], which enables interactive threshold signatures schemes, e.g., the schemes by [http://cacr.uwaterloo.ca/techreports/2001/corr2001-13.ps Stinson and Strobl (2001)], by [https://link.springer.com/content/pdf/10.1007/s00145-006-0347-3.pdf Gennaro, Jarecki, Krawczyk, and Rabin (2007)], or the [https://eprint.iacr.org/2020/852.pdf FROST] scheme including its variants such as [https://eprint.iacr.org/2023/899.pdf FROST3]. These protocols make it possible to realize ''k''-of-''n'' threshold signatures, which ensure that any subset of size ''k'' of the set of ''n'' signers can sign but no subset of size less than ''k'' can produce a valid Schnorr signature.
=== Adaptor Signatures ===
[https://download.wpsoftware.net/bitcoin/wizardry/mw-slides/2018-05-18-l2/slides.pdf Adaptor signatures] can be produced by a signer by offsetting his public nonce ''R'' with a known point ''T = t⋅G'', but not offsetting the signature's ''s'' value.
A correct signature (or partial signature, as individual signers' contributions to a multisignature are called) on the same message with same nonce will then be equal to the adaptor signature offset by ''t'', meaning that learning ''t'' is equivalent to learning a correct signature.
This can be used to enable atomic swaps or even [https://eprint.iacr.org/2018/472 general payment channels] in which the atomicity of disjoint transactions is ensured using the signatures themselves, rather than Bitcoin script support. The resulting transactions will appear to verifiers to be no different from ordinary single-signer transactions, except perhaps for the inclusion of locktime refund logic.
Adaptor signatures, beyond the efficiency and privacy benefits of encoding script semantics into constant-sized signatures, have additional benefits over traditional hash-based payment channels. Specifically, the secret values ''t'' may be reblinded between hops, allowing long chains of transactions to be made atomic while even the participants cannot identify which transactions are part of the chain. Also, because the secret values are chosen at signing time, rather than key generation time, existing outputs may be repurposed for different applications without recourse to the blockchain, even multiple times.
=== Blind Signatures ===
A blind signature protocol is an interactive protocol that enables a signer to sign a message at the behest of another party without learning any information about the signed message or the signature. Schnorr signatures admit a very [http://publikationen.ub.uni-frankfurt.de/files/4292/schnorr.blind_sigs_attack.2001.pdf simple blind signature scheme] which is however insecure because it's vulnerable to [https://www.iacr.org/archive/crypto2002/24420288/24420288.pdf Wagner's attack]. Known mitigations are to let the signer abort a signing session with a certain probability, which can be [https://eprint.iacr.org/2019/877 proven secure under non-standard cryptographic assumptions], or [https://eprint.iacr.org/2022/1676.pdf to use zero-knowledge proofs].
Blind Schnorr signatures could for example be used in [https://github.com/ElementsProject/scriptless-scripts/blob/master/md/partially-blind-swap.md Partially Blind Atomic Swaps], a construction to enable transferring of coins, mediated by an untrusted escrow agent, without connecting the transactors in the public blockchain transaction graph.
== Test Vectors and Reference Code ==
For development and testing purposes, we provide a [[bip-0340/test-vectors.csv|collection of test vectors in CSV format]],
a naive, highly inefficient, and non-constant time [[bip-0340/reference.py|pure Python 3.7 reference implementation of the signing and verification algorithm]]
as well as the [[bip-0340/test-vectors.py|script used to generate the test vectors]]
under the BSD-2-Clause License, or the MIT License, or CC0 1.0, at your choice.
The reference implementation is for demonstration purposes only and not to be used in production environments.
== Changelog ==
To help implementers understand updates to this BIP, we keep a list of substantial changes.
* 2022-08: Fix function signature of lift_x in reference code
* 2023-04: Allow messages of arbitrary size
* 2024-05: Update "Applications" section with more recent references
* 2025-04: Change license of test vectors and code
== Footnotes ==
== Acknowledgements ==
This document is the result of many discussions around Schnorr based signatures over the years, and had input from Johnson Lau, Greg Maxwell, Andrew Poelstra, Rusty Russell, and Anthony Towns. The authors further wish to thank all those who provided valuable feedback and reviews, including the participants of the [https://github.com/ajtowns/taproot-review structured reviews].
================================================
FILE: bip-0341/wallet-test-vectors.json
================================================
{
"version": 1,
"scriptPubKey": [
{
"given": {
"internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d",
"scriptTree": null
},
"intermediary": {
"merkleRoot": null,
"tweak": "b86e7be8f39bab32a6f2c0443abbc210f0edac0e2c53d501b36b64437d9c6c70",
"tweakedPubkey": "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343"
},
"expected": {
"scriptPubKey": "512053a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
"bip350Address": "bc1p2wsldez5mud2yam29q22wgfh9439spgduvct83k3pm50fcxa5dps59h4z5"
}
},
{
"given": {
"internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
"scriptTree": {
"id": 0,
"script": "20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac",
"leafVersion": 192
}
},
"intermediary": {
"leafHashes": [
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
],
"merkleRoot": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
"tweak": "cbd8679ba636c1110ea247542cfbd964131a6be84f873f7f3b62a777528ed001",
"tweakedPubkey": "147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3"
},
"expected": {
"scriptPubKey": "5120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
"bip350Address": "bc1pz37fc4cn9ah8anwm4xqqhvxygjf9rjf2resrw8h8w4tmvcs0863sa2e586",
"scriptPathControlBlocks": [
"c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27"
]
}
},
{
"given": {
"internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
"scriptTree": {
"id": 0,
"script": "20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac",
"leafVersion": 192
}
},
"intermediary": {
"leafHashes": [
"c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
],
"merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
"tweak": "6af9e28dbf9d6aaf027696e2598a5b3d056f5fd2355a7fd5a37a0e5008132d30",
"tweakedPubkey": "e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e"
},
"expected": {
"scriptPubKey": "5120e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
"bip350Address": "bc1punvppl2stp38f7kwv2u2spltjuvuaayuqsthe34hd2dyy5w4g58qqfuag5",
"scriptPathControlBlocks": [
"c093478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820"
]
}
},
{
"given": {
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
"scriptTree": [
{
"id": 0,
"script": "20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac",
"leafVersion": 192
},
{
"id": 1,
"script": "06424950333431",
"leafVersion": 250
}
]
},
"intermediary": {
"leafHashes": [
"8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7",
"f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
],
"merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
"tweak": "9e0517edc8259bb3359255400b23ca9507f2a91cd1e4250ba068b4eafceba4a9",
"tweakedPubkey": "712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5"
},
"expected": {
"scriptPubKey": "5120712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5",
"bip350Address": "bc1pwyjywgrd0ffr3tx8laflh6228dj98xkjj8rum0zfpd6h0e930h6saqxrrm",
"scriptPathControlBlocks": [
"c0ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
"faee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf37865928ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
]
}
},
{
"given": {
"internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
"scriptTree": [
{
"id": 0,
"script": "2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac",
"leafVersion": 192
},
{
"id": 1,
"script": "07546170726f6f74",
"leafVersion": 192
}
]
},
"intermediary": {
"leafHashes": [
"64512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89",
"2cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
],
"merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
"tweak": "639f0281b7ac49e742cd25b7f188657626da1ad169209078e2761cefd91fd65e",
"tweakedPubkey": "77e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220"
},
"expected": {
"scriptPubKey": "512077e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220",
"bip350Address": "bc1pwl3s54fzmk0cjnpl3w9af39je7pv5ldg504x5guk2hpecpg2kgsqaqstjq",
"scriptPathControlBlocks": [
"c1f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd82cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
"c1f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd864512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89"
]
}
},
{
"given": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
"scriptTree": [
{
"id": 0,
"script": "2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac",
"leafVersion": 192
},
[
{
"id": 1,
"script": "202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac",
"leafVersion": 192
},
{
"id": 2,
"script": "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
"leafVersion": 192
}
]
]
},
"intermediary": {
"leafHashes": [
"2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c",
"9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf6"
],
"merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
"tweak": "b57bfa183d28eeb6ad688ddaabb265b4a41fbf68e5fed2c72c74de70d5a786f4",
"tweakedPubkey": "91b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605"
},
"expected": {
"scriptPubKey": "512091b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
"bip350Address": "bc1pjxmy65eywgafs5tsunw95ruycpqcqnev6ynxp7jaasylcgtcxczs6n332e",
"scriptPathControlBlocks": [
"c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
"c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"c0e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6fba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
]
}
},
{
"given": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
"scriptTree": [
{
"id": 0,
"script": "2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac",
"leafVersion": 192
},
[
{
"id": 1,
"script": "20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac",
"leafVersion": 192
},
{
"id": 2,
"script": "20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac",
"leafVersion": 192
}
]
]
},
"intermediary": {
"leafHashes": [
"f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711",
"d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7"
],
"merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
"tweak": "6579138e7976dc13b6a92f7bfd5a2fc7684f5ea42419d43368301470f3b74ed9",
"tweakedPubkey": "75169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831"
},
"expected": {
"scriptPubKey": "512075169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
"bip350Address": "bc1pw5tf7sqp4f50zka7629jrr036znzew70zxyvvej3zrpf8jg8hqcssyuewe",
"scriptPathControlBlocks": [
"c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d3cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
"c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312dd7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"c155adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
]
}
}
],
"keyPathSpending": [
{
"given": {
"rawUnsignedTx": "02000000097de20cbff686da83a54981d2b9bab3586f4ca7e48f57f5b55963115f3b334e9c010000000000000000d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd990000000000fffffffff8e1f583384333689228c5d28eac13366be082dc57441760d957275419a418420000000000fffffffff0689180aa63b30cb162a73c6d2a38b7eeda2a83ece74310fda0843ad604853b0100000000feffffffaa5202bdf6d8ccd2ee0f0202afbbb7461d9264a25e5bfd3c5a52ee1239e0ba6c0000000000feffffff956149bdc66faa968eb2be2d2faa29718acbfe3941215893a2a3446d32acd050000000000000000000e664b9773b88c09c32cb70a2a3e4da0ced63b7ba3b22f848531bbb1d5d5f4c94010000000000000000e9aa6b8e6c9de67619e6a3924ae25696bb7b694bb677a632a74ef7eadfd4eabf0000000000ffffffffa778eb6a263dc090464cd125c466b5a99667720b1c110468831d058aa1b82af10100000000ffffffff0200ca9a3b000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac807840cb0000000020ac9a87f5594be208f8532db38cff670c450ed2fea8fcdefcc9a663f78bab962b0065cd1d",
"utxosSpent": [
{
"scriptPubKey": "512053a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
"amountSats": 420000000
},
{
"scriptPubKey": "5120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
"amountSats": 462000000
},
{
"scriptPubKey": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac",
"amountSats": 294000000
},
{
"scriptPubKey": "5120e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
"amountSats": 504000000
},
{
"scriptPubKey": "512091b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
"amountSats": 630000000
},
{
"scriptPubKey": "00147dd65592d0ab2fe0d0257d571abf032cd9db93dc",
"amountSats": 378000000
},
{
"scriptPubKey": "512075169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
"amountSats": 672000000
},
{
"scriptPubKey": "5120712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5",
"amountSats": 546000000
},
{
"scriptPubKey": "512077e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220",
"amountSats": 588000000
}
]
},
"intermediary": {
"hashAmounts": "58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde6",
"hashOutputs": "a2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc5",
"hashPrevouts": "e3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f",
"hashScriptPubkeys": "23ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e21",
"hashSequences": "18959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957e"
},
"inputSpending": [
{
"given": {
"txinIndex": 0,
"internalPrivkey": "6b973d88838f27366ed61c9ad6367663045cb456e28335c109e30717ae0c6baa",
"merkleRoot": null,
"hashType": 3
},
"intermediary": {
"internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d",
"tweak": "b86e7be8f39bab32a6f2c0443abbc210f0edac0e2c53d501b36b64437d9c6c70",
"tweakedPrivkey": "2405b971772ad26915c8dcdf10f238753a9b837e5f8e6a86fd7c0cce5b7296d9",
"sigMsg": "0003020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957e0000000000d0418f0e9a36245b9a50ec87f8bf5be5bcae434337b87139c3a5b1f56e33cba0",
"precomputedUsed": [
"hashAmounts",
"hashPrevouts",
"hashScriptPubkeys",
"hashSequences"
],
"sigHash": "2514a6272f85cfa0f45eb907fcb0d121b808ed37c6ea160a5a9046ed5526d555"
},
"expected": {
"witness": [
"ed7c1647cb97379e76892be0cacff57ec4a7102aa24296ca39af7541246d8ff14d38958d4cc1e2e478e4d4a764bbfd835b16d4e314b72937b29833060b87276c03"
]
}
},
{
"given": {
"txinIndex": 1,
"internalPrivkey": "1e4da49f6aaf4e5cd175fe08a32bb5cb4863d963921255f33d3bc31e1343907f",
"merkleRoot": "5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21",
"hashType": 131
},
"intermediary": {
"internalPubkey": "187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27",
"tweak": "cbd8679ba636c1110ea247542cfbd964131a6be84f873f7f3b62a777528ed001",
"tweakedPrivkey": "ea260c3b10e60f6de018455cd0278f2f5b7e454be1999572789e6a9565d26080",
"sigMsg": "0083020000000065cd1d00d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd9900000000808f891b00000000225120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3ffffffffffcef8fb4ca7efc5433f591ecfc57391811ce1e186a3793024def5c884cba51d",
"precomputedUsed": [],
"sigHash": "325a644af47e8a5a2591cda0ab0723978537318f10e6a63d4eed783b96a71a4d"
},
"expected": {
"witness": [
"052aedffc554b41f52b521071793a6b88d6dbca9dba94cf34c83696de0c1ec35ca9c5ed4ab28059bd606a4f3a657eec0bb96661d42921b5f50a95ad33675b54f83"
]
}
},
{
"given": {
"txinIndex": 3,
"internalPrivkey": "d3c7af07da2d54f7a7735d3d0fc4f0a73164db638b2f2f7c43f711f6d4aa7e64",
"merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
"hashType": 1
},
"intermediary": {
"internalPubkey": "93478e9488f956df2396be2ce6c5cced75f900dfa18e7dabd2428aae78451820",
"tweak": "6af9e28dbf9d6aaf027696e2598a5b3d056f5fd2355a7fd5a37a0e5008132d30",
"tweakedPrivkey": "97323385e57015b75b0339a549c56a948eb961555973f0951f555ae6039ef00d",
"sigMsg": "0001020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957ea2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc50003000000",
"precomputedUsed": [
"hashAmounts",
"hashOutputs",
"hashPrevouts",
"hashScriptPubkeys",
"hashSequences"
],
"sigHash": "bf013ea93474aa67815b1b6cc441d23b64fa310911d991e713cd34c7f5d46669"
},
"expected": {
"witness": [
"ff45f742a876139946a149ab4d9185574b98dc919d2eb6754f8abaa59d18b025637a3aa043b91817739554f4ed2026cf8022dbd83e351ce1fabc272841d2510a01"
]
}
},
{
"given": {
"txinIndex": 4,
"internalPrivkey": "f36bb07a11e469ce941d16b63b11b9b9120a84d9d87cff2c84a8d4affb438f4e",
"merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
"hashType": 0
},
"intermediary": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
"tweak": "b57bfa183d28eeb6ad688ddaabb265b4a41fbf68e5fed2c72c74de70d5a786f4",
"tweakedPrivkey": "a8e7aa924f0d58854185a490e6c41f6efb7b675c0f3331b7f14b549400b4d501",
"sigMsg": "0000020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957ea2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc50004000000",
"precomputedUsed": [
"hashAmounts",
"hashOutputs",
"hashPrevouts",
"hashScriptPubkeys",
"hashSequences"
],
"sigHash": "4f900a0bae3f1446fd48490c2958b5a023228f01661cda3496a11da502a7f7ef"
},
"expected": {
"witness": [
"b4010dd48a617db09926f729e79c33ae0b4e94b79f04a1ae93ede6315eb3669de185a17d2b0ac9ee09fd4c64b678a0b61a0a86fa888a273c8511be83bfd6810f"
]
}
},
{
"given": {
"txinIndex": 6,
"internalPrivkey": "415cfe9c15d9cea27d8104d5517c06e9de48e2f986b695e4f5ffebf230e725d8",
"merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
"hashType": 2
},
"intermediary": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
"tweak": "6579138e7976dc13b6a92f7bfd5a2fc7684f5ea42419d43368301470f3b74ed9",
"tweakedPrivkey": "241c14f2639d0d7139282aa6abde28dd8a067baa9d633e4e7230287ec2d02901",
"sigMsg": "0002020000000065cd1de3b33bb4ef3a52ad1fffb555c0d82828eb22737036eaeb02a235d82b909c4c3f58a6964a4f5f8f0b642ded0a8a553be7622a719da71d1f5befcefcdee8e0fde623ad0f61ad2bca5ba6a7693f50fce988e17c3780bf2b1e720cfbb38fbdd52e2118959c7221ab5ce9e26c3cd67b22c24f8baa54bac281d8e6b05e400e6c3a957e0006000000",
"precomputedUsed": [
"hashAmounts",
"hashPrevouts",
"hashScriptPubkeys",
"hashSequences"
],
"sigHash": "15f25c298eb5cdc7eb1d638dd2d45c97c4c59dcaec6679cfc16ad84f30876b85"
},
"expected": {
"witness": [
"a3785919a2ce3c4ce26f298c3d51619bc474ae24014bcdd31328cd8cfbab2eff3395fa0a16fe5f486d12f22a9cedded5ae74feb4bbe5351346508c5405bcfee002"
]
}
},
{
"given": {
"txinIndex": 7,
"internalPrivkey": "c7b0e81f0a9a0b0499e112279d718cca98e79a12e2f137c72ae5b213aad0d103",
"merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
"hashType": 130
},
"intermediary": {
"internalPubkey": "ee4fe085983462a184015d1f782d6a5f8b9c2b60130aff050ce221ecf3786592",
"tweak": "9e0517edc8259bb3359255400b23ca9507f2a91cd1e4250ba068b4eafceba4a9",
"tweakedPrivkey": "65b6000cd2bfa6b7cf736767a8955760e62b6649058cbc970b7c0871d786346b",
"sigMsg": "0082020000000065cd1d00e9aa6b8e6c9de67619e6a3924ae25696bb7b694bb677a632a74ef7eadfd4eabf00000000804c8b2000000000225120712447206d7a5238acc7ff53fbe94a3b64539ad291c7cdbc490b7577e4b17df5ffffffff",
"precomputedUsed": [],
"sigHash": "cd292de50313804dabe4685e83f923d2969577191a3e1d2882220dca88cbeb10"
},
"expected": {
"witness": [
"ea0c6ba90763c2d3a296ad82ba45881abb4f426b3f87af162dd24d5109edc1cdd11915095ba47c3a9963dc1e6c432939872bc49212fe34c632cd3ab9fed429c482"
]
}
},
{
"given": {
"txinIndex": 8,
"internalPrivkey": "77863416be0d0665e517e1c375fd6f75839544eca553675ef7fdf4949518ebaa",
"merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
"hashType": 129
},
"intermediary": {
"internalPubkey": "f9f400803e683727b14f463836e1e78e1c64417638aa066919291a225f0e8dd8",
"tweak": "639f0281b7ac49e742cd25b7f188657626da1ad169209078e2761cefd91fd65e",
"tweakedPrivkey": "ec18ce6af99f43815db543f47b8af5ff5df3b2cb7315c955aa4a86e8143d2bf5",
"sigMsg": "0081020000000065cd1da2e6dab7c1f0dcd297c8d61647fd17d821541ea69c3cc37dcbad7f90d4eb4bc500a778eb6a263dc090464cd125c466b5a99667720b1c110468831d058aa1b82af101000000002b0c230000000022512077e30a5522dd9f894c3f8b8bd4c4b2cf82ca7da8a3ea6a239655c39c050ab220ffffffff",
"precomputedUsed": [
"hashOutputs"
],
"sigHash": "cccb739eca6c13a8a89e6e5cd317ffe55669bbda23f2fd37b0f18755e008edd2"
},
"expected": {
"witness": [
"bbc9584a11074e83bc8c6759ec55401f0ae7b03ef290c3139814f545b58a9f8127258000874f44bc46db7646322107d4d86aec8e73b8719a61fff761d75b5dd981"
]
}
}
],
"auxiliary": {
"fullySignedTx": "020000000001097de20cbff686da83a54981d2b9bab3586f4ca7e48f57f5b55963115f3b334e9c010000000000000000d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd990000000000fffffffff8e1f583384333689228c5d28eac13366be082dc57441760d957275419a41842000000006b4830450221008f3b8f8f0537c420654d2283673a761b7ee2ea3c130753103e08ce79201cf32a022079e7ab904a1980ef1c5890b648c8783f4d10103dd62f740d13daa79e298d50c201210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff0689180aa63b30cb162a73c6d2a38b7eeda2a83ece74310fda0843ad604853b0100000000feffffffaa5202bdf6d8ccd2ee0f0202afbbb7461d9264a25e5bfd3c5a52ee1239e0ba6c0000000000feffffff956149bdc66faa968eb2be2d2faa29718acbfe3941215893a2a3446d32acd050000000000000000000e664b9773b88c09c32cb70a2a3e4da0ced63b7ba3b22f848531bbb1d5d5f4c94010000000000000000e9aa6b8e6c9de67619e6a3924ae25696bb7b694bb677a632a74ef7eadfd4eabf0000000000ffffffffa778eb6a263dc090464cd125c466b5a99667720b1c110468831d058aa1b82af10100000000ffffffff0200ca9a3b000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac807840cb0000000020ac9a87f5594be208f8532db38cff670c450ed2fea8fcdefcc9a663f78bab962b0141ed7c1647cb97379e76892be0cacff57ec4a7102aa24296ca39af7541246d8ff14d38958d4cc1e2e478e4d4a764bbfd835b16d4e314b72937b29833060b87276c030141052aedffc554b41f52b521071793a6b88d6dbca9dba94cf34c83696de0c1ec35ca9c5ed4ab28059bd606a4f3a657eec0bb96661d42921b5f50a95ad33675b54f83000141ff45f742a876139946a149ab4d9185574b98dc919d2eb6754f8abaa59d18b025637a3aa043b91817739554f4ed2026cf8022dbd83e351ce1fabc272841d2510a010140b4010dd48a617db09926f729e79c33ae0b4e94b79f04a1ae93ede6315eb3669de185a17d2b0ac9ee09fd4c64b678a0b61a0a86fa888a273c8511be83bfd6810f0247304402202b795e4de72646d76eab3f0ab27dfa30b810e856ff3a46c9a702df53bb0d8cc302203ccc4d822edab5f35caddb10af1be93583526ccfbade4b4ead350781e2f8adcd012102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f90141a3785919a2ce3c4ce26f298c3d51619bc474ae24014bcdd31328cd8cfbab2eff3395fa0a16fe5f486d12f22a9cedded5ae74feb4bbe5351346508c5405bcfee0020141ea0c6ba90763c2d3a296ad82ba45881abb4f426b3f87af162dd24d5109edc1cdd11915095ba47c3a9963dc1e6c432939872bc49212fe34c632cd3ab9fed429c4820141bbc9584a11074e83bc8c6759ec55401f0ae7b03ef290c3139814f545b58a9f8127258000874f44bc46db7646322107d4d86aec8e73b8719a61fff761d75b5dd9810065cd1d"
}
}
]
}
================================================
FILE: bip-0341.mediawiki
================================================
BIP: 341
Layer: Consensus (soft fork)
Title: Taproot: SegWit version 1 spending rules
Authors: Pieter Wuille
Jonas Nick
Anthony Towns
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0341
Status: Deployed
Type: Specification
Assigned: 2020-01-19
License: BSD-3-Clause
Discussion: 2019-05-06: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-May/016914.html [bitcoin-dev] Taproot proposal
2019-10-09: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-October/017378.html [bitcoin-dev] Taproot updates
Requires: 340
==Introduction==
===Abstract===
This document proposes a new SegWit version 1 output type, with spending rules based on Taproot, Schnorr signatures, and Merkle branches.
===Copyright===
This document is licensed under the 3-clause BSD license.
===Motivation===
This proposal aims to improve privacy, efficiency, and flexibility of Bitcoin's scripting capabilities without adding new security assumptions'''What does not adding security assumptions mean?''' Unforgeability of signatures is a necessary requirement to prevent theft. At least when treating script execution as a digital signature scheme itself, unforgeability can be [https://github.com/apoelstra/taproot proven] in the Random Oracle Model assuming the Discrete Logarithm problem is hard. A [https://nbn-resolving.de/urn:nbn:de:hbz:294-60803 proof] for unforgeability of ECDSA in the current script system needs non-standard assumptions on top of that. Note that it is hard in general to model exactly what security for script means, as it depends on the policies and protocols used by wallet software.. Specifically, it seeks to minimize how much information about the spendability conditions of a transaction output is revealed on chain at creation or spending time and to add a number of upgrade mechanisms, while fixing a few minor but long-standing issues.
==Design==
A number of related ideas for improving Bitcoin's scripting capabilities have been previously proposed: Schnorr signatures ([[bip-0340.mediawiki|BIP340]]), Merkle branches ("MAST", [[bip-0114.mediawiki|BIP114]], [[bip-0117.mediawiki|BIP117]]), new sighash modes ([[bip-0118.mediawiki|BIP118]]), new opcodes like CHECKSIGFROMSTACK, [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-January/015614.html Taproot], [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-February/015700.html Graftroot], [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-July/016249.html G'root], and [https://bitcointalk.org/index.php?topic=1377298.0 cross-input aggregation].
Combining all these ideas in a single proposal would be an extensive change, be hard to review, and likely miss new discoveries that otherwise could have been made along the way. Not all are equally mature as well. For example, cross-input aggregation [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-March/015838.html interacts] in complex ways with upgrade mechanisms, and solutions to that are still [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-October/016461.html in flux]. On the other hand, separating them all into independent upgrades would reduce the efficiency and privacy gains to be had, and wallet and service providers may not be inclined to go through many incremental updates. Therefore, we're faced with a tradeoff between functionality and scope creep. In this design we strike a balance by focusing on the structural script improvements offered by Taproot and Merkle branches, as well as changes necessary to make them usable and efficient. For things like sighashes and opcodes we include fixes for known problems, but exclude new features that can be added independently with no downsides.
As a result we choose this combination of technologies:
* '''Merkle branches''' let us only reveal the actually executed part of the script to the blockchain, as opposed to all possible ways a script can be executed. Among the various known mechanisms for implementing this, one where the Merkle tree becomes part of the script's structure directly maximizes the space savings, so that approach is chosen.
* '''Taproot''' on top of that lets us merge the traditionally separate pay-to-pubkey and pay-to-scripthash policies, making all outputs spendable by either a key or (optionally) a script, and indistinguishable from each other. As long as the key-based spending path is used for spending, it is not revealed whether a script path was permitted as well, resulting in space savings and an increase in scripting privacy at spending time.
* Taproot's advantages become apparent under the assumption that most applications involve outputs that could be spent by all parties agreeing. That's where '''Schnorr''' signatures come in, as they permit [https://eprint.iacr.org/2018/068 key aggregation]: a public key can be constructed from multiple participant public keys, and which requires cooperation between all participants to sign for. Such multi-party public keys and signatures are indistinguishable from their single-party equivalents. This means that with taproot most applications can use the key-based spending path, which is both efficient and private. This can be generalized to arbitrary M-of-N policies, as Schnorr signatures support threshold signing, at the cost of more complex setup protocols.
* As Schnorr signatures also permit '''batch validation''', allowing multiple signatures to be validated together more efficiently than validating each one independently, we make sure all parts of the design are compatible with this.
* Where unused bits appear as a result of the above changes, they are reserved for mechanisms for '''future extensions'''. As a result, every script in the Merkle tree has an associated version such that new script versions can be introduced with a soft fork while remaining compatible with BIP 341. Additionally, future soft forks can make use of the currently unused annex in the witness (see [[bip-0341.mediawiki#rationale|Rationale]]).
* While the core semantics of the '''signature hashing algorithm''' are not changed, a number of improvements are included in this proposal. The new signature hashing algorithm fixes the verification capabilities of offline signing devices by including amount and scriptPubKey in the signature message, avoids unnecessary hashing, uses '''tagged hashes''' and defines a default sighash byte.
* The '''public key is directly included in the output''' in contrast to typical earlier constructions which store a hash of the public key or script in the output. This has the same cost for senders and is more space efficient overall if the key-based spending path is taken. '''Why is the public key directly included in the output?''' While typical earlier constructions store a hash of a script or a public key in the output, this is rather wasteful when a public key is always involved. To guarantee batch verifiability, the public key must be known to every verifier, and thus only revealing its hash as an output would imply adding an additional 32 bytes to the witness. Furthermore, to maintain [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-January/012198.html 128-bit collision security] for outputs, a 256-bit hash would be required anyway, which is comparable in size (and thus in cost for senders) to revealing the public key directly. While the usage of public key hashes is often said to protect against ECDLP breaks or quantum computers, this protection is very weak at best: transactions are not protected while being confirmed, and a very [https://web.archive.org/web/20220531184542/https://twitter.com/pwuille/status/1108085284862713856 large portion] of the currency's supply is not under such protection regardless. Actual resistance to such systems can be introduced by relying on different cryptographic assumptions, but this proposal focuses on improvements that do not change the security model.
Informally, the resulting design is as follows: a new witness version is added (version 1), whose programs consist of 32-byte encodings of points ''Q''. ''Q'' is computed as ''P + hash(P||m)G'' for a public key ''P'', and the root ''m'' of a Merkle tree whose leaves consist of a version number and a script. These outputs can be spent directly by providing a signature for ''Q'', or indirectly by revealing ''P'', the script and leaf version, inputs that satisfy the script, and a Merkle path that proves ''Q'' committed to that leaf. All hashes in this construction (the hash for computing ''Q'' from ''P'', the hashes inside the Merkle tree's inner nodes, and the signature hashes used) are tagged to guarantee domain separation.
== Specification ==
This section specifies the Taproot consensus rules. Validity is defined by exclusion: a block or transaction is valid if no condition exists that marks it failed.
The notation below follows that of [[bip-0340.mediawiki#design|BIP340]]. This includes the ''hashtag(x)'' notation to refer to ''SHA256(SHA256(tag) || SHA256(tag) || x)''. To the best of the authors' knowledge, no existing use of SHA256 in Bitcoin feeds it a message that starts with two single SHA256 outputs, making collisions between ''hashtag'' with other hashes extremely unlikely.
=== Script validation rules ===
A Taproot output is a native SegWit output (see [[bip-0141.mediawiki|BIP141]]) with version number 1, and a 32-byte witness program.
The following rules only apply when such an output is being spent. Any other outputs, including version 1 outputs with lengths other than 32 bytes, or P2SH-wrapped version 1 outputs'''Why is P2SH-wrapping not supported?''' Using P2SH-wrapped outputs only provides 80-bit collision security due to the use of a 160-bit hash. This is considered low, and becomes a security risk whenever the output includes data from more than a single party (public keys, hashes, ...)., remain unencumbered.
* Let ''q'' be the 32-byte array containing the witness program (the second push in the scriptPubKey) which represents a public key according to [[bip-0340.mediawiki#design|BIP340]].
* Fail if the witness stack has 0 elements.
* If there are at least two witness elements, and the first byte of the last element is 0x50'''Why is the first byte of the annex 0x50?''' The 0x50 is chosen as it could not be confused with a valid P2WPKH or P2WSH spending. As the control block's initial byte's lowest bit is used to indicate the parity of the public key's Y coordinate, each leaf version needs an even byte value and the immediately following odd byte value that are both not yet used in P2WPKH or P2WSH spending. To indicate the annex, only an "unpaired" available byte is necessary like 0x50. This choice maximizes the available options for future script versions., this last element is called ''annex'' ''a'''''What is the purpose of the annex?''' The annex is a reserved space for future extensions, such as indicating the validation costs of computationally expensive new opcodes in a way that is recognizable without knowing the scriptPubKey of the output being spent. Until the meaning of this field is defined by another softfork, users SHOULD NOT include annex in transactions, or it may lead to PERMANENT FUND LOSS. and is removed from the witness stack. The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, but is otherwise ignored during taproot validation.
* If there is exactly one element left in the witness stack, key path spending is used:
** The single witness stack element is interpreted as the signature and must be valid (see the next section) for the public key ''q'' (see the next subsection).
* If there are at least two witness elements left, script path spending is used:
** Call the second-to-last stack element ''s'', the script.
** The last stack element is called the control block ''c'', and must have length ''33 + 32m'', for a value of ''m'' that is an integer between 0 and 128'''Why is the Merkle path length limited to 128?''' The optimally space-efficient Merkle tree can be constructed based on the probabilities of the scripts in the leaves, using the Huffman algorithm. This algorithm will construct branches with lengths approximately equal to ''log2(1/probability)'', but to have branches longer than 128 you would need to have scripts with an execution chance below 1 in ''2128''. As that is our security bound, scripts that truly have such a low chance can probably be removed entirely., inclusive. Fail if it does not have such a length.
** Let ''p = c[1:33]'' and let ''P = lift_x(int(p))'' where ''lift_x'' and ''[:]'' are defined as in [[bip-0340.mediawiki#design|BIP340]]. Fail if this point is not on the curve.
** Let ''v = c[0] & 0xfe'' and call it the ''leaf version'''''What constraints are there on the leaf version?''' First, the leaf version cannot be odd as ''c[0] & 0xfe'' will always be even, and cannot be ''0x50'' as that would result in ambiguity with the annex. In addition, in order to support some forms of static analysis that rely on being able to identify script spends without access to the output being spent, it is recommended to avoid using any leaf versions that would conflict with a valid first byte of either a valid P2WPKH pubkey or a valid P2WSH script (that is, both ''v'' and ''v | 1'' should be an undefined, invalid or disabled opcode or an opcode that is not valid as the first opcode). The values that comply to this rule are the 32 even values between ''0xc0'' and ''0xfe'' and also ''0x66'', ''0x7e'', ''0x80'', ''0x84'', ''0x96'', ''0x98'', ''0xba'', ''0xbc'', ''0xbe''. Note also that this constraint implies that leaf versions should be shared amongst different witness versions, as knowing the witness version requires access to the output being spent..
** Let ''k0 = hashTapLeaf(v || compact_size(size of s) || s)''; also call it the ''tapleaf hash''.
** For ''j'' in ''[0,1,...,m-1]'':
*** Let ''ej = c[33+32j:65+32j]''.
*** Let ''kj+1 depend on whether ''kj < ej'' (lexicographically)'''Why are child elements sorted before hashing in the Merkle tree?''' By doing so, it is not necessary to reveal the left/right directions along with the hashes in revealed Merkle branches. This is possible because we do not actually care about the position of specific scripts in the tree; only that they are actually committed to.:
**** If ''kj < ej'': ''kj+1 = hashTapBranch(kj || ej)'''''Why not use a more efficient hash construction for inner Merkle nodes?''' The chosen construction does require two invocations of the SHA256 compression functions, one of which can be avoided in theory (see [[bip-0098.mediawiki|BIP98]]). However, it seems preferable to stick to constructions that can be implemented using standard cryptographic primitives, both for implementation simplicity and analyzability. If necessary, a significant part of the second compression function can be optimized out by [https://github.com/bitcoin/bitcoin/pull/13191 specialization] for 64-byte inputs..
**** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''.
** Let ''t = hashTapTweak(p || km)''.
** If ''t ≥ 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141'' (order of secp256k1), fail.
** Let ''Q = P + int(t)G''.
** If ''q ≠ x(Q)'' or ''c[0] & 1 ≠ y(Q) mod 2'', fail'''Why is it necessary to reveal a bit in a script path spend and check that it matches the parity of the Y coordinate of ''Q''?''' The parity of the Y coordinate is necessary to lift the X coordinate ''q'' to a unique point. While this is not strictly necessary for verifying the taproot commitment as described above, it is necessary to allow batch verification. Alternatively, ''Q'' could be forced to have an even Y coordinate, but that would require retrying with different internal public keys (or different messages) until ''Q'' has that property. There is no downside to adding the parity bit because otherwise the control block bit would be unused..
** Execute the script, according to the applicable script rules'''What are the applicable script rules in script path spends?''' [[bip-0342.mediawiki|BIP342]] specifies validity rules that apply for leaf version 0xc0, but future proposals can introduce rules for other leaf versions., using the witness stack elements excluding the script ''s'', the control block ''c'', and the annex ''a'' if present, as initial stack. This implies that for the future leaf versions (non-''0xC0'') the execution must succeed.'''Why we need to success on future leaf version validation''' This is required to enable future leaf versions as soft forks.
''q'' is referred to as ''taproot output key'' and ''p'' as ''taproot internal key''.
=== Signature validation rules ===
We first define a reusable common signature message calculation function, followed by the actual signature validation as it's used in key path spending.
==== Common signature message ====
The function ''SigMsg(hash_type, ext_flag)'' computes the common portion of the message being signed as a byte array. It is implicitly also a function of the spending transaction and the outputs it spends, but these are not listed to keep notation simple.
The parameter ''hash_type'' is an 8-bit unsigned value. The SIGHASH encodings from the legacy script system are reused, including SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, and SIGHASH_ANYONECANPAY. We define a new ''hashtype'' SIGHASH_DEFAULT (value ''0x00'') which results in signing over the whole transaction just as for SIGHASH_ALL. The following restrictions apply, which cause validation failure if violated:
* Using any undefined ''hash_type'' (not ''0x00'', ''0x01'', ''0x02'', ''0x03'', ''0x81'', ''0x82'', or ''0x83'''''Why reject unknown ''hash_type'' values?''' By doing so, it is easier to reason about the worst case amount of signature hashing an implementation with adequate caching must perform.).
* Using SIGHASH_SINGLE without a "corresponding output" (an output with the same index as the input being verified).
The parameter ''ext_flag'' is an integer in range 0-127, and is used for indicating (in the message) that extensions are appended to the output of ''SigMsg()'''''What extensions use the ''ext_flag'' mechanism?''' [[bip-0342.mediawiki#common-signature-message-extension|BIP342]] reuses the same common signature message algorithm, but adds BIP342-specific data at the end, which is indicated using ''ext_flag = 1''..
If the parameters take acceptable values, the message is the concatenation of the following data, in order (with byte size of each item listed in parentheses). Numerical values in 2, 4, or 8-byte are encoded in little-endian.
* Control:
** ''hash_type'' (1).
* Transaction data:
** ''nVersion'' (4): the ''nVersion'' of the transaction.
** ''nLockTime'' (4): the ''nLockTime'' of the transaction.
** If the ''hash_type & 0x80'' does not equal SIGHASH_ANYONECANPAY:
*** ''sha_prevouts'' (32): the SHA256 of the serialization of all input outpoints.
*** ''sha_amounts'' (32): the SHA256 of the serialization of all input amounts.
*** ''sha_scriptpubkeys'' (32): the SHA256 of all spent outputs' ''scriptPubKeys'', serialized as script inside CTxOut.
*** ''sha_sequences'' (32): the SHA256 of the serialization of all input ''nSequence''.
** If ''hash_type & 3'' does not equal SIGHASH_NONE or SIGHASH_SINGLE:
*** ''sha_outputs'' (32): the SHA256 of the serialization of all outputs in CTxOut format.
* Data about this input:
** ''spend_type'' (1): equal to ''(ext_flag * 2) + annex_present'', where ''annex_present'' is 0 if no annex is present, or 1 otherwise (the original witness stack has two or more witness elements, and the first byte of the last element is ''0x50'')
** If ''hash_type & 0x80'' equals SIGHASH_ANYONECANPAY:
*** ''outpoint'' (36): the COutPoint of this input (32-byte hash + 4-byte little-endian).
*** ''amount'' (8): value of the previous output spent by this input.
*** ''scriptPubKey'' (35): ''scriptPubKey'' of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
*** ''nSequence'' (4): ''nSequence'' of this input.
** If ''hash_type & 0x80'' does not equal SIGHASH_ANYONECANPAY:
*** ''input_index'' (4): index of this input in the transaction input vector. Index of the first input is 0.
** If an annex is present (the lowest bit of ''spend_type'' is set):
*** ''sha_annex'' (32): the SHA256 of ''(compact_size(size of annex) || annex)'', where ''annex'' includes the mandatory ''0x50'' prefix.
* Data about this output:
** If ''hash_type & 3'' equals SIGHASH_SINGLE:
*** ''sha_single_output'' (32): the SHA256 of the corresponding output in CTxOut format.
The total length of ''SigMsg()'' is at most ''206'' bytes'''What is the output length of ''SigMsg()''?''' The total length of ''SigMsg()'' can be computed using the following formula: ''174 - is_anyonecanpay * 49 - is_none * 32 + has_annex * 32''.. Note that this does not include the size of sub-hashes such as ''sha_prevouts'', which may be cached across signatures of the same transaction.
In summary, the semantics of the [[bip-0143.mediawiki|BIP143]] sighash types remain unchanged, except the following:
# The way and order of serialization is changed.'''Why is the serialization in the signature message changed?''' Hashes that go into the signature message and the message itself are now computed with a single SHA256 invocation instead of double SHA256. There is no expected security improvement by doubling SHA256 because this only protects against length-extension attacks against SHA256 which are not a concern for signature messages because there is no secret data. Therefore doubling SHA256 is a waste of resources. The message computation now follows a logical order with transaction level data first, then input data and output data. This allows to efficiently cache the transaction part of the message across different inputs using the SHA256 midstate. Additionally, sub-hashes can be skipped when calculating the message (for example `sha_prevouts` if SIGHASH_ANYONECANPAY is set) instead of setting them to zero and then hashing them as in BIP143. Despite that, collisions are made impossible by committing to the length of the data (implicit in ''hash_type'' and ''spend_type'') before the variable length data.
# The signature message commits to the ''scriptPubKey'' of the spent output and if the SIGHASH_ANYONECANPAY flag is not set, the message commits to the ''scriptPubKey''s of ''all'' outputs spent by the transaction. '''Why does the signature message commit to the ''scriptPubKey''?''' This prevents lying to offline signing devices about output being spent, even when the actually executed script (''scriptCode'' in BIP143) is correct. This means it's possible to compactly prove to a hardware wallet what (unused) execution paths existed. Moreover, committing to all spent ''scriptPubKey''s helps offline signing devices to determine the subset that belong to its own wallet. This is useful in [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-April/017801.html automated coinjoins]..
# If the SIGHASH_ANYONECANPAY flag is not set, the message commits to the amounts of ''all'' transaction inputs.'''Why does the signature message commit to the amounts of all transaction inputs?''' This eliminates the possibility to lie to offline signing devices about the fee of a transaction.
# The signature message commits to all input ''nSequence'' if SIGHASH_NONE or SIGHASH_SINGLE are set (unless SIGHASH_ANYONECANPAY is set as well).'''Why does the signature message commit to all input ''nSequence'' if SIGHASH_SINGLE or SIGHASH_NONE are set?''' Because setting them already makes the message commit to the prevouts part of all transaction inputs, it is not useful to treat the ''nSequence'' any different. Moreover, this change makes ''nSequence'' consistent with the view that SIGHASH_SINGLE and SIGHASH_NONE only modify the signature message with respect to transaction outputs and not inputs.
# The signature message includes commitments to the taproot-specific data ''spend_type'' and ''annex'' (if present).
==== Taproot key path spending signature validation ====
A Taproot signature is a 64-byte Schnorr signature, as defined in [[bip-0340.mediawiki|BIP340]], with the sighash byte appended in the usual Bitcoin fashion. This sighash byte is optional. If omitted, the resulting signatures are 64 bytes, and a SIGHASH_DEFAULT mode is implied.
To validate a signature ''sig'' with public key ''q'':
* If the ''sig'' is 64 bytes long, return ''Verify(q, hashTapSighash(0x00 || SigMsg(0x00, 0)), sig)'''''Why is the input to ''hashTapSighash'' prefixed with 0x00?''' This prefix is called the sighash epoch, and allows reusing the ''hashTapSighash'' tagged hash in future signature algorithms that make invasive changes to how hashing is performed (as opposed to the ''ext_flag'' mechanism that is used for incremental extensions). An alternative is having them use a different tag, but supporting a growing number of tags may become undesirable., where ''Verify'' is defined in [[bip-0340.mediawiki#design|BIP340]].
* If the ''sig'' is 65 bytes long, return ''sig[64] ≠ 0x00'''Why can the hash_type not be 0x00 in 65-byte signatures?''' Permitting that would enable malleating (by third parties, including miners) 64-byte signatures into 65-byte ones, resulting in a different `wtxid` and a different fee rate than the creator intended. and Verify(q, hashTapSighash(0x00 || SigMsg(sig[64], 0)), sig[0:64])''.
* Otherwise, fail'''Why permit two signature lengths?''' By making the most common type of hash_type implicit, a byte can often be saved..
== Constructing and spending Taproot outputs ==
This section discusses how to construct and spend Taproot outputs. It only affects wallet software that chooses to implement receiving and spending,
and is not consensus critical in any way.
Conceptually, every Taproot output corresponds to a combination of a single public key condition (the internal key), and zero or more general conditions encoded in scripts organized in a tree.
Satisfying any of these conditions is sufficient to spend the output.
'''Initial steps''' The first step is determining what the internal key and the organization of the rest of the scripts should be. The specifics are likely application dependent, but here are some general guidelines:
* When deciding between scripts with conditionals (OP_IF etc.) and splitting them up into multiple scripts (each corresponding to one execution path through the original script), it is generally preferable to pick the latter.
* When a single condition requires signatures with multiple keys, key aggregation techniques like MuSig can be used to combine them into a single key. The details are out of scope for this document, but note that this may complicate the signing procedure.
* If one or more of the spending conditions consist of just a single key (after aggregation), the most likely one should be made the internal key. If no such condition exists, it may be worthwhile adding one that consists of an aggregation of all keys participating in all scripts combined; effectively adding an "everyone agrees" branch. If that is inacceptable, pick as internal key a "Nothing Up My Sleeve" (NUMS) point, i.e., a point with unknown discrete logarithm. One example of such a point is ''H = lift_x(0x50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0)'' which is [https://github.com/ElementsProject/secp256k1-zkp/blob/11af7015de624b010424273be3d91f117f172c82/src/modules/rangeproof/main_impl.h#L16 constructed] by taking the hash of the standard uncompressed encoding of the [https://www.secg.org/sec2-v2.pdf secp256k1] base point ''G'' as X coordinate. In order to avoid leaking the information that key path spending is not possible it is recommended to pick a fresh integer ''r'' in the range ''0...n-1'' uniformly at random and use ''H + rG'' as internal key. It is possible to prove that this internal key does not have a known discrete logarithm with respect to ''G'' by revealing ''r'' to a verifier who can then reconstruct how the internal key was created.
* If the spending conditions do not require a script path, the output key should commit to an unspendable script path instead of having no script path. This can be achieved by computing the output key point as ''Q = P + int(hashTapTweak(bytes(P)))G''. '''Why should the output key always have a taproot commitment, even if there is no script path?'''
If the taproot output key is an aggregate of keys, there is the possibility for a malicious party to add a script path without being noticed by the other parties.
This allows to bypass the multiparty policy and to steal the coin.
MuSig key aggregation does not have this issue because it already causes the internal key to be randomized.
The attack works as follows: Assume Alice and Mallory want to aggregate their keys into a taproot output key without a script path.
In order to prevent key cancellation and related attacks they use [https://eprint.iacr.org/2018/483.pdf MSDL-pop] instead of MuSig.
The MSDL-pop protocol requires all parties to provide a proof of possession of their corresponding secret key and the aggregated key is just the sum of the individual keys.
After Mallory receives Alice's key ''A'', Mallory creates ''M = M0 + int(t)G'' where ''M0'' is Mallory's original key and ''t'' allows a script path spend with internal key ''P = A + M0'' and a script that only contains Mallory's key.
Mallory sends a proof of possession of ''M'' to Alice and both parties compute output key ''Q = A + M = P + int(t)G''.
Alice will not be able to notice the script path, but Mallory can unilaterally spend any coin with output key ''Q''.
* The remaining scripts should be organized into the leaves of a binary tree. This can be a balanced tree if each of the conditions these scripts correspond to are equally likely. If probabilities for each condition are known, consider constructing the tree as a Huffman tree.
'''Computing the output script''' Once the spending conditions are split into an internal key internal_pubkey and a binary tree whose leaves are (leaf_version, script) tuples, the output script can be computed using the Python3 algorithms below. These algorithms take advantage of helper functions from the [[bip-0340/reference.py|BIP340 reference code]] for integer conversion, point multiplication, and tagged hashes.
First, we define taproot_tweak_pubkey for 32-byte [[bip-0340.mediawiki|BIP340]] public key arrays.
The function returns a bit indicating the tweaked public key's Y coordinate as well as the public key byte array.
The parity bit will be required for spending the output with a script path.
In order to allow spending with the key path, we define taproot_tweak_seckey to compute the secret key for a tweaked public key.
For any byte string h it holds that taproot_tweak_pubkey(pubkey_gen(seckey), h)[1] == pubkey_gen(taproot_tweak_seckey(seckey, h)).
Note that because tweaks are applied to 32-byte public keys, `taproot_tweak_seckey` may need to negate the secret key before applying the tweak.
def taproot_tweak_pubkey(pubkey, h):
t = int_from_bytes(tagged_hash("TapTweak", pubkey + h))
if t >= SECP256K1_ORDER:
raise ValueError
P = lift_x(int_from_bytes(pubkey))
if P is None:
raise ValueError
Q = point_add(P, point_mul(G, t))
return 0 if has_even_y(Q) else 1, bytes_from_int(x(Q))
def taproot_tweak_seckey(seckey0, h):
seckey0 = int_from_bytes(seckey0)
P = point_mul(G, seckey0)
seckey = seckey0 if has_even_y(P) else SECP256K1_ORDER - seckey0
t = int_from_bytes(tagged_hash("TapTweak", bytes_from_int(x(P)) + h))
if t >= SECP256K1_ORDER:
raise ValueError
return bytes_from_int((seckey + t) % SECP256K1_ORDER)
The following function, taproot_output_script, returns a byte array with the scriptPubKey (see [[bip-0141.mediawiki|BIP141]]).
ser_script refers to a function that prefixes its input with a CompactSize-encoded length.
def taproot_tree_helper(script_tree):
if isinstance(script_tree, tuple):
leaf_version, script = script_tree
h = tagged_hash("TapLeaf", bytes([leaf_version]) + ser_script(script))
return ([((leaf_version, script), bytes())], h)
left, left_h = taproot_tree_helper(script_tree[0])
right, right_h = taproot_tree_helper(script_tree[1])
ret = [(l, c + right_h) for l, c in left] + [(l, c + left_h) for l, c in right]
if right_h < left_h:
left_h, right_h = right_h, left_h
return (ret, tagged_hash("TapBranch", left_h + right_h))
def taproot_output_script(internal_pubkey, script_tree):
"""Given a internal public key and a tree of scripts, compute the output script.
script_tree is either:
- a (leaf_version, script) tuple (leaf_version is 0xc0 for [[bip-0342.mediawiki|BIP342]] scripts)
- a list of two elements, each with the same structure as script_tree itself
- None
"""
if script_tree is None:
h = bytes()
else:
_, h = taproot_tree_helper(script_tree)
_, output_pubkey = taproot_tweak_pubkey(internal_pubkey, h)
return bytes([0x51, 0x20]) + output_pubkey
[[File:bip-0341/tree.png|frame|This diagram shows the hashing structure to obtain the tweak from an internal key ''P'' and a Merkle tree consisting of 5 script leaves. ''A'', ''B'', ''C'' and ''E'' are ''TapLeaf'' hashes similar to ''D'' and ''AB'' is a ''TapBranch'' hash. Note that when ''CDE'' is computed ''E'' is hashed first because ''E'' is less than ''CD''.]]
To spend this output using script ''D'', the control block would contain the following data in this order:
The TapTweak would then be computed as described [[bip-0341.mediawiki#script-validation-rules|above]] like so:
D = tagged_hash("TapLeaf", bytes([leaf_version]) + ser_script(script))
CD = tagged_hash("TapBranch", C + D)
CDE = tagged_hash("TapBranch", E + CD)
ABCDE = tagged_hash("TapBranch", AB + CDE)
TapTweak = tagged_hash("TapTweak", p + ABCDE)
'''Spending using the key path''' A Taproot output can be spent with the secret key corresponding to the internal_pubkey. To do so, a witness stack consists of a single element: a [[bip-0340.mediawiki|BIP340]] signature on the signature hash as defined above, with the secret key tweaked by the same h as in the above snippet. See the code below:
def taproot_sign_key(script_tree, internal_seckey, hash_type, bip340_aux_rand):
if script_tree is None:
h = bytes()
else:
_, h = taproot_tree_helper(script_tree)
output_seckey = taproot_tweak_seckey(internal_seckey, h)
sig = schnorr_sign(sighash(hash_type), output_seckey, bip340_aux_rand)
if hash_type != 0:
sig += bytes([hash_type])
return [sig]
This function returns the witness stack necessary and a sighash function to compute the signature hash as defined above (for simplicity, the snippet above ignores passing information like the transaction, the input position, ... to the sighashing code).
'''Spending using one of the scripts''' A Taproot output can be spent by satisfying any of the scripts used in its construction. To do so, a witness stack consisting of the script's inputs, plus the script itself and the control block are necessary. See the code below:
def taproot_sign_script(internal_pubkey, script_tree, script_num, inputs):
info, h = taproot_tree_helper(script_tree)
(leaf_version, script), path = info[script_num]
output_pubkey_y_parity, _ = taproot_tweak_pubkey(internal_pubkey, h)
pubkey_data = bytes([output_pubkey_y_parity + leaf_version]) + internal_pubkey
return inputs + [script, pubkey_data + path]
== Security ==
Taproot improves the privacy of Bitcoin because instead of revealing all possible conditions for spending an output, only the satisfied spending condition has to be published.
Ideally, outputs are spent using the key path which prevents observers from learning the spending conditions of a coin.
A key path spend could be a "normal" payment from a single- or multi-signature wallet or the cooperative settlement of hidden multiparty contract.
A script path spend leaks that there is a script path and that the key path was not applicable - for example because the involved parties failed to reach agreement.
Moreover, the depth of a script in the Merkle root leaks information including the minimum depth of the tree, which suggests specific wallet software that created the output and helps clustering.
Therefore, the privacy of script spends can be improved by deviating from the optimal tree determined by the probability distribution over the leaves.
Just like other existing output types, taproot outputs should never reuse keys, for privacy reasons.
This does not only apply to the particular leaf that was used to spend an output but to all leaves committed to in the output.
If leaves were reused, it could happen that spending a different output would reuse the same Merkle branches in the Merkle proof.
Using fresh keys implies that taproot output construction does not need to take special measures to randomizing leaf positions because they are already randomized due to the branch-sorting Merkle tree construction used in taproot.
This does not avoid leaking information through the leaf depth and therefore only applies to balanced (sub-) trees.
In addition, every leaf should have a set of keys distinct from every other leaf.
The reason for this is to increase leaf entropy and prevent an observer from learning an undisclosed script using brute-force search.
== Test vectors ==
Test vectors for wallet operation (scriptPubKey computation, key path spending, control block construction) can be found [[bip-0341/wallet-test-vectors.json|here]].
It consists of two sets of vectors.
* The first "scriptPubKey" tests concern computing the scriptPubKey and (mainnet) BIP350 address given an internal public key, and a script tree. The script tree is encoded as null to represent no scripts, a JSON object to represent a leaf node, or a 2-element array to represent an inner node. The control blocks needed for script path spending are also provided for each of the script leaves.
* The second "keyPathSpending" tests consists of a list of test cases, each of which provides an unsigned transaction and the UTXOs it spends. For each of its BIP341 inputs, the internal private key and the Merkle root it was derived from is given, as well as the expected witness to spend it. All signatures are created with an all-zero (0x0000...0000) BIP340 auxiliary randomness array.
* In all cases, hexadecimal values represent byte arrays, not numbers. In particular, that means that provided hash values have the hex digits corresponding to the first bytes first. This differs from the convention used for txids and block hashes, where the hex strings represent numbers, resulting in a reversed order.
Validation test vectors used in the [https://github.com/bitcoin/bitcoin/blob/3820090bd619ac85ab35eff376c03136fe4a9f04/src/test/script_tests.cpp#L1718 Bitcoin Core unit test framework] can be found [https://github.com/bitcoin-core/qa-assets/blob/main/unit_test_data/script_assets_test.json?raw=true here].
== Rationale ==
== Deployment ==
This BIP is deployed concurrently with [[bip-0342.mediawiki|BIP342]].
For Bitcoin signet, these BIPs are always active.
For Bitcoin mainnet and testnet3, these BIPs are deployed by "version bits" with the name "taproot" and bit 2, using [[bip-0009.mediawiki|BIP9]] modified to use a lower threshold, with an additional ''min_activation_height'' parameter and replacing the state transition logic for the DEFINED, STARTED and LOCKED_IN states as follows:
case DEFINED:
if (GetMedianTimePast(block.parent) >= starttime) {
return STARTED;
}
return DEFINED;
case STARTED:
int count = 0;
walk = block;
for (i = 0; i < 2016; i++) {
walk = walk.parent;
if ((walk.nVersion & 0xE0000000) == 0x20000000 && ((walk.nVersion >> bit) & 1) == 1) {
count++;
}
}
if (count >= threshold) {
return LOCKED_IN;
} else if (GetMedianTimePast(block.parent) >= timeout) {
return FAILED;
}
return STARTED;
case LOCKED_IN:
if (block.nHeight < min_activation_height) {
return LOCKED_IN;
}
return ACTIVE;
For Bitcoin mainnet, the starttime is epoch timestamp 1619222400 (midnight 24 April 2021 UTC), timeout is epoch timestamp 1628640000 (midnight 11 August 2021 UTC), the threshold is 1815 blocks (90%) instead of 1916 blocks (95%), and the min_activation_height is block 709632.
The deployment did activate at height 709632 on Bitcoin mainnet.
For Bitcoin testnet3, the starttime is epoch timestamp 1619222400 (midnight 24 April 2021 UTC), timeout is epoch timestamp 1628640000 (midnight 11 August 2021 UTC), the threshold is 1512 blocks (75%), and the min_activation_height is block 0.
The deployment did activate at height 2011968 on Bitcoin testnet3.
== Backwards compatibility ==
As a soft fork, older software will continue to operate without modification.
Non-upgraded nodes, however, will consider all SegWit version 1 witness programs as anyone-can-spend scripts.
They are strongly encouraged to upgrade in order to fully validate the new programs.
Non-upgraded wallets can receive and send bitcoin from non-upgraded and upgraded wallets using SegWit version 0 programs, traditional pay-to-pubkey-hash, etc.
Depending on the implementation non-upgraded wallets may be able to send to Segwit version 1 programs if they support sending to [[bip-0350.mediawiki|BIP350]] Bech32m addresses.
== Acknowledgements ==
This document is the result of discussions around script and signature improvements with many people, and had direct contributions from Greg Maxwell and others. It further builds on top of earlier published proposals such as Taproot by Greg Maxwell, and Merkle branch constructions by Russell O'Connor, Johnson Lau, and Mark Friedenbach.
The authors wish the thank Arik Sosman for suggesting to sort Merkle node children before hashes, removing the need to transfer the position in the tree, as well as all those who provided valuable feedback and reviews, including the participants of the [https://github.com/ajtowns/taproot-review structured reviews].
================================================
FILE: bip-0342.mediawiki
================================================
BIP: 342
Layer: Consensus (soft fork)
Title: Validation of Taproot Scripts
Authors: Pieter Wuille
Jonas Nick
Anthony Towns
Status: Deployed
Type: Specification
Assigned: 2020-01-19
License: BSD-3-Clause
Discussion: 2019-05-06: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-May/016914.html [bitcoin-dev] Taproot proposal
Requires: 340, 341
==Introduction==
===Abstract===
This document specifies the semantics of the initial scripting system under [[bip-0341.mediawiki|BIP341]].
===Copyright===
This document is licensed under the 3-clause BSD license.
===Motivation===
[[bip-0341.mediawiki|BIP341]] proposes improvements to just the script structure, but some of its goals are incompatible with the semantics of certain opcodes within the scripting language itself.
While it is possible to deal with these in separate optional improvements, their impact is not guaranteed unless they are addressed simultaneously with [[bip-0341.mediawiki|BIP341]] itself.
Specifically, the goal is making '''Schnorr signatures''', '''batch validation''', and '''signature hash''' improvements available to spends that use the script system as well.
==Design==
In order to achieve these goals, signature opcodes OP_CHECKSIG and OP_CHECKSIGVERIFY are modified to verify Schnorr signatures as specified in [[bip-0340.mediawiki|BIP340]] and to use a signature message algorithm based on the common message calculation in [[bip-0341.mediawiki|BIP341]].
The tapscript signature message also simplifies OP_CODESEPARATOR handling and makes it more efficient.
The inefficient OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY opcodes are disabled.
Instead, a new opcode OP_CHECKSIGADD is introduced to allow creating the same multisignature policies in a batch-verifiable way.
Tapscript uses a new, simpler signature opcode limit fixing complicated interactions with transaction weight.
Furthermore, a potential malleability vector is eliminated by requiring MINIMALIF.
Tapscript can be upgraded through soft forks by defining unknown key types, for example to add new hash_types or signature algorithms.
Additionally, the new tapscript OP_SUCCESS opcodes allow introducing new opcodes more cleanly than through OP_NOP.
==Specification==
The rules below only apply when validating a transaction input for which all of the conditions below are true:
* The transaction input is a '''segregated witness spend''' (i.e., the scriptPubKey contains a witness program as defined in [[bip-0141.mediawiki|BIP141]]).
* It is a '''taproot spend''' as defined in [[bip-0341.mediawiki#design|BIP341]] (i.e., the witness version is 1, the witness program is 32 bytes, and it is not P2SH wrapped).
* It is a '''script path spend''' as defined in [[bip-0341.mediawiki#design|BIP341]] (i.e., after removing the optional annex from the witness stack, two or more stack elements remain).
* The leaf version is ''0xc0'' (i.e. the first byte of the last witness element after removing the optional annex is ''0xc0'' or ''0xc1''), marking it as a '''tapscript spend'''.
Validation of such inputs must be equivalent to performing the following steps in the specified order.
# If the input is invalid due to BIP141 or BIP341, fail.
# The script as defined in BIP341 (i.e., the penultimate witness stack element after removing the optional annex) is called the '''tapscript''' and is decoded into opcodes, one by one:
## If any opcode numbered ''80, 98, 126-129, 131-134, 137-138, 141-142, 149-153, 187-254'' is encountered, validation succeeds (none of the rules below apply). This is true even if later bytes in the tapscript would fail to decode otherwise. These opcodes are renamed to OP_SUCCESS80, ..., OP_SUCCESS254, and collectively known as OP_SUCCESSx'''OP_SUCCESSx''' OP_SUCCESSx is a mechanism to upgrade the Script system. Using an OP_SUCCESSx before its meaning is defined by a softfork is insecure and leads to fund loss. The inclusion of OP_SUCCESSx in a script will pass it unconditionally. It precedes any script execution rules to avoid the difficulties in specifying various edge cases, for example: OP_SUCCESSx in a script with an input stack larger than 1000 elements, OP_SUCCESSx after too many signature opcodes, or even scripts with conditionals lacking OP_ENDIF. The mere existence of an OP_SUCCESSx anywhere in the script will guarantee a pass for all such cases. OP_SUCCESSx are similar to the OP_RETURN in very early bitcoin versions (v0.1 up to and including v0.3.5). The original OP_RETURN terminates script execution immediately, and return pass or fail based on the top stack element at the moment of termination. This was one of a major design flaws in the original bitcoin protocol as it permitted unconditional third party theft by placing an OP_RETURN in scriptSig. This is not a concern in the present proposal since it is not possible for a third party to inject an OP_SUCCESSx to the validation process, as the OP_SUCCESSx is part of the script (and thus committed to by the taproot output), implying the consent of the coin owner. OP_SUCCESSx can be used for a variety of upgrade possibilities:
* An OP_SUCCESSx could be turned into a functional opcode through a softfork. Unlike OP_NOPx-derived opcodes which only have read-only access to the stack, OP_SUCCESSx may also write to the stack. Any rule changes to an OP_SUCCESSx-containing script may only turn a valid script into an invalid one, and this is always achievable with softforks.
* Since OP_SUCCESSx precedes size check of initial stack and push opcodes, an OP_SUCCESSx-derived opcode requiring stack elements bigger than 520 bytes may uplift the limit in a softfork.
* OP_SUCCESSx may also redefine the behavior of existing opcodes so they could work together with the new opcode. For example, if an OP_SUCCESSx-derived opcode works with 64-bit integers, it may also allow the existing arithmetic opcodes in the ''same script'' to do the same.
* Given that OP_SUCCESSx even causes potentially unparseable scripts to pass, it can be used to introduce multi-byte opcodes, or even a completely new scripting language when prefixed with a specific OP_SUCCESSx opcode..
## If any push opcode fails to decode because it would extend past the end of the tapscript, fail.
# If the '''initial stack''' as defined in BIP341 (i.e., the witness stack after removing both the optional annex and the two last stack elements after that) violates any resource limits (stack size, and size of the elements in the stack; see "Resource Limits" below), fail. Note that this check can be bypassed using OP_SUCCESSx.
# The tapscript is executed according to the rules in the following section, with the initial stack as input.
## If execution fails for any reason, fail.
## If the execution results in anything but exactly one element on the stack which evaluates to true with CastToBool(), fail.
# If this step is reached without encountering a failure, validation succeeds.
===Script execution===
The execution rules for tapscript are based on those for P2WSH according to BIP141, including the OP_CHECKLOCKTIMEVERIFY and OP_CHECKSEQUENCEVERIFY opcodes defined in [[bip-0065.mediawiki|BIP65]] and [[bip-0112.mediawiki|BIP112]], but with the following modifications:
* '''Disabled script opcodes''' The following script opcodes are disabled in tapscript: OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY'''Why are OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY disabled, and not turned into OP_SUCCESSx?''' This is a precaution to make sure people who accidentally keep using OP_CHECKMULTISIG in Tapscript notice a problem immediately. It also avoids the complication of script disassemblers needing to become context-dependent.. The disabled opcodes behave in the same way as OP_RETURN, by failing and terminating the script immediately when executed, and being ignored when found in unexecuted branch of the script.
* '''Consensus-enforced MINIMALIF''' The MINIMALIF rules, which are only a standardness rule in P2WSH, are consensus enforced in tapscript. This means that the input argument to the OP_IF and OP_NOTIF opcodes must be either exactly 0 (the empty vector) or exactly 1 (the one-byte vector with value 1)'''Why make MINIMALIF consensus?''' This makes it considerably easier to write non-malleable scripts that take branch information from the stack..
* '''OP_SUCCESSx opcodes''' As listed above, some opcodes are renamed to OP_SUCCESSx, and make the script unconditionally valid.
* '''Signature opcodes'''. The OP_CHECKSIG and OP_CHECKSIGVERIFY are modified to operate on Schnorr public keys and signatures (see [[bip-0340.mediawiki|BIP340]]) instead of ECDSA, and a new opcode OP_CHECKSIGADD is added.
** The opcode 186 (0xba) is named as OP_CHECKSIGADD. '''OP_CHECKSIGADD''' This opcode is added to compensate for the loss of OP_CHECKMULTISIG-like opcodes, which are incompatible with batch verification. OP_CHECKSIGADD is functionally equivalent to OP_ROT OP_SWAP OP_CHECKSIG OP_ADD, but only takes 1 byte. All CScriptNum-related behaviours of OP_ADD are also applicable to OP_CHECKSIGADD.'''Alternatives to CHECKMULTISIG''' There are multiple ways of implementing a threshold ''k''-of-''n'' policy using Taproot and Tapscript:
* '''Using a single OP_CHECKSIGADD-based script''' A CHECKMULTISIG script m ... n CHECKMULTISIG with witness 0 ... can be rewritten as script CHECKSIG CHECKSIGADD ... CHECKSIGADD m NUMEQUAL with witness ... . Every witness element w_i is either a signature corresponding to pubkey_i or an empty vector. A similar CHECKMULTISIGVERIFY script can be translated to BIP342 by replacing NUMEQUAL with NUMEQUALVERIFY. This approach has very similar characteristics to the existing OP_CHECKMULTISIG-based scripts.
* '''Using a ''k''-of-''k'' script for every combination''' A ''k''-of-''n'' policy can be implemented by splitting the script into several leaves of the Merkle tree, each implementing a ''k''-of-''k'' policy using CHECKSIGVERIFY ... CHECKSIGVERIFY CHECKSIG. This may be preferable for privacy reasons over the previous approach, as it only exposes the participating public keys, but it is only more cost effective for small values of ''k'' (1-of-''n'' for any ''n'', 2-of-''n'' for ''n ≥ 6'', 3-of-''n'' for ''n ≥ 9'', ...). Furthermore, the signatures here commit to the branch used, which means signers need to be aware of which other signers will be participating, or produce signatures for each of the tree leaves.
* '''Using an aggregated public key for every combination''' Instead of building a tree where every leaf consists of ''k'' public keys, it is possible instead build a tree where every leaf contains a single ''aggregate'' of those ''k'' keys using [https://eprint.iacr.org/2018/068 MuSig]. This approach is far more efficient, but does require a 3-round interactive signing protocol to jointly produce the (single) signature.
* '''Native Schnorr threshold signatures''' Multisig policies can also be realized with [http://cacr.uwaterloo.ca/techreports/2001/corr2001-13.ps threshold signatures] using verifiable secret sharing. This results in outputs and inputs that are indistinguishable from single-key payments, but at the cost of needing an interactive protocol (and associated backup procedures) before determining the address to send to.
===Rules for signature opcodes===
The following rules apply to OP_CHECKSIG, OP_CHECKSIGVERIFY, and OP_CHECKSIGADD.
* For OP_CHECKSIGVERIFY and OP_CHECKSIG, the public key (top element) and a signature (second to top element) are popped from the stack.
** If fewer than 2 elements are on the stack, the script MUST fail and terminate immediately.
* For OP_CHECKSIGADD, the public key (top element), a CScriptNumn (second to top element), and a signature (third to top element) are popped from the stack.
** If fewer than 3 elements are on the stack, the script MUST fail and terminate immediately.
** If n is larger than 4 bytes, the script MUST fail and terminate immediately.
* If the public key size is zero, the script MUST fail and terminate immediately.
* If the public key size is 32 bytes, it is considered to be a public key as described in BIP340:
** If the signature is not the empty vector, the signature is validated against the public key (see the next subsection). Validation failure in this case immediately terminates script execution with failure.
* If the public key size is not zero and not 32 bytes, the public key is of an ''unknown public key type'''''Unknown public key types''' allow adding new signature validation rules through softforks. A softfork could add actual signature validation which either passes or makes the script fail and terminate immediately. This way, new SIGHASH modes can be added, as well as [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-December/016549.html NOINPUT-tagged public keys] and a public key constant which is replaced by the taproot internal key for signature validation. and no actual signature verification is applied. During script execution of signature opcodes they behave exactly as known public key types except that signature validation is considered to be successful.
* If the script did not fail and terminate before this step, regardless of the public key type:
** If the signature is the empty vector:
*** For OP_CHECKSIGVERIFY, the script MUST fail and terminate immediately.
*** For OP_CHECKSIG, an empty vector is pushed onto the stack, and execution continues with the next opcode.
*** For OP_CHECKSIGADD, a CScriptNum with value n is pushed onto the stack, and execution continues with the next opcode.
** If the signature is not the empty vector, the opcode is counted towards the sigops budget (see further).
*** For OP_CHECKSIGVERIFY, execution continues without any further changes to the stack.
*** For OP_CHECKSIG, a 1-byte value 0x01 is pushed onto the stack.
*** For OP_CHECKSIGADD, a CScriptNum with value of n + 1 is pushed onto the stack.
===Common Signature Message Extension===
We define the tapscript message extension ''ext'' to [[bip-0341.mediawiki#common-signature-message|BIP341 Common Signature Message]], indicated by ''ext_flag = 1'':
* ''tapleaf_hash'' (32): the tapleaf hash as defined in [[bip-0341.mediawiki#design|BIP341]]
* ''key_version'' (1): a constant value ''0x00'' representing the current version of public keys in the tapscript signature opcode execution.
* ''codesep_pos'' (4): the opcode position of the last executed OP_CODESEPARATOR before the currently executed signature opcode, with the value in little endian (or ''0xffffffff'' if none executed). The first opcode in a script has a position of 0. A multi-byte push opcode is counted as one opcode, regardless of the size of data being pushed. Opcodes in parsed but unexecuted branches count towards this value as well.
===Signature validation===
To validate a signature ''sig'' with public key ''p'':
* Compute the tapscript message extension ''ext'' described above.
* If the ''sig'' is 64 bytes long, return ''Verify(p, hashTapSighash(0x00 || SigMsg(0x00, 1) || ext), sig)'', where ''Verify'' is defined in [[bip-0340.mediawiki#design|BIP340]].
* If the ''sig'' is 65 bytes long, return ''sig[64] ≠ 0x00 and Verify(p, hashTapSighash(0x00 || SigMsg(sig[64], 1) || ext), sig[0:64])''.
* Otherwise, fail.
In summary, the semantics of signature validation is identical to BIP340, except the following:
# The signature message includes the tapscript-specific data ''key_version''.'''Why does the signature message commit to the ''key_version''?''' This is for future extensions that define unknown public key types, making sure signatures can't be moved from one key type to another.
# The signature message commits to the executed script through the ''tapleaf_hash'' which includes the leaf version and script instead of ''scriptCode''. This implies that this commitment is unaffected by OP_CODESEPARATOR.
# The signature message includes the opcode position of the last executed OP_CODESEPARATOR.'''Why does the signature message include the position of the last executed OP_CODESEPARATOR?''' This allows continuing to use OP_CODESEPARATOR to sign the executed path of the script. Because the codeseparator_position is the last input to the hash, the SHA256 midstate can be efficiently cached for multiple OP_CODESEPARATORs in a single script. In contrast, the BIP143 handling of OP_CODESEPARATOR is to commit to the executed script only from the last executed OP_CODESEPARATOR onwards which requires unnecessary rehashing of the script. It should be noted that the one known OP_CODESEPARATOR use case of saving a second public key push in a script by sharing the first one between two code branches can be most likely expressed even cheaper by moving each branch into a separate taproot leaf.
===Resource limits===
In addition to changing the semantics of a number of opcodes, there are also some changes to the resource limitations:
* '''Script size limit''' The maximum script size of 10000 bytes does not apply. Their size is only implicitly bounded by the block weight limit.'''Why is a limit on script size no longer needed?''' Since there is no scriptCode directly included in the signature hash (only indirectly through a precomputable tapleaf hash), the CPU time spent on a signature check is no longer proportional to the size of the script being executed.
* '''Non-push opcodes limit''' The maximum non-push opcodes limit of 201 per script does not apply.'''Why is a limit on the number of opcodes no longer needed?''' An opcode limit only helps to the extent that it can prevent data structures from growing unboundedly during execution (both because of memory usage, and because of time that may grow in proportion to the size of those structures). The size of stack and altstack is already independently limited. By using O(1) logic for OP_IF, OP_NOTIF, OP_ELSE, and OP_ENDIF as suggested [https://bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts/ here] and implemented [https://github.com/bitcoin/bitcoin/pull/16902 here], the only other instance can be avoided as well.
* '''Sigops limit''' The sigops in tapscripts do not count towards the block-wide limit of 80000 (weighted). Instead, there is a per-script sigops ''budget''. The budget equals 50 + the total serialized size in bytes of the transaction input's witness (including the CompactSize prefix). Executing a signature opcode (OP_CHECKSIG, OP_CHECKSIGVERIFY, or OP_CHECKSIGADD) with a non-empty signature decrements the budget by 50. If that brings the budget below zero, the script fails immediately. Signature opcodes with unknown public key type and non-empty signature are also counted.'''The tapscript sigop limit''' The signature opcode limit protects against scripts which are slow to verify due to excessively many signature operations. In tapscript the number of signature opcodes does not count towards the BIP141 or legacy sigop limit. The old sigop limit makes transaction selection in block construction unnecessarily difficult because it is a second constraint in addition to weight. Instead, the number of tapscript signature opcodes is limited by witness weight. Additionally, the limit applies to the transaction input instead of the block and only actually executed signature opcodes are counted. Tapscript execution allows one signature opcode per 50 witness weight units plus one free signature opcode.'''Parameter choice of the sigop limit''' Regular witnesses are unaffected by the limit as their weight is composed of public key and (SIGHASH_ALL) signature pairs with ''33 + 65'' weight units each (which includes a 1 weight unit CompactSize tag). This is also the case if public keys are reused in the script because a signature's weight alone is 65 or 66 weight units. However, the limit increases the fees of abnormal scripts with duplicate signatures (and public keys) by requiring additional weight. The weight per sigop factor 50 corresponds to the ratio of BIP141 block limits: 4 mega weight units divided by 80,000 sigops. The "free" signature opcode permitted by the limit exists to account for the weight of the non-witness parts of the transaction input.'''Why are only signature opcodes counted toward the budget, and not for example hashing opcodes or other expensive operations?''' It turns out that the CPU cost per witness byte for verification of a script consisting of the maximum density of signature checking opcodes (taking the 50 WU/sigop limit into account) is already very close to that of scripts packed with other opcodes, including hashing opcodes (taking the 520 byte stack element limit into account) and OP_ROLL (taking the 1000 stack element limit into account). That said, the construction is very flexible, and allows adding new signature opcodes like CHECKSIGFROMSTACK to count towards the limit through a soft fork. Even if in the future new opcodes are introduced which change normal script cost there is no need to stuff the witness with meaningless data. Instead, the taproot annex can be used to add weight to the witness without increasing the actual witness size..
* '''Stack + altstack element count limit''' The existing limit of 1000 elements in the stack and altstack together after every executed opcode remains. It is extended to also apply to the size of initial stack.
* '''Stack element size limit''' The existing limit of maximum 520 bytes per stack element remains, both in the initial stack and in push opcodes.
==Rationale==
==Deployment==
This proposal is deployed identically to Taproot ([[bip-0341.mediawiki|BIP341]]).
==Examples==
The Taproot ([[bip-0341.mediawiki|BIP341]]) test vectors also contain examples for Tapscript execution.
==Acknowledgements==
This document is the result of many discussions and contains contributions by a number of people. The authors wish to thank all those who provided valuable feedback and reviews, including the participants of the [https://github.com/ajtowns/taproot-review structured reviews].
================================================
FILE: bip-0343.mediawiki
================================================
BIP: 343
Layer: Consensus (soft fork)
Title: Mandatory activation of taproot deployment
Authors: Shinobius
Michael Folkson
Status: Deployed
Type: Specification
Assigned: 2021-04-25
License: BSD-3-Clause OR CC0-1.0
==Abstract==
This document specifies a BIP8 (LOT=true) deployment to activate taproot.
==Motivation==
The Taproot soft fork upgrade has been assessed to have overwhelming community consensus and hence should attempt to be activated. Lessons have been learned from the BIP148 and BIP91 deployments in 2017 with regards to giving many months of advance warning before the mandatory signaling is attempted. The mandatory signaling is only required if miners have failed to meet the signaling threshold during the BIP8 deployment. It is important that mandatory signaling is included as without it miners would effectively have the ability to indefinitely block the activation of a soft fork with overwhelming consensus.
==Specification==
This BIP will begin an activation signaling period using bit 2 at blockheight 681408 with a minimum activation height of 709632 and an activation threshold of 90%. The signaling period will timeout at blockheight 760032 with a latest activation height of 762048. Lockinontimeout (LOT) is set to true so mandatory signaling will be enforced in the last signaling period before the timeout height. Blocks without the signaling bit 2 set run the risk of being rejected during this period if taproot is not locked in prior. This BIP will cease to be active when taproot is locked in.
==Reference implementation==
*[[https://github.com/BitcoinActivation/bitcoin]]
==Backward Compatibility==
As a soft fork, older software will continue to operate without modification. Non-upgraded nodes, however, will consider all SegWit version 1 witness programs as anyone-can-spend scripts. They are strongly encouraged to upgrade in order to fully validate the new programs.
==Compatibility with later alternative activations==
The activation mechanism “Speedy Trial” as proposed by Russell O’Connor and outlined in this bitcoin-dev mailing list [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-March/018583.html post] by David Harding was released in Bitcoin Core. It is effectively a BIP8 activation mechanism with one exception: start height and timeout height were defined using median time past (MTP) rather than block heights. It uses signaling bit 2, was deployed between midnight April 24th 2021 and midnight August 11th 2021, has a minimum activation height of 709632 and intends to activate BIPs 340, 341, and 342. The BIP8(LOT=true) deployment is compatible with the “Speedy Trial” deployment in Bitcoin Core as there was not a discrepancy between MTP and block height for the defined start heights.
The BIP8 (LOT=true) deployment has also been deliberately designed to be compatible with a future BIP8(LOT=false) or BIP8(LOT=true) deployment in Bitcoin Core assuming Bitcoin Core releases one of these activation mechanisms in the event of the Speedy Trial deployment failing to activate.
==Rationale==
The deployment of BIP148 demonstrated that multiple implementations with different activation mechanisms can incentivize the necessary actors to act so that the different deployments activate in sync. A BIP8 LOT=true deployment can run in parallel with other BIP8 activation mechanisms that have eventual mandatory signaling or no mandatory signaling. Eventual mandatory signaling ensures that miners cannot prevent the activation of a desired feature with community consensus indefinitely.
==Acknowledgements==
Thanks to Shaolin Fry and Luke Dashjr for their work on BIP148 and BIP8 which were important prerequisites for this proposal.
==References==
*[[bip-0008.mediawiki|BIP8 Version bits with lock-in by height]]
*[[bip-0148.mediawiki|BIP148 Mandatory activation of segwit deployment]]
*[[bip-0340.mediawiki|BIP340 Schnorr Signatures for secp256k1]]
*[[bip-0341.mediawiki|BIP341 Taproot: SegWit version 1 spending rules]]
*[[bip-0342.mediawiki|BIP342 Validation of Taproot Scripts]]
*[https://taproot.works/taproot-faq/ Taproot benefits]
==Copyright==
This document is dual licensed as BSD 3-clause, and Creative Commons CC0 1.0 Universal.
================================================
FILE: bip-0345/vaults.drawio
================================================
================================================
FILE: bip-0345.mediawiki
================================================
== Introduction ==
This BIP proposes two new tapscript opcodes that add consensus support for a specialized
covenant: OP_VAULT and OP_VAULT_RECOVER. These opcodes, in conjunction with
OP_CHECKTEMPLATEVERIFY
([https://github.com/bitcoin/bips/blob/master/bip-0119.mediawiki BIP-0119]),
allow users to enforce a delay period before designated coins may be spent to
an arbitrary destination, with the exception of a prespecified "recovery" path.
At any time prior to final withdrawal, the coins can be spent to the
recovery path.
=== Copyright ===
This document is licensed under the 3-clause BSD license.
=== Motivation ===
The hazard of custodying Bitcoin is well-known. Users of Bitcoin must go to
significant effort to secure their private keys, and hope that once provisioned
their custody system does not yield to any number of evolving and
persistent threats. Users have little means to intervene once a compromise is
detected. This proposal introduces a mechanism that significantly
mitigates the worst-case outcome of key compromise: coin loss.
Introducing a way to intervene during unexpected spends allows users to
incorporate highly secure key storage methods or unusual fallback strategies
that are only exercised in the worst case, and which may otherwise be
operationally prohibitive. The goal of this proposal is to make this strategy
usable for custodians of any size with minimal complication.
==== Example uses ====
A common configuration for an individual custodying Bitcoin is "single
signature and passphrase" using a hardware wallet. A user with such a
configuration might be concerned about the risk associated with relying on a
single manufacturer for key management, as well as physical access to the
hardware.
This individual can use OP_VAULT to make use of a highly secure
key as the unlikely recovery path, while using their existing signing procedure
as the withdrawal trigger key with a configured spend delay of e.g. 1 day.
The recovery path key can be of a highly secure nature that might otherwise
make it impractical for daily use. For example, the key could be generated in
some analog fashion, or on an old computer that is then destroyed, with the
private key replicated only in paper form. Or the key could be a 2-of-3
multisig using devices from different manufacturers. Perhaps the key is
geographically or socially distributed.
Since it can be any Bitcoin script policy, the recovery key can include a
number of spending conditions, e.g. a time-delayed fallback to an "easier"
recovery method, in case the highly secure key winds up being ''too'' highly
secure.
The user can run software on their mobile device that monitors the blockchain
for spends of the vault outpoints. If the vaulted coins move in an unexpected
way, the user can immediately sweep them to the recovery path, but spending the
coins on a daily basis works in the same way it did prior to vaulting (aside
from the spend delay).
Institutional custodians of Bitcoin may use vaults in similar fashion.
===== Provable timelocks =====
This proposal provides a mitigation to the
[https://web.archive.org/web/20230210123933/https://xkcd.com/538/ "$5 wrench attack."] By
setting the spend delay to, say, a week, and using as the recovery path a
script that enforces a longer relative timelock, the owner of the vault can
prove that he is unable to access its value immediately. To the author's
knowledge, this is the only way to configure this defense without rolling
timelocked coins for perpetuity or relying on a trusted third party.
== Goals ==
[[File:bip-0345/vaults-Basic.png|frame|center]]
Vaults in Bitcoin have been discussed formally since 2016
([https://crypto.news/app/uploads/2016/08/MES16.pdf MES16]) and informally since [https://web.archive.org/web/20160220215151/https://bitcointalk.org/index.php?topic=511881.0 2014]. The value of
having a configurable delay period with recovery capability in light of an
unexpected spend has been widely recognized.
The only way to implement vaults given the existing consensus rules, aside from
[https://github.com/revault emulating vaults with large multisig
configurations], is to use presigned transactions created with a one-time-use
key. This approach was first demonstrated
[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-April/017755.html in 2020].
Unfortunately, this approach has a number of practical shortcomings:
* generating and securely deleting ephemeral keys, which are used to emulate the vault covenant, is required,
* amounts and withdrawal patterns must be precommitted to,
* there is a necessity to precommit to an address that the funds must pass through on their way to the final withdrawal target, which is likely only known at unvault time,
* the particular fee management technique or wallet must be decided upon vault creation,
* coin loss follows if a vault address is reused,
* the transaction data that represents the "bearer asset" of the vault must be stored for perpetuity, otherwise value is lost, and
* the vault creation ceremony must be performed each time a new balance is to be deposited.
The deployment of a "precomputed" covenant mechanism like
[https://github.com/bitcoin/bips/blob/master/bip-0119.mediawiki OP_CHECKTEMPLATEVERIFY] or
[https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki SIGHASH_ANYPREVOUT]
would both remove the necessity to use an ephemeral key, since the
covenant is enforced on-chain, and lessen the burden of sensitive data storage,
since the necessary transactions can be generated from a set of compact
parameters. This approach was demonstrated [https://github.com/jamesob/simple-ctv-vault in
2022].
However, the limitations of precomputation still apply: amounts,
destinations, and fee management are all fixed. Funds must flow through a fixed
intermediary to their final destination. Batch operations, which may be vital
for successful recovery during fee spikes or short spend delay, are not possible.
[[File:bip-0345/withdrawal-comparison.drawio.png|frame|center]]
Having a "general" covenant mechanism that can encode arbitrary transactional
state machines would allow us to solve these issues, but at the cost of complex
and large scripts that would probably be duplicated many times over in the
blockchain. The particular design and deployment timeline of such a general
framework is also uncertain. This approach was demonstrated
[https://blog.blockstream.com/en-covenants-in-elements-alpha/ in 2016].
This proposal intends to address the problems outlined above by
providing a delay period/recovery path use with minimal transactional and
operational overhead using a specialized covenant.
The design goals of the proposal are:
* '''efficient reuse of an existing vault configuration.''''''Why does this support address reuse?''' The proposal doesn't rely on or encourage address reuse, but certain uses are unsafe if address reuse cannot be handled - for example, if a custodian gives its users a vault address to deposit to, it cannot enforce that those users make a single deposit for each address. A single vault configuration, whether the same literal scriptPubKey or not, should be able to “receive” multiple deposits.
* '''batched operations''' for recovery and withdrawal to allow managing multiple vault coins efficiently.
* '''unbounded partial withdrawals''', which allows users to withdraw partial vault balances without having to perform the setup ceremony for a new vault.
* '''dynamic unvault targets''', which allow the proposed withdrawal target for a vault to be specified at withdrawal time rather than when the vault is first created. This would remove the need for a prespecified, intermediate wallet that only exists to route unvaulted funds to their desired destination.
* '''dynamic fee management''' that, like dynamic targets, defers the specification of fee rates and source to unvault time rather than vault creation time.
These goals are accompanied by basic safety considerations (e.g. not being
vulnerable to mempool pinning) and a desire for concision, both in terms of the number
of outputs created as well as script sizes.
This proposal is designed to be compatible with any future sighash modes (e.g. SIGHASH_GROUP) or fee management strategies (e.g. [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-September/018168.html transaction sponsors]) that may be introduced. Use of these opcodes will benefit from, but do not strictly rely on, [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-September/020937.html v3 transaction relay] and [https://github.com/instagibbs/bips/blob/527b007dbf5b9a89895017030183370e05468ae6/bip-ephemeralanchors.mediawiki ephemeral anchors].
== Design ==
In typical usage, a vault is created by encumbering coins under a
taptree [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki (BIP-341)]
containing at least two leaves: one with an OP_VAULT-containing script that
facilitates the expected withdrawal process, and another leaf with
OP_VAULT_RECOVER which ensures the coins can be recovered
at any time prior to withdrawal finalization.
The rules of OP_VAULT ensure the timelocked, interruptible
withdrawal by allowing a spending transaction to replace the
OP_VAULT tapleaf with a prespecified script template, allowing for
some parameters to be set at spend (trigger) time. All other leaves in the
taptree must be unchanged in the destination output, which preserves the recovery path as well as any
other spending conditions originally included in the vault. This is similar to
the TAPLEAF_UPDATE_VERIFY design that was proposed
[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-September/019419.html in 2021].
These tapleaf replacement rules, described more precisely below, ensure a
timelocked withdrawal, where the timelock is fixed by the original
OP_VAULT parameters, to a fixed set of outputs (via
OP_CHECKTEMPLATEVERIFY'''Why is OP_CHECKTEMPLATEVERIFY (BIP-119) relied upon for this proposal?''' During the withdrawal process, the proposed final destination for value being withdrawn must be committed to. OP_CTV is the simplest, safest way to commit the spend of some coins to a particular set of outputs. An earlier version of this proposal attempted to use a simpler, but similar method, of locking the spend of coins to a set of outputs, but this method introduced txid malleability. Note that if some other method of locking spends to a particular set of outputs should be deployed, that method can be used in the OP_VAULT with no changes.) which is chosen when the withdrawal
process is triggered.
While OP_CHECKTEMPLATEVERIFY is used in this proposal as the
preferred method to bind the proposed withdrawal to a particular set of final
outputs, OP_VAULT is composable with other (and future) opcodes to
facilitate other kinds of withdrawal processes.
[[File:bip-0345/opvault.drawio.png|frame|center]]
=== Transaction types ===
The vault has a number of stages, some of them optional:
* '''vault transaction''': encumbers some coins into a Taproot structure that includes at least one OP_VAULT leaf and one OP_VAULT_RECOVER leaf.
* '''trigger transaction''': spends one or more OP_VAULT-tapleaf inputs into an output which is encumbered by a timelocked withdrawal to a fixed set of outputs, chosen at trigger time. This publicly broadcasts the intent to withdraw to some specific set of outputs.
The trigger transaction may have an additional output which allocates some of the vault balance into a partial "revault," which simply encumbers the revaulted portion of the value into the same scriptPubKey as the OP_VAULT-containing input(s) being spent.
* '''withdrawal transaction''': spends the timelocked, destination-locked trigger inputs into a compatible set of final withdrawal outputs (per, e.g., a CHECKTEMPLATEVERIFY hash), after the trigger inputs have matured per the spend delay. Timelocked CTV transactions are the motivating usage of OP_VAULT, but any script template can be specified during the creation of the vault.
* '''recovery transaction''': spends one or more vault inputs via OP_VAULT_RECOVER tapleaf to the prespecified recovery path, which can be done at any point before the withdrawal transaction confirms. Each input can optionally require a witness satisfying a specified ''recovery authorization'' script, an optional script prefixing the OP_VAULT_RECOVER fragment. The use of recovery authorization has certain trade-offs discussed later.
=== Fee management ===
A primary consideration of this proposal is how fee management is handled.
Providing dynamic fee management is critical to the operation of a vault, since
* precalculated fees are prone to making transactions unconfirmable in high fee environments, and
* a fee wallet that is prespecified might be compromised or lost before use.
But dynamic fee management can introduce
[https://bitcoinops.org/en/topics/transaction-pinning/ pinning vectors]. Care
has been taken to avoid unnecessarily introducing these vectors when using the new
destination-based spending policies that this proposal introduces.
Originally, this proposal had a hard dependency on reformed transaction
nVersion=3 policies, including ephemeral anchors, but it has since been revised
to simply benefit from these changes in policy as well as other potential fee
management mechanisms.
== Specification ==
The tapscript opcodes OP_SUCCESS187 (0xbb) and
OP_SUCCESS188 (0xbc) are constrained with new rules
to implement OP_VAULT and OP_VAULT_RECOVER,
respectively.
=== OP_VAULT evaluation ===
When evaluating OP_VAULT (OP_SUCCESS187,
0xbb), the expected format of the stack, shown top to bottom, is:
[ leaf-update script data items ... ]
where
* is a minimally-encoded data push of a serialized script. In conjunction with the leaf-update data items, it dictates the tapleaf script in the output taptree that will replace the one currently executing.
** Otherwise, script execution MUST fail and terminate immediately.
* is an up to 4-byte minimally encoded CScriptNum indicating how many leaf-update script items should be popped off the stack. '''Why only prefix with data pushes?''' Prefixing the leaf-update-script-body with opcodes opens up the door to prefix OP_SUCCESSX opcodes, to name a single issue only, side-stepping the validation that was meant to be run by the committed script.
** If this value does not decode to a valid CScriptNum, script execution MUST fail and terminate immediately.
** If this value is less than 0, script execution MUST fail and terminate immediately.
** If there are fewer than 3 items following the items on the stack, script execution MUST fail and terminate immediately. In other words, after popping , there must be at least 3 + items remaining on the stack.
* The following stack items are popped off the stack and prefixed as minimally-encoded push-data arguments to the to construct the expected tapleaf replacement script.
* is an up to 4-byte minimally encoded CScriptNum indicating the index of the output which, in conjunction with an optional revault output, carries forward the value of this input, and has an identical taptree aside from the currently executing leaf.
** If this value does not decode to a valid CScriptNum, script execution MUST fail and terminate immediately.
** If this value is less than 0 or is greater than or equal to the number of outputs, script execution MUST fail and terminate immediately.
* is an up to 4-byte minimally encoded CScriptNum optionally indicating the index of an output which, in conjunction with the trigger output, carries forward the value of this input, and has an identical scriptPubKey to the current input.
** If this value does not decode to a valid CScriptNum, script execution MUST fail and terminate immediately.
** If this value is greater than or equal to the number of outputs, script execution MUST fail and terminate immediately.
** If this value is negative and not equal to -1, script execution MUST fail and terminate immediately.'''Why is -1 the only allowable negative value for revault-vout-idx?''' A negative revault index indicates that no revault output exists; if this value were allowed to be any negative number, the witness could be malleated (and bloated) while a transaction is waiting for confirmation.
* is an up to 7-byte minimally encoded CScriptNum indicating the number of satoshis being revaulted.
** If this value does not decode to a valid CScriptNum, script execution MUST fail and terminate immediately.
** If this value is not greater than or equal to 0, script execution MUST fail and terminate immediately.
** If this value is non-zero but is negative, script execution MUST fail and terminate immediately.
** If this value is zero but is not -1, script execution MUST fail and terminate immediately.
After the stack is parsed, the following validation checks are performed:
* Decrement the per-script sigops budget (see [https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#user-content-Resource_limits BIP-0342]) by 60'''Why is the sigops cost for OP_VAULT set to 60?''' To determine the validity of a trigger output, OP_VAULT must perform an EC multiplication and hashing proportional to the length of the control block in order to generate the output's expected TapTweak. This has been measured to have a cost in the worst case (max length control block) of roughly twice a Schnorr verification. Because the hashing cost could be mitigated by caching midstate, the cost is 60 and not 100.; if the budget is brought below zero, script execution MUST fail and terminate immediately.
* Let the output designated by be called ''triggerOut''.
* If the scriptPubKey of ''triggerOut'' is not a version 1 witness program, script execution MUST fail and terminate immediately.
* Let the script constructed by taking the and prefixing it with minimally-encoded data pushes of the leaf-update script data items be called the ''leaf-update-script''.
* If the scriptPubKey of ''triggerOut'' does not match that of a taptree that is identical to that of the currently evaluated input, but with the leaf script substituted for ''leaf-update-script'', script execution MUST fail and terminate immediately.
** Note: the parity bit of the resulting taproot output is allowed to vary, so both values for the new output must be checked.
* Let the output designated by (if the index value is non-negative) be called ''revaultOut''.
* If the scriptPubKey of ''revaultOut'' is not equal to the scriptPubKey of the input being spent, script execution MUST fail and terminate immediately.
* Implementation recommendation: if the sum of the amounts of ''triggerOut'' and ''revaultOut'' (if any) are not greater than or equal to the value of this input, script execution SHOULD fail and terminate immediately. This ensures that (at a minimum) the vaulted value for this input is carried through.
** Amount checks are ultimately done with deferred checks, but this check can help short-circuit obviously invalid spends.
* Queue a deferred check'''What is a deferred check and why does this proposal require them for correct script evaluation?''' A deferred check is a validation check that is executed only after all input scripts have been validated, and is based on aggregate information collected during each input's EvalScript run.
Currently, the validity of each input is (usually) checked concurrently across all inputs in a transaction. Because this proposal allows batching the spend of multiple vault inputs into a single recovery or withdrawal output, we need a mechanism to ensure that all expected values per output can be summed and then checked. This necessitates the introduction of an "aggregating" set of checks which can only be executed after each input's script is evaluated. Note that similar functionality would be required for batch input validation or cross-input signature aggregation. that ensures the satoshis for this input's nValue minus are included within the output nValue found at .
* Queue a deferred check that ensures satoshis, if non-zero, are included within the output's nValue found at .
** These deferred checks could be characterized in terms of the pseudocode below (in ''Deferred checks'') as TriggerCheck(input_amount, , , ).
If none of the conditions fail, a single true value (0x01) is left on the stack.
=== OP_VAULT_RECOVER evaluation ===
When evaluating OP_VAULT_RECOVER (OP_SUCCESS188,
0xbc), the expected format of the stack, shown top to bottom, is:
where
* is a 32-byte data push.
** If this is not 32 bytes in length, script execution MUST fail and terminate immediately.
* is an up to 4-byte minimally encoded CScriptNum indicating the index of the recovery output.
** If this value does not decode to a valid CScriptNum, script execution MUST fail and terminate immediately.
** If this value is less than 0 or is greater than or equal to the number of outputs, script execution MUST fail and terminate immediately.
After the stack is parsed, the following validation checks are performed:
* Let the output at index be called ''recoveryOut''.
* Compute the scriptPubKey tagged hash for ''recoveryOut'' as output-sPK-hash = tagged_hash("VaultRecoverySPK", CompactSize(len(recoveryOut.scriptPubKey)) || recoveryOut.scriptPubKey), where tagged_hash() is from the [https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py BIP-0340 reference code].
* If the ''recoveryOut'' output-sPK-hash is not equal to , script execution MUST fail and terminate immediately.
** Implementation recommendation: if ''recoveryOut'' does not have an nValue greater than or equal to this input's amount, the script SHOULD fail and terminate immediately.
* Queue a deferred check that ensures the nValue of ''recoveryOut'' contains the entire nValue of this input.'''How do recovery transactions pay for fees?''' If the recovery is unauthorized, fees are attached either via CPFP with an ephemeral anchor or as inputs which are solely spent to fees (i.e. no change output). If the recovery is authorized, fees can be attached in any manner, e.g. unrelated inputs and outputs or CPFP via anchor.
** This deferred check could be characterized in terms of the pseudocode below as RecoveryCheck(, input_amount).
If none of the conditions fail, a single true value (0x01) is left on the stack.
=== Deferred check evaluation ===
Once all inputs for a transaction are validated per the rules above, any
deferred checks queued MUST be evaluated.
The Python pseudocode for this is as follows:
class TriggerCheck:
"""Queued by evaluation of OP_VAULT (withdrawal trigger)."""
input_amount: int
revault_amount: int
trigger_vout_idx: int
revault_vout_idx: int
class RecoveryCheck:
"""Queued by evaluation of OP_VAULT_RECOVER."""
input_amount: int
vout_idx: int
def validate_deferred_checks(checks: [DeferredCheck], tx: Transaction) -> bool:
"""
Ensure that all value from vault inputs being triggered or recovered is preserved
in suitable output nValues.
"""
# Map to hold expected output values.
out_map: Dict[int, int] = defaultdict(lambda: 0)
for c in checks:
if isinstance(c, TriggerCheck):
out_map[c.trigger_vout_idx] += (c.input_amount - c.revault_amount)
if c.revault_amount > 0:
out_map[c.revault_vout_idx] += c.revault_amount
elif isinstance(c, RecoveryCheck):
out_map[c.vout_idx] += c.input_amount
for (vout_idx, amount_sats) in out_map.items():
# Trigger/recovery value can be greater than the constituent vault input
# amounts.
if tx.vout[vout_idx].nValue < amount_sats:
return False
return True
If the above procedure, or an equivalent, returns false, script execution MUST fail and terminate
immediately.
This ensures that all compatible vault inputs can be batched into shared
corresponding trigger or recovery outputs while preserving their entire input value.
== Policy changes ==
In order to prevent possible pinning attacks, recovery transactions must be replaceable.
* When validating an OP_VAULT_RECOVER input being spent, the script MUST fail (by policy, not consensus) and terminate immediately if both'''Why are recovery transactions required to be replaceable?''' In the case of unauthorized recoveries, an attacker may attempt to pin recovery transactions by broadcasting a "rebundled" version with a low fee rate. Vault owners must be able to overcome this with replacement. In the case of authorized recovery, if an attacker steals the recovery authorization key, the attacker may try to pin the recovery transaction during theft. Requiring replaceability ensures that the owner can always raise the fee rate of the recovery transaction, even if they are RBF rule #3 griefed in the process.
*# the input is not marked as opt-in replaceable by having an nSequence number less than 0xffffffff - 1, per [https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki BIP-0125], and
*# the version of the recovery transaction has an nVersion other than 3.
If the script containing OP_VAULT_RECOVER is 34 bytes or less34 bytes is the length of a recovery script that consists solely of OP_VAULT_RECOVER., let
it be called "unauthorized," because there is no script guarding the recovery
process. In order to prevent pinning attacks in the case of unauthorized
recovery - since the spend of the input (and the structure of the
transaction) is not authorized by a signed signature message - the output structure of
unauthorized recovery transaction is limited.
* If the recovery is unauthorized, the recovery transaction MUST (by policy) abide by the following constraints:
** If the spending transaction has more than two outputs, the script MUST fail and terminate immediately.
** If the spending transaction has two outputs, and the output which is not ''recoveryOut'' is not an [https://github.com/instagibbs/bips/blob/527b007dbf5b9a89895017030183370e05468ae6/bip-ephemeralanchors.mediawiki ephemeral anchor], the script MUST fail and terminate immediately.'''Why can unauthorized recoveries only process a single recovery path?''' Because there is no signature required for unauthorized recoveries, if additional outputs were allowed, someone observing a recovery in the mempool would be able to rebundle and broadcast the recovery with a lower fee rate.
== Implementation ==
A sample implementation is available on bitcoin-inquisition [https://github.com/jamesob/bitcoin/tree/2023-02-opvault-inq here], with an associated [https://github.com/bitcoin-inquisition/bitcoin/pull/21 pull request].
== Applications ==
The specification above, perhaps surprisingly, does not specifically cover how a relative timelocked withdrawal process with a fixed target is implemented. The tapleaf update semantics specified in OP_VAULT as well as the output-based authorization enabled by OP_VAULT_RECOVER can be used to implement a vault, but they are incomplete without two other pieces:
* a way to enforce relative timelocks, like OP_CHECKSEQUENCEVERIFY, and
* a way to enforce that proposed withdrawals are ultimately being spent to a precise set of outputs, like OP_CHECKTEMPLATEVERIFY.
These two pieces are combined with the tapleaf update capabilities of
OP_VAULT to create a vault, described below.
=== Creating a vault ===
In order to vault coins, they can be spent into a witness v1 scriptPubKey
that contains a taptree of the form
tr(,
leaves = {
recover:
OP_VAULT_RECOVER,
trigger:
OP_CHECKSIGVERIFY (i)
2 $leaf-update-script-body OP_VAULT, (ii)
... [ possibly other leaves ]
}
)
where
* $leaf-update-script-body is, for example, OP_CHECKSEQUENCEVERIFY OP_DROP OP_CHECKTEMPLATEVERIFY.
** This is one example of a trigger script, but ''any'' script fragment can be used, allowing the creation of different types of vaults. For example, you could use OP_CHECKSEQUENCEVERIFY OP_DROP OP_CHECKSIG to do a time-delayed transfer of the coins to another key. This also future-proofs OP_VAULT for future scripting capabilities.
* The script fragment in (i) is called the "trigger authorization," because it gates triggering the withdrawal. This can be done in whatever manner the wallet designer would like.
* The script fragment in (ii) is the incomplete OP_VAULT invocation - it will be completed once the rest of the parameters (the CTV target hash, trigger vout index, and revault vout index) are provided by the trigger transaction witness.
Typically, the internal key for the vault taproot output will be specified so
that it is controlled by the same descriptor as the recovery path, which
facilitates another (though probably unused) means of recovering the vault
output to the recovery path. This has the potential advantage of recovering the
coin without ever revealing it was a vault.
Otherwise, the internal key can be chosen to be an unspendable NUMS point to
force execution of the taptree contents.
=== Triggering a withdrawal ===
To make use of the vault, and spend it towards some output, we construct a spend
of the above tr() output that simply replaces the "trigger" leaf with the
full leaf-update script (in this case, a timelocked CTV script):
Witness stack:
-
- (-1 if none)
-
-
-
- [ "trigger" leaf script contents ]
- [ taproot control block prompting a script-path spend to "trigger" leaf ]
Output scripts:
[
tr(,
leaves = {
recover:
OP_VAULT_RECOVER, <-- unchanged
trigger:
OP_CHECKSEQUENCEVERIFY OP_DROP OP_CHECKTEMPLATEVERIFY <-- changed per the
leaf-update
rules of OP_VAULT
... [ possibly other leaves ]
}
),
[ optional revault output with the
same sPK as the original vault output ],
]
OP_VAULT has allowed the taptree to be transformed so that the trigger leaf
becomes a timelocked CTV script, which is what actually facilitates the announced
withdrawal. The withdrawal is interruptible by the recovery path because the
"recover" leaf is preserved exactly from the original taptree.
Note that the CTV hash is specified at spend time using the witness stack, and
"locked in" via the OP_VAULT spend rules which assert its existence in the output.
The vault funds can be recovered at any time prior to the spend of the
timelocked CTV script by way of a script-path spend using the "recover" leaf.
=== Recovery authorization ===
When configuring a vault, the user must decide if they want to have the
recovery process gated by a script fragment prefixing the
OP_VAULT_RECOVER instruction in the "recover" leaf. Its use
entails trade-offs.
==== Unauthorized recovery ====
Unauthorized recovery simplifies vault use in that recovery never requires additional information aside from the location of the vault outpoints and the recovery path - the "authorization" is simply the reveal of the recovery path, i.e. the preimage of .
But because this reveal is the only authorization necessary to spend the vault coins to recovery, the user must expect to recover all such vaults at once, since an observer can replay this recovery (provided they know the outpoints).
Additionally, unauthorized recovery across multiple distinct recovery paths
cannot be done in the same transaction, and fee control is more constrained:
because the output structure is limited for unauthorized recovery, fee
management relies either on inputs which are completely spent to fees or the
use of the optional ephemeral anchor and package relay.
These limitations are to avoid pinning attacks.
==== Authorized recovery ====
With authorized recovery, the user must keep track of an additional piece of information: how to solve the recovery authorization script fragment when recovery is required.
If this key is lost, the user will be unable to initiate the recovery process for their coins. If an attacker obtains the recovery key, they may grief the user during the recovery process by constructing a low fee rate recovery transaction and broadcasting it (though they will not be able to pin because of the replaceability requirement on recovery transactions).
However, authorized recovery configurations have significant benefits. Batched recoveries are possible for vaults with otherwise incompatible recovery parameters. Fee management is much more flexible, since authorized recovery transactions are "free form" and unrelated inputs and outputs can be added, potentially to handle fees.
==== Recommendation: use a simple, offline recovery authorization key seed ====
The benefits of batching and fee management that authorized recovery provides are significant. If the recovery authorization key falls into the hands of an attacker, the outcome is not catastrophic, whereas if the user loses their recovery authorization key as well as their trigger key, the result is likely coin loss. Consequently, the author's recommendation is to use a simple seed for the recovery authorization key that can be written down offline and replicated.
Note that the recovery authorization key '''is not''' the recovery path key, and
this is '''much different''' than any recommendation on how to generate the
recovery path key itself.
=== Address reuse and recovery ===
When creating a vault, four factors affect the resulting P2TR address:
# The internal pubkey (likely belonging to the recovery wallet)
# The recovery leaf
# The trigger leaf
# Any other leaves that exist in the taptree
The end user has the option of varying certain contents along descriptors in
order to avoid reusing vault addresses without affecting key management, e.g.
the trigger authorization pubkeys.
Note that when using unauthorized recovery, the reveal of the
recovery scriptPubKey will allow any observer to initiate the recovery process
for any vault with matching recovery params, provided they are able to locate
the vault outpoints. As a result, it is recommended to expect that
'''all outputs sharing an identical unauthorized should be recovered together'''.
This situation can be avoided with a comparable key management model by varying
the generation of each vault's recovery scriptPubKey along a single descriptor,
but note that this will prevent recovering multiple separate vaults into a single
recovery output.
Varying the internal pubkey will prevent batching the trigger of multiple vault
inputs into a single trigger output; consequently it is recommended that users
instead vary some component of the trigger leaf script if address reuse is
undesirable. Users could vary the trigger pubkey along a descriptor, keeping
the recovery path and internal-pubkey the same, which both avoids reusing
addresses and allows batched trigger and recovery operations.
==== Recommendation: generate new recovery addresses for new trigger keys ====
If using unauthorized recovery, it is recommended that you do not share recovery scriptPubKeys
across separate trigger keys. If one trigger key is compromised, that will necessitate the (unauthorized)
recovery of all vaults with that trigger key, which will reveal the recovery path preimage. This
means that an observer might be able to initiate recovery for vaults controlled by an uncompromised
trigger key.
==== Fee management ====
Fees can be managed in a variety of ways, but it's worth noting that both
trigger and recovery transactions must preserve the total value of vault
inputs, so vaulted values cannot be repurposed to pay for fees. This does not
apply to the withdrawal transaction, which can allocate value arbitrarily.
In the case of vaults that use recovery authorization, all transactions can
"bring their own fees" in the form of unrelated inputs and outputs. These
transactions are also free to specify ephemeral anchors, once the related relay
policies are deployed. This means that vaults using recovery authorization have
no dependence on the deploy of v3 relay policy.
For vaults using unauthorized recovery, the recovery
transaction relies on the use of either fully-spent fee inputs or an ephemeral
anchor output. This means that vaults which do not use recovery authorization
are essentially dependent on v3 transaction relay policy being deployed.
=== Batching ===
==== During trigger ====
OP_VAULT outputs with the same taptree, aside from slightly
different trigger leaves, can be batched together in the same withdrawal
process. Two "trigger" leaves are compatible if they have the same
OP_VAULT arguments.
Note that this allows the trigger authorization -- the script prefixing the
OP_VAULT invocation -- to differ while still allowing batching.
Trigger transactions can act on multiple incompatible OP_VAULT
input sets, provided each set has a suitable associated ''triggerOut''
output.
Since SIGHASH_DEFAULT can be used to sign the trigger
authorization, unrelated inputs and outputs can be included, possibly to
facilitate fee management or the batch withdrawal of incompatible vaults.
==== During withdrawal ====
During final withdrawal, multiple trigger outputs can be used towards the same
withdrawal transaction provided that they share identical
parameters. This facilitates batched
withdrawals.
==== During recovery ====
OP_VAULT_RECOVER outputs with the same
can be recovered into the same output.
Recovery-incompatible vaults which have authorized recovery can be recovered in
the same transaction, so long as each set (grouped by
) has an associated ''recoveryOut''. This allows
unrelated recoveries to share common fee management.
=== Watchtowers ===
The value of vaults is contingent upon having monitoring in place that will
alert the owner when unexpected spends are taking place. This can be done in a
variety of ways, with varying degrees of automation and trust in the
watchtower.
In the maximum-trust case, the watchtower can be fully aware of all vaulted
coins and has the means to initiate the recovery process if spends are not
pre-reported to the watchtower.
In the minimum-trust case, the user can supply a probabilistic filter of which
coins they wish to monitor; the watchtower would then alert the user if any
coins matching the filter move, and the user would be responsible for ignoring
false positives and handling recovery initiation.
=== Output descriptors ===
Output descriptors for vault-related outputs will be covered in a subsequent BIP.
== Deployment ==
Activation mechanism is to be determined.
This BIP should be deployed concurrently with BIP-0119 to enable full use of vaults.
== Backwards compatibility ==
OP_VAULT and OP_VAULT_RECOVER replace, respectively,
the witness v1-only opcodes OP_SUCCESS187 and OP_SUCCESS188 with stricter
verification semantics. Consequently, scripts using those opcodes which
previously were valid will cease to be valid with this change.
Stricter verification semantics for an OP_SUCCESSx opcode are a soft fork, so
existing software will be fully functional without upgrade except for mining
and block validation.
Backwards compatibility considerations are very comparable to previous
deployments for OP_CHECKSEQUENCEVERIFY and OP_CHECKLOCKTIMEVERIFY (see
[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP-0065] and
[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP-0112]).
== Rationale ==
== References ==
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-February/012470.html [bitcoin-dev] Bitcoin Vaults (2016)]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-February/015793.html [bitcoin-dev] Simple lock/unlock mechanism (2018)]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-April/017755.html [bitcoin-dev] On-chain vaults prototype (2020)]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-September/019419.html [bitcoin-dev] TAPLEAF_UPDATE_VERIFY covenant opcode (2021)]
* [https://arxiv.org/abs/2005.11776 Custody Protocols Using Bitcoin Vaults (2020)]
* [https://jameso.be/vaults.pdf Vaults and Covenants (2023)]
== Acknowledgements ==
The author would like to thank
* AJ Towns and Greg Sanders for discussion, numerous suggestions that improved the proposal, and advice.
* Jeremy Rubin for inspiration, advice, and mentorship.
* BL for discussion and insight.
* John Moffett for early feedback and a test case demonstrating a recursive script evaluation attack.
* Johan Halseth for providing conceptual review and pointing out a pinning attack.
* Pieter Wuille for implementation advice.
================================================
FILE: bip-0346/ref-impl/Cargo.toml
================================================
[package]
name = "txhash-ref"
version = "0.0.0"
edition = "2021"
[dependencies]
bitcoin = { version = "=0.32.8", features = [ "serde" ] }
serde_json = "1"
================================================
FILE: bip-0346/ref-impl/src/main.rs
================================================
use bitcoin::{Transaction, TxOut};
use bitcoin::consensus::encode::Encodable;
use bitcoin::hashes::{sha256, Hash, HashEngine};
pub const TXFS_VERSION: u8 = 1 << 0;
pub const TXFS_LOCKTIME: u8 = 1 << 1;
pub const TXFS_CURRENT_INPUT_IDX: u8 = 1 << 2;
pub const TXFS_CURRENT_INPUT_CONTROL_BLOCK: u8 = 1 << 3;
pub const TXFS_CURRENT_INPUT_SPENTSCRIPT: u8 = 1 << 4;
pub const TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS: u8 = 1 << 5;
pub const TXFS_CURRENT_INPUT_TAPROOT_ANNEX: u8 = 1 << 6;
pub const TXFS_CONTROL: u8 = 1 << 7;
pub const TXFS_INPUTS_PREVOUTS: u8 = 1 << 0;
pub const TXFS_INPUTS_SEQUENCES: u8 = 1 << 1;
pub const TXFS_INPUTS_SCRIPTSIGS: u8 = 1 << 2;
pub const TXFS_INPUTS_PREV_SCRIPTPUBKEYS: u8 = 1 << 3;
pub const TXFS_INPUTS_PREV_VALUES: u8 = 1 << 4;
pub const TXFS_INPUTS_TAPROOT_ANNEXES: u8 = 1 << 5;
pub const TXFS_OUTPUTS_SCRIPTPUBKEYS: u8 = 1 << 6;
pub const TXFS_OUTPUTS_VALUES: u8 = 1 << 7;
pub const TXFS_INPUTS_ALL: u8 = TXFS_INPUTS_PREVOUTS
| TXFS_INPUTS_SEQUENCES
| TXFS_INPUTS_SCRIPTSIGS
| TXFS_INPUTS_PREV_SCRIPTPUBKEYS
| TXFS_INPUTS_PREV_VALUES
| TXFS_INPUTS_TAPROOT_ANNEXES;
pub const TXFS_OUTPUTS_ALL: u8 = TXFS_OUTPUTS_SCRIPTPUBKEYS | TXFS_OUTPUTS_VALUES;
pub const TXFS_INOUT_NUMBER: u8 = 1 << 7;
pub const TXFS_INOUT_SELECTION_NONE: u8 = 0x00;
pub const TXFS_INOUT_SELECTION_CURRENT: u8 = 0x40;
pub const TXFS_INOUT_SELECTION_ALL: u8 = 0x3f;
pub const TXFS_INOUT_SELECTION_MODE: u8 = 1 << 6;
pub const TXFS_INOUT_LEADING_SIZE: u8 = 1 << 5;
pub const TXFS_INOUT_INDIVIDUAL_MODE: u8 = 1 << 5;
pub const TXFS_INOUT_SELECTION_MASK: u8 = 0xff ^ (1 << 7) ^ (1 << 6) ^ (1 << 5);
pub const TXFS_SPECIAL_TEMPLATE: [u8; 4] = [
TXFS_VERSION | TXFS_LOCKTIME | TXFS_CURRENT_INPUT_IDX,
TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS | TXFS_OUTPUTS_ALL,
TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL,
TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL,
];
const SHA256_EMPTY: sha256::Hash = sha256::Hash::const_hash(&[]);
/// Interpret the bits of the input byte as a signed 7-bit integer and return the
/// value as an i8.
fn read_i7(input: u8) -> i8 {
let masked = input & 0x7f;
if (masked & 0x40) == 0 {
masked as i8
} else {
0i8 - ((!(masked-1)) & 0x7f) as i8
}
}
/// Interpret the bits of the input bytes as a signed 15-bit integer and return the
/// value as an i16.
fn read_i15(input: u16) -> i16 {
let masked = input & 0x7fff;
if (masked & 0x4000) == 0 {
masked as i16
} else {
0i16 - ((!(masked-1)) & 0x7fff) as i16
}
}
fn convert_short_txfs(txfs: u8) -> Result<[u8; 4], &'static str> {
let mut base = TXFS_VERSION | TXFS_LOCKTIME | TXFS_CONTROL | TXFS_CURRENT_INPUT_TAPROOT_ANNEX;
let mut inout_fields = TXFS_OUTPUTS_ALL | TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS;
let input_selection = match txfs & 0b00000011 {
0b00000000 => TXFS_INOUT_SELECTION_NONE,
0b00000001 => TXFS_INOUT_SELECTION_CURRENT,
0b00000011 => TXFS_INOUT_SELECTION_ALL,
_ => return Err("0b10 is not a valid input selection"),
};
let output_selection = match txfs & 0b00001100 {
0b00000000 => TXFS_INOUT_SELECTION_NONE,
0b00000100 => TXFS_INOUT_SELECTION_CURRENT,
0b00001100 => TXFS_INOUT_SELECTION_ALL,
_ => return Err("0b10 is not a valid output selection"),
};
if txfs & 0b00010000 != 0 {
inout_fields = inout_fields | TXFS_INPUTS_PREVOUTS;
}
if txfs & 0b00100000 != 0 {
inout_fields = inout_fields | TXFS_INPUTS_PREV_SCRIPTPUBKEYS | TXFS_INPUTS_PREV_VALUES;
}
if txfs & 0b01000000 != 0 {
base = base | TXFS_CURRENT_INPUT_CONTROL_BLOCK | TXFS_CURRENT_INPUT_SPENTSCRIPT
| TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS;
}
if txfs & 0b10000000 != 0 {
base = base | TXFS_CURRENT_INPUT_IDX;
}
Ok([base, inout_fields, input_selection, output_selection])
}
/// Parse an input or output selection from the TxFieldSelector bytes.
///
/// Returns the selected indices and a flag whether to commit the number of items.
fn parse_inout_selection(
first_byte: u8,
bytes: &mut impl Iterator,
nb_items: usize,
current_input_idx: u32,
) -> Result<(Vec, bool), &'static str> {
let commit_number = (first_byte & TXFS_INOUT_NUMBER) != 0;
let selection = first_byte & (0xff ^ TXFS_INOUT_NUMBER);
let selected = if selection == TXFS_INOUT_SELECTION_NONE {
vec![]
} else if selection == TXFS_INOUT_SELECTION_ALL {
(0..nb_items).collect()
} else if selection == TXFS_INOUT_SELECTION_CURRENT {
if current_input_idx as usize >= nb_items {
// NB can only happen for outputs
return Err("current input index exceeds number of outputs and current output selected");
}
vec![current_input_idx as usize]
} else if (selection & TXFS_INOUT_SELECTION_MODE) == 0 {
// leading mode
let count = if (selection & TXFS_INOUT_LEADING_SIZE) == 0 {
(selection & TXFS_INOUT_SELECTION_MASK) as usize
} else {
let next_byte = bytes.next().ok_or("second leading selection byte missing")?;
(((selection & TXFS_INOUT_SELECTION_MASK) as usize) << 8) + next_byte as usize
};
assert_ne!(count, 0, "this should be interpreted as NONE above");
if count > nb_items {
return Err("selected number of leading in/outputs out of bounds");
}
(0..count).collect()
} else {
// individual mode
let absolute = (selection & TXFS_INOUT_INDIVIDUAL_MODE) == 0;
let count = (selection & TXFS_INOUT_SELECTION_MASK) as usize;
let mut selected = Vec::with_capacity(count as usize);
for _ in 0..count {
let first = bytes.next().ok_or("expected an index byte")?;
let single_byte = (first & (1 << 7)) == 0;
let number = if single_byte {
first as usize
} else {
let next_byte = bytes.next().ok_or("expected another index byte")?;
(((first & (1 << 7)) as usize) << 8) + next_byte as usize
};
let idx = if absolute {
number
} else {
let rel = if single_byte {
read_i7(number as u8) as isize
} else {
read_i15(number as u16) as isize
};
if rel.is_negative() && rel.abs() > current_input_idx as isize {
return Err("relative index out of bounds");
}
(current_input_idx as isize + rel) as usize
};
if idx > nb_items {
return Err("selected index out of bounds");
}
if let Some(last) = selected.last() {
if idx <= *last {
return Err("selected indices not in increasing order")
}
}
selected.push(idx);
}
selected
};
Ok((selected, commit_number))
}
///
///
/// Assumes that TxFieldSelector is valid.
pub fn calculate_txhash(
txfs: &[u8],
tx: &Transaction,
prevouts: &[TxOut],
current_input_idx: u32,
current_input_last_codeseparator_pos: Option,
) -> Result {
assert_eq!(tx.input.len(), prevouts.len());
let txfs = if txfs.is_empty() {
TXFS_SPECIAL_TEMPLATE.to_vec()
} else if txfs.len() == 1 {
convert_short_txfs(txfs[0])?.to_vec()
} else {
txfs.to_vec()
};
let txfs = &txfs;
let mut engine = sha256::Hash::engine();
if (txfs[0] & TXFS_CONTROL) != 0 {
engine.input(txfs);
}
let mut bytes = txfs.iter().copied().peekable();
let global = bytes.next().unwrap();
if (global & TXFS_VERSION) != 0 {
tx.version.consensus_encode(&mut engine).unwrap();
}
if (global & TXFS_LOCKTIME) != 0 {
tx.lock_time.consensus_encode(&mut engine).unwrap();
}
if (global & TXFS_CURRENT_INPUT_IDX) != 0 {
(current_input_idx as u32).consensus_encode(&mut engine).unwrap();
}
let current_prevout = &prevouts[current_input_idx as usize];
let current_input = &tx.input[current_input_idx as usize];
if (global & TXFS_CURRENT_INPUT_CONTROL_BLOCK) != 0 {
assert!(current_prevout.script_pubkey.is_p2tr(), "only active in taproot context");
if let Some(cb) = current_input.witness.taproot_control_block() {
engine.input(&sha256::Hash::hash(&cb)[..]);
} else {
// keyspend
engine.input(&SHA256_EMPTY[..]);
}
}
if (global & TXFS_CURRENT_INPUT_SPENTSCRIPT) != 0 {
assert!(current_prevout.script_pubkey.is_p2tr(), "only active in taproot context");
if let Some(script) = current_input.witness.taproot_leaf_script() {
let mut eng = sha256::Hash::engine();
script.version.to_consensus().consensus_encode(&mut eng).unwrap();
script.script.consensus_encode(&mut eng).unwrap();
engine.input(&sha256::Hash::from_engine(eng)[..]);
} else {
engine.input(&SHA256_EMPTY[..]);
}
}
if (global & TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS) != 0 {
let pos = current_input_last_codeseparator_pos.unwrap_or(u32::MAX);
(pos as u32).consensus_encode(&mut engine).unwrap();
}
if (global & TXFS_CURRENT_INPUT_TAPROOT_ANNEX) != 0 {
if let Some(annex) = current_input.witness.taproot_annex() {
engine.input(&sha256::Hash::hash(annex)[..]);
} else {
engine.input(&SHA256_EMPTY[..]);
}
}
let inout_fields = bytes.next().unwrap_or(0x00);
// Inputs
let (input_selection, commit_number_inputs) = if let Some(first_byte) = bytes.next() {
parse_inout_selection(first_byte, &mut bytes, tx.input.len(), current_input_idx)?
} else {
(vec![], false)
};
if commit_number_inputs {
(tx.input.len() as u32).consensus_encode(&mut engine).unwrap();
}
if !input_selection.is_empty() && (inout_fields & TXFS_INPUTS_PREVOUTS) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &input_selection {
tx.input[*i].previous_output.consensus_encode(&mut engine).unwrap();
}
sha256::Hash::from_engine(engine)
};
engine.input(&hash[..]);
}
if !input_selection.is_empty() && (inout_fields & TXFS_INPUTS_SEQUENCES) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &input_selection {
tx.input[*i].sequence.consensus_encode(&mut engine).unwrap();
}
sha256::Hash::from_engine(engine)
};
engine.input(&hash[..]);
}
if !input_selection.is_empty() && (inout_fields & TXFS_INPUTS_SCRIPTSIGS) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &input_selection {
engine.input(&sha256::Hash::hash(&tx.input[*i].script_sig.as_bytes())[..]);
}
sha256::Hash::from_engine(engine)
};
engine.input(&hash[..]);
}
if !input_selection.is_empty() && (inout_fields & TXFS_INPUTS_PREV_SCRIPTPUBKEYS) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &input_selection {
engine.input(&sha256::Hash::hash(&prevouts[*i].script_pubkey.as_bytes())[..]);
}
sha256::Hash::from_engine(engine)
};
engine.input(&hash[..]);
}
if !input_selection.is_empty() && (inout_fields & TXFS_INPUTS_PREV_VALUES) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &input_selection {
prevouts[*i].value.consensus_encode(&mut engine).unwrap();
}
sha256::Hash::from_engine(engine)
};
engine.input(&hash[..]);
}
if !input_selection.is_empty() && (inout_fields & TXFS_INPUTS_TAPROOT_ANNEXES) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &input_selection {
if prevouts[*i].script_pubkey.is_p2tr() {
if let Some(annex) = tx.input[*i].witness.taproot_annex() {
engine.input(&sha256::Hash::hash(annex)[..]);
} else {
engine.input(&SHA256_EMPTY[..]);
}
} else {
engine.input(&SHA256_EMPTY[..]);
}
}
sha256::Hash::from_engine(engine)
};
engine.input(&hash[..]);
}
// Outputs
let (output_selection, commit_number_outputs) = if let Some(first_byte) = bytes.next() {
parse_inout_selection(first_byte, &mut bytes, tx.output.len(), current_input_idx)?
} else {
(vec![], false)
};
if commit_number_outputs {
(tx.output.len() as u32).consensus_encode(&mut engine).unwrap();
}
if !output_selection.is_empty() && (inout_fields & TXFS_OUTPUTS_SCRIPTPUBKEYS) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &output_selection {
engine.input(&sha256::Hash::hash(&tx.output[*i].script_pubkey.as_bytes())[..]);
}
sha256::Hash::from_engine(engine)
};
hash.consensus_encode(&mut engine).unwrap();
}
if !output_selection.is_empty() && (inout_fields & TXFS_OUTPUTS_VALUES) != 0 {
let hash = {
let mut engine = sha256::Hash::engine();
for i in &output_selection {
tx.output[*i].value.consensus_encode(&mut engine).unwrap();
}
sha256::Hash::from_engine(engine)
};
hash.consensus_encode(&mut engine).unwrap();
}
if bytes.next().is_some() {
return Err("unexpected additional txfs bytes");
}
Ok(sha256::Hash::from_engine(engine))
}
mod test_vectors {
use super::*;
use std::any::Any;
use std::ops::{self, RangeBounds};
use bitcoin::hex::DisplayHex;
use bitcoin::{Amount, ScriptBuf, Sequence, Witness};
use bitcoin::blockdata::transaction::{self, TxIn};
use bitcoin::opcodes::all::*;
fn test_vector_tx() -> (Transaction, Vec) {
let tx = Transaction {
version: transaction::Version::TWO,
lock_time: bitcoin::absolute::LockTime::from_consensus(42),
input: vec![
TxIn {
previous_output: "3333333333333333333333333333333333333333333333333333333333333333:3".parse().unwrap(),
script_sig: ScriptBuf::new(),
sequence: Sequence::from_consensus(2),
witness: {
let mut buf = Witness::new();
buf.push(vec![0x12]);
buf
},
},
TxIn {
previous_output: "4444444444444444444444444444444444444444444444444444444444444444:4".parse().unwrap(),
script_sig: ScriptBuf::new(),
sequence: Sequence::from_consensus(3),
witness: {
let mut buf = Witness::new();
buf.push(vec![0x13]);
buf.push(vec![0x14]);
buf.push(vec![0x50, 0x42]); // annex
buf
},
},
TxIn {
previous_output: "1111111111111111111111111111111111111111111111111111111111111111:1".parse().unwrap(),
script_sig: vec![0x23].into(),
sequence: Sequence::from_consensus(1),
witness: Witness::new(),
},
TxIn {
previous_output: "2222222222222222222222222222222222222222222222222222222222222222:2".parse().unwrap(),
script_sig: ScriptBuf::new(),
sequence: Sequence::from_consensus(3),
witness: { // p2wsh annex-like stack element
let mut buf = Witness::new();
buf.push(vec![0x13]);
buf.push(vec![0x14]);
buf.push(vec![0x50, 0x42]); // annex
buf
},
},
],
output: vec![
TxOut {
script_pubkey: vec![OP_PUSHNUM_6.to_u8()].into(),
value: Amount::from_sat(350),
},
TxOut {
script_pubkey: vec![OP_PUSHNUM_7.to_u8()].into(),
value: Amount::from_sat(351),
},
TxOut {
script_pubkey: vec![OP_PUSHNUM_8.to_u8()].into(),
value: Amount::from_sat(353),
},
],
};
let prevs = vec![
TxOut {
script_pubkey: vec![ // p2tr
0x51, 0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
].into(),
value: Amount::from_sat(361),
},
TxOut {
script_pubkey: vec![ // p2tr
0x51, 0x20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
].into(),
value: Amount::from_sat(362),
},
TxOut {
script_pubkey: vec![OP_PUSHNUM_16.to_u8()].into(),
value: Amount::from_sat(360),
},
TxOut {
script_pubkey: vec![ // p2wsh
0x00, 0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
].into(),
value: Amount::from_sat(361),
},
];
(tx, prevs)
}
#[derive(Debug)]
struct TestCase {
tx: Transaction,
prevs: Vec,
vectors: Vec
}
#[derive(Debug)]
struct TestVector {
txfs: Vec,
input: usize,
codeseparator: Option,
txhash: sha256::Hash,
}
fn generate_vectors() -> Vec {
let all = 0xff;
let allio = TXFS_INPUTS_ALL | TXFS_OUTPUTS_ALL;
let selnone = TXFS_INOUT_SELECTION_NONE; // 0x00
let selcur = TXFS_INOUT_SELECTION_CURRENT;
let selall = TXFS_INOUT_SELECTION_ALL;
let number = TXFS_INOUT_NUMBER;
let leading = 0;
let individual = TXFS_INOUT_SELECTION_MODE;
let absolute = 0;
let relative = TXFS_INOUT_INDIVIDUAL_MODE;
fn r + 'static>(t: T) -> Option> {
Some(Box::new(t))
}
// txfs and range of inputs to run it on
let selectors: &[(&[u8], Option>)] = &[
// global
(&[1 << 0, 0], None),
(&[1 << 1, 0], None),
(&[1 << 2, 0], None),
(&[1 << 3, 0], None),
(&[1 << 4, 0], None),
(&[1 << 5, 0], None),
(&[1 << 6, 0], None),
(&[1 << 7, 0], None),
// outputs
(&[all, 0, 0, number | selnone], None),
(&[all, TXFS_OUTPUTS_SCRIPTPUBKEYS, 0, selcur], None),
(&[all, TXFS_OUTPUTS_VALUES, 0, selcur], None),
(&[all, TXFS_OUTPUTS_ALL, 0, selcur], None),
(&[all, TXFS_OUTPUTS_SCRIPTPUBKEYS, 0, selall], None),
(&[all, TXFS_OUTPUTS_VALUES, 0, selall], None),
(&[all, TXFS_OUTPUTS_ALL, 0, selall], None),
(&[all, TXFS_OUTPUTS_SCRIPTPUBKEYS, 0, number | selcur], None),
(&[all, TXFS_OUTPUTS_VALUES, 0, number | selcur], None),
(&[all, TXFS_OUTPUTS_ALL, 0, number | selcur], None),
(&[all, TXFS_OUTPUTS_SCRIPTPUBKEYS, 0, number | selall], None),
(&[all, TXFS_OUTPUTS_VALUES, 0, number | selall], None),
(&[all, TXFS_OUTPUTS_ALL, 0, number | selall], None),
// inputs
(&[all, 0, number | selnone], None),
(&[all, TXFS_INPUTS_PREVOUTS, selcur], None),
(&[all, TXFS_INPUTS_SEQUENCES, selcur], None),
(&[all, TXFS_INPUTS_SCRIPTSIGS, selcur], None),
(&[all, TXFS_INPUTS_PREV_SCRIPTPUBKEYS, selcur], None),
(&[all, TXFS_INPUTS_PREV_VALUES, selcur], None),
(&[all, TXFS_INPUTS_TAPROOT_ANNEXES, selcur], None),
(&[all, TXFS_INPUTS_ALL, selcur], None),
(&[all, TXFS_INPUTS_PREVOUTS, selall], None),
(&[all, TXFS_INPUTS_SEQUENCES, selall], None),
(&[all, TXFS_INPUTS_SCRIPTSIGS, selall], None),
(&[all, TXFS_INPUTS_PREV_SCRIPTPUBKEYS, selall], None),
(&[all, TXFS_INPUTS_PREV_VALUES, selall], None),
(&[all, TXFS_INPUTS_TAPROOT_ANNEXES, selall], None),
(&[all, TXFS_INPUTS_ALL, selall], None),
(&[all, TXFS_INPUTS_PREVOUTS, number | selcur], None),
(&[all, TXFS_INPUTS_SEQUENCES, number | selcur], None),
(&[all, TXFS_INPUTS_SCRIPTSIGS, number | selcur], None),
(&[all, TXFS_INPUTS_PREV_SCRIPTPUBKEYS, number | selcur], None),
(&[all, TXFS_INPUTS_PREV_VALUES, number | selcur], None),
(&[all, TXFS_INPUTS_TAPROOT_ANNEXES, number | selcur], None),
(&[all, TXFS_INPUTS_ALL, number | selcur], None),
(&[all, TXFS_INPUTS_PREVOUTS, number | selall], None),
(&[all, TXFS_INPUTS_SEQUENCES, number | selall], None),
(&[all, TXFS_INPUTS_SCRIPTSIGS, number | selall], None),
(&[all, TXFS_INPUTS_PREV_SCRIPTPUBKEYS, number | selall], None),
(&[all, TXFS_INPUTS_PREV_VALUES, number | selall], None),
(&[all, TXFS_INPUTS_TAPROOT_ANNEXES, number | selall], None),
(&[all, TXFS_INPUTS_ALL, number | selall], None),
// both
(&[all, allio, selall, selall], None),
(&[all, allio, selcur, selcur], None),
(&[all, 0, number | selnone, number | selnone], None),
(&[all, allio, number | selall, number | selall], None),
(&[all, allio, number | selcur, number | selcur], None),
(&[all, allio, selcur, selall], None),
(&[all, allio, selall, selcur], None),
// leading
(&[all, allio, leading | 0x01, number | leading | 0x02], None),
(&[all, allio, number | selcur, leading | 0x02], None),
// individual absolute
(&[all, allio, individual | absolute | 0x01, 0x01,
individual | absolute | 0x02, 0x00, 0x02], None),
(&[all, allio, number | individual | absolute | 0x01, 0x01,
number | individual | absolute | 0x02, 0x00, 0x02], None),
// individual relative
(&[all, allio, individual | relative | 0x01, (-1i8 as u8) >> 1,
individual | relative | 0x02, (-1i8 as u8) >> 1, 0], r(1..2)),
(&[all, allio, number | individual | relative | 0x01, (-1i8 as u8) >> 1,
number | individual | relative | 0x02, (-1i8 as u8) >> 1, 0], r(1..2)),
//TODO(stevenroose) test index size, but for that we need > 32 in/outputs
// special case template
(&[], None),
// shorthand txfs, sighash examples
(&[0b11111111], None),
(&[0b11110111], None),
(&[0b11110011], None),
(&[0b11111101], None),
(&[0b11110101], None),
(&[0b11110001], None),
(&[0b11101101], None),
(&[0b11100101], None),
(&[0b11100001], None),
(&[0b11001101], None),
(&[0b11000101], None),
(&[0b11000001], None),
];
let cases = vec![
test_vector_tx(),
];
fn check_range(r: &Box, idx: usize) -> bool {
if let Some(ref range) = r.downcast_ref::() {
return range.contains(&idx);
}
if let Some(ref range) = r.downcast_ref::>() {
return range.contains(&idx);
}
if let Some(ref range) = r.downcast_ref::>() {
return range.contains(&idx);
}
if let Some(ref range) = r.downcast_ref::>() {
return range.contains(&idx);
}
unreachable!("invalid range type used: {:?}", r.type_id());
}
cases.into_iter().enumerate().map(|(cidx, (tx, prevs))| {
let mut vectors = Vec::new();
for (_sidx, (txfs, idx_range)) in selectors.iter().enumerate() {
for i in 0..tx.input.len() {
let default = r(..2); // only 2 fist inputs are taproot
let range = idx_range.as_ref().unwrap_or(default.as_ref().unwrap());
if !check_range(range, i) {
continue;
}
// println!("{} >> #{} ({}) >> {}", cidx, _sidx, txfs.as_hex(), i);
match calculate_txhash(txfs, &tx, &prevs, i as u32, None) {
Ok(txhash) => vectors.push(TestVector {
txfs: txfs.to_vec(),
input: i,
codeseparator: None,
txhash: txhash,
}),
Err(e) => panic!("Error in vector #{} for selector {}: {}",
cidx, txfs.as_hex(), e,
),
}
}
}
TestCase { tx, prevs, vectors }
}).collect()
}
pub fn write_vector_file(path: impl AsRef) {
use bitcoin::consensus::encode::serialize_hex;
let ret = generate_vectors().into_iter().enumerate().map(|(i_tx, c)| serde_json::json!({
"tx": serialize_hex(&c.tx),
"prevs": c.prevs.iter().map(|p| serialize_hex(p)).collect::>(),
"vectors": c.vectors.into_iter().enumerate().map(|(i_v, v)| serde_json::json!({
"id": format!("{}:{} ({} #{})", i_tx, i_v, v.txfs.as_hex(), v.input),
"txfs": v.txfs.as_hex().to_string(),
"input": v.input,
"codeseparator": v.codeseparator,
"txhash": v.txhash,
})).collect::>(),
})).collect::>();
let mut file = std::fs::File::create(path).unwrap();
serde_json::to_writer_pretty(&mut file, &ret).unwrap();
}
}
fn main() {
test_vectors::write_vector_file("./txhash_vectors.json");
}
================================================
FILE: bip-0346/ref-impl/txhash_vectors.json
================================================
[
{
"prevs": [
"69010000000000002251200100000000000000000000000000000000000000000000000000000000000000",
"6a010000000000002251200200000000000000000000000000000000000000000000000000000000000000",
"68010000000000000160",
"69010000000000002200200100000000000000000000000000000000000000000000000000000000000000"
],
"tx": "02000000000104333333333333333333333333333333333333333333333333333333333333333303000000000200000044444444444444444444444444444444444444444444444444444444444444440400000000030000001111111111111111111111111111111111111111111111111111111111111111010000000123010000002222222222222222222222222222222222222222222222222222222222222222020000000003000000035e0100000000000001565f0100000000000001576101000000000000015801011203011301140250420003011301140250422a000000",
"vectors": [
{
"codeseparator": null,
"id": "0:0 (0100 #0)",
"input": 0,
"txfs": "0100",
"txhash": "26b25d457597a7b0463f9620f666dd10aa2c4373a505967c7c8d70922a2d6ece"
},
{
"codeseparator": null,
"id": "0:1 (0100 #1)",
"input": 1,
"txfs": "0100",
"txhash": "26b25d457597a7b0463f9620f666dd10aa2c4373a505967c7c8d70922a2d6ece"
},
{
"codeseparator": null,
"id": "0:2 (0200 #0)",
"input": 0,
"txfs": "0200",
"txhash": "e8a4b2ee7ede79a3afb332b5b6cc3d952a65fd8cffb897f5d18016577c33d7cc"
},
{
"codeseparator": null,
"id": "0:3 (0200 #1)",
"input": 1,
"txfs": "0200",
"txhash": "e8a4b2ee7ede79a3afb332b5b6cc3d952a65fd8cffb897f5d18016577c33d7cc"
},
{
"codeseparator": null,
"id": "0:4 (0400 #0)",
"input": 0,
"txfs": "0400",
"txhash": "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"
},
{
"codeseparator": null,
"id": "0:5 (0400 #1)",
"input": 1,
"txfs": "0400",
"txhash": "67abdd721024f0ff4e0b3f4c2fc13bc5bad42d0b7851d456d88d203d15aaa450"
},
{
"codeseparator": null,
"id": "0:6 (0800 #0)",
"input": 0,
"txfs": "0800",
"txhash": "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
},
{
"codeseparator": null,
"id": "0:7 (0800 #1)",
"input": 1,
"txfs": "0800",
"txhash": "d703d3da6a87bd8e0b453f3b6c41edcc9bf331b2b88ef26eb39dc7abee4e00a3"
},
{
"codeseparator": null,
"id": "0:8 (1000 #0)",
"input": 0,
"txfs": "1000",
"txhash": "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
},
{
"codeseparator": null,
"id": "0:9 (1000 #1)",
"input": 1,
"txfs": "1000",
"txhash": "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
},
{
"codeseparator": null,
"id": "0:10 (2000 #0)",
"input": 0,
"txfs": "2000",
"txhash": "ad95131bc0b799c0b1af477fb14fcf26a6a9f76079e48bf090acb7e8367bfd0e"
},
{
"codeseparator": null,
"id": "0:11 (2000 #1)",
"input": 1,
"txfs": "2000",
"txhash": "ad95131bc0b799c0b1af477fb14fcf26a6a9f76079e48bf090acb7e8367bfd0e"
},
{
"codeseparator": null,
"id": "0:12 (4000 #0)",
"input": 0,
"txfs": "4000",
"txhash": "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"
},
{
"codeseparator": null,
"id": "0:13 (4000 #1)",
"input": 1,
"txfs": "4000",
"txhash": "227747766d19539b54f018e7ccfde16bd7c38ebbf5649357ecf67bdfb9755b5c"
},
{
"codeseparator": null,
"id": "0:14 (8000 #0)",
"input": 0,
"txfs": "8000",
"txhash": "8509b81230019d2ad970d970f791dfbdc8caf54f5c594fcd327cef9feed206c1"
},
{
"codeseparator": null,
"id": "0:15 (8000 #1)",
"input": 1,
"txfs": "8000",
"txhash": "8509b81230019d2ad970d970f791dfbdc8caf54f5c594fcd327cef9feed206c1"
},
{
"codeseparator": null,
"id": "0:16 (ff000080 #0)",
"input": 0,
"txfs": "ff000080",
"txhash": "6286469e7f9ac95ff97d41ab1cf8a1d8a3872e45f5bac80a1acf8fd9d4397c18"
},
{
"codeseparator": null,
"id": "0:17 (ff000080 #1)",
"input": 1,
"txfs": "ff000080",
"txhash": "74256c5211c8209c1be86fa0d7b92993a03d5e19647b5d1f83fdc65ebee51b86"
},
{
"codeseparator": null,
"id": "0:18 (ff400040 #0)",
"input": 0,
"txfs": "ff400040",
"txhash": "66c3a2d99e0eccce1e769d61b879f6003252912982a9efc138b24365d6c68879"
},
{
"codeseparator": null,
"id": "0:19 (ff400040 #1)",
"input": 1,
"txfs": "ff400040",
"txhash": "f1dfe060222dfa92e1f91d5afd5790ac9de5b1ff5db777282c85e0a968c25d0e"
},
{
"codeseparator": null,
"id": "0:20 (ff800040 #0)",
"input": 0,
"txfs": "ff800040",
"txhash": "52bc63b1b02c3d375d13236938b25d5249df08fb4d891686a70e5702ea12c0e4"
},
{
"codeseparator": null,
"id": "0:21 (ff800040 #1)",
"input": 1,
"txfs": "ff800040",
"txhash": "40351ff507344dd2493e80df868843bac4cff20c456e2ca28cfa39b2a0cf0557"
},
{
"codeseparator": null,
"id": "0:22 (ffc00040 #0)",
"input": 0,
"txfs": "ffc00040",
"txhash": "75ae3a008d82c09aa7afd34abd46f03afe940758d33763b188d1fa2bd068cd80"
},
{
"codeseparator": null,
"id": "0:23 (ffc00040 #1)",
"input": 1,
"txfs": "ffc00040",
"txhash": "6c3adf154dec8e01f323c0ac20ee5731bfbc5af4259a9a87c8ad0c77dd9c4417"
},
{
"codeseparator": null,
"id": "0:24 (ff40003f #0)",
"input": 0,
"txfs": "ff40003f",
"txhash": "8dea16353d8dbb04764bc5a21fa36236aa3f736761cbb9be809a0a870fa6a366"
},
{
"codeseparator": null,
"id": "0:25 (ff40003f #1)",
"input": 1,
"txfs": "ff40003f",
"txhash": "f3d00fee00e8841e38f465e211ede292fde56e1223c0f211786bc1d357593545"
},
{
"codeseparator": null,
"id": "0:26 (ff80003f #0)",
"input": 0,
"txfs": "ff80003f",
"txhash": "d0b05b4c01125da54d473da6d5f21bef264cfa236e9dde70ff140027cef94931"
},
{
"codeseparator": null,
"id": "0:27 (ff80003f #1)",
"input": 1,
"txfs": "ff80003f",
"txhash": "5eb3c700160c0b8b185babc8d2f2be4370f666c660ddb2113a187aacbfbf2b59"
},
{
"codeseparator": null,
"id": "0:28 (ffc0003f #0)",
"input": 0,
"txfs": "ffc0003f",
"txhash": "a28ff0cd1109352b4dcbf74a0d2a6c73732235b532bb8284ad388b8e49838ea5"
},
{
"codeseparator": null,
"id": "0:29 (ffc0003f #1)",
"input": 1,
"txfs": "ffc0003f",
"txhash": "ec672278f9ab6f4a21e9406721c27173e7887b75ab82cdee81988692324b3e47"
},
{
"codeseparator": null,
"id": "0:30 (ff4000c0 #0)",
"input": 0,
"txfs": "ff4000c0",
"txhash": "af6e1adf1ff16c7bae08e4127b30dab4fedee683277c8b65e27897e9013d63cf"
},
{
"codeseparator": null,
"id": "0:31 (ff4000c0 #1)",
"input": 1,
"txfs": "ff4000c0",
"txhash": "a0f1b5db81c1bba78772f6306107809c29c2f01d41e5d74e39fcf3463e666a91"
},
{
"codeseparator": null,
"id": "0:32 (ff8000c0 #0)",
"input": 0,
"txfs": "ff8000c0",
"txhash": "8ce6884e8b3a11d81f69b9642981770cf2f7ed59cd7748e66f443e10cb16094d"
},
{
"codeseparator": null,
"id": "0:33 (ff8000c0 #1)",
"input": 1,
"txfs": "ff8000c0",
"txhash": "d62d70495e26ba054e60328d35595ea3caf74d8faec2a34e08fb0da8ac6e4514"
},
{
"codeseparator": null,
"id": "0:34 (ffc000c0 #0)",
"input": 0,
"txfs": "ffc000c0",
"txhash": "29c5f8ace77d67bc684be308d8bba076ddbccb7db86890f1affde88243111d66"
},
{
"codeseparator": null,
"id": "0:35 (ffc000c0 #1)",
"input": 1,
"txfs": "ffc000c0",
"txhash": "9d7f7313cf89e95b4984f6864fe6103e26fe02d8e930221d1bdf47b8222b5d8d"
},
{
"codeseparator": null,
"id": "0:36 (ff4000bf #0)",
"input": 0,
"txfs": "ff4000bf",
"txhash": "a111bf0e5c46831243ec5d8095ffdb959b316c00e00296dfce12b5dc817f1d29"
},
{
"codeseparator": null,
"id": "0:37 (ff4000bf #1)",
"input": 1,
"txfs": "ff4000bf",
"txhash": "1ac5b588e154bbf4cf1a462eb83718bcd72c1b544867300004950afa15a416a0"
},
{
"codeseparator": null,
"id": "0:38 (ff8000bf #0)",
"input": 0,
"txfs": "ff8000bf",
"txhash": "2ecd12402dd1443629037d5864d5464d9c8812bd44449bfc25b16b0c76bfff79"
},
{
"codeseparator": null,
"id": "0:39 (ff8000bf #1)",
"input": 1,
"txfs": "ff8000bf",
"txhash": "c5a5ac672a574311029e25b4d381f844745aad80e23040119aa9df76570d9ae2"
},
{
"codeseparator": null,
"id": "0:40 (ffc000bf #0)",
"input": 0,
"txfs": "ffc000bf",
"txhash": "6b7d5990b3435e42a4212c88967eb0f9c8b3c3738ecc2fc79d4b48bb386f178c"
},
{
"codeseparator": null,
"id": "0:41 (ffc000bf #1)",
"input": 1,
"txfs": "ffc000bf",
"txhash": "ba92bbf9b3151efaaa0582c5db076066fdc842037daf5c8d51ee425130cd2181"
},
{
"codeseparator": null,
"id": "0:42 (ff0080 #0)",
"input": 0,
"txfs": "ff0080",
"txhash": "3a23df77318fd630a1b004bd49ee23e2f6ffb588a3e38d50577a307401f67127"
},
{
"codeseparator": null,
"id": "0:43 (ff0080 #1)",
"input": 1,
"txfs": "ff0080",
"txhash": "c8c9cb44b4405c2efb77e6fd2a1258d4479042d6dc1fb51bf8aa0448f6514635"
},
{
"codeseparator": null,
"id": "0:44 (ff0140 #0)",
"input": 0,
"txfs": "ff0140",
"txhash": "e2fcdd4957e7891edac19f58776806218069192b0e94d1d77260a555342d06ac"
},
{
"codeseparator": null,
"id": "0:45 (ff0140 #1)",
"input": 1,
"txfs": "ff0140",
"txhash": "3f87e78b8be3e4b28b29c255bd5ed7c10ab69b02963b02b9394aee1b5f788434"
},
{
"codeseparator": null,
"id": "0:46 (ff0240 #0)",
"input": 0,
"txfs": "ff0240",
"txhash": "2589b0924c45f17484e681c5df41fa136833c44b985ef3fbf17974ca46d7ecd4"
},
{
"codeseparator": null,
"id": "0:47 (ff0240 #1)",
"input": 1,
"txfs": "ff0240",
"txhash": "871bc1ff067094336c1860b01a38673cedce057568f036202e7a3e2410847e44"
},
{
"codeseparator": null,
"id": "0:48 (ff0440 #0)",
"input": 0,
"txfs": "ff0440",
"txhash": "91509f1fd4fb675a936c5cf9c79528ea6441750f41ca8851125c1d78f1880a6c"
},
{
"codeseparator": null,
"id": "0:49 (ff0440 #1)",
"input": 1,
"txfs": "ff0440",
"txhash": "6e18b0171ce7aee2307a4e9ecc1e8d625d07116063e52604a85bc6d1064cfc32"
},
{
"codeseparator": null,
"id": "0:50 (ff0840 #0)",
"input": 0,
"txfs": "ff0840",
"txhash": "d9f97f4e62518332b2bd5d0bad604973d5dfef0945a95685d258ce9743d079ec"
},
{
"codeseparator": null,
"id": "0:51 (ff0840 #1)",
"input": 1,
"txfs": "ff0840",
"txhash": "0575703690b0c557080ff3bef27cfe517abacbe420aa9ddaf53cfe3c733ec077"
},
{
"codeseparator": null,
"id": "0:52 (ff1040 #0)",
"input": 0,
"txfs": "ff1040",
"txhash": "eb53fa90d5e2617ec342007a1bf7ac62dbe66c5147ba60a294a7db1704620f75"
},
{
"codeseparator": null,
"id": "0:53 (ff1040 #1)",
"input": 1,
"txfs": "ff1040",
"txhash": "6dc2f01a3b22b761df91d9a6ba9b58d85f26d881585bd252fcf75eed4ab74e94"
},
{
"codeseparator": null,
"id": "0:54 (ff2040 #0)",
"input": 0,
"txfs": "ff2040",
"txhash": "1a7a2897721b14ebabac2dd83964323864d6f54610a21c255b7a61be4042f269"
},
{
"codeseparator": null,
"id": "0:55 (ff2040 #1)",
"input": 1,
"txfs": "ff2040",
"txhash": "953b14f68d47206c29b780c13234a8e2017804367c4b67012626d19e2f21ceff"
},
{
"codeseparator": null,
"id": "0:56 (ff3f40 #0)",
"input": 0,
"txfs": "ff3f40",
"txhash": "e94869fa522e4acd229958b360dd6b9d87f9e59fcead016875b0f97f10c18595"
},
{
"codeseparator": null,
"id": "0:57 (ff3f40 #1)",
"input": 1,
"txfs": "ff3f40",
"txhash": "3262c8c9f7b2538e123f11e7b31aa7c7c5f6c7bf031ac89ead194991a9df74b1"
},
{
"codeseparator": null,
"id": "0:58 (ff013f #0)",
"input": 0,
"txfs": "ff013f",
"txhash": "3ab80fffdf1301f056762b0e2e09c11699a479adbaa1bea38a95a6ec49e94c0e"
},
{
"codeseparator": null,
"id": "0:59 (ff013f #1)",
"input": 1,
"txfs": "ff013f",
"txhash": "2ccab90e40aaab0304458362ba31ce910c41ed446ad14b15a15613a84be0a147"
},
{
"codeseparator": null,
"id": "0:60 (ff023f #0)",
"input": 0,
"txfs": "ff023f",
"txhash": "29ebfe25e2d5e33a416808b36e2d23538c7e94c77ada313fd78a3137471fb618"
},
{
"codeseparator": null,
"id": "0:61 (ff023f #1)",
"input": 1,
"txfs": "ff023f",
"txhash": "eddeb813dabe380be2f59cf04b4e0528a2033933ffea03bb49b45a262ca2d566"
},
{
"codeseparator": null,
"id": "0:62 (ff043f #0)",
"input": 0,
"txfs": "ff043f",
"txhash": "ebd4f5e2636391b007d0c1e68e0d088d6e5a638a3e40c00e322b0a9363b3e477"
},
{
"codeseparator": null,
"id": "0:63 (ff043f #1)",
"input": 1,
"txfs": "ff043f",
"txhash": "9f1cd389104b23b29d534b16d06ba3f0839d58d443f798ada9155bf2f4ebe4f6"
},
{
"codeseparator": null,
"id": "0:64 (ff083f #0)",
"input": 0,
"txfs": "ff083f",
"txhash": "4b596fbefb903426720ba9a3906306371253d2de874537e722a47de29c925647"
},
{
"codeseparator": null,
"id": "0:65 (ff083f #1)",
"input": 1,
"txfs": "ff083f",
"txhash": "ef50137ead871d0dd9c1b4c6cb0c57ea00f7650d111897d0bcd0441622e9375d"
},
{
"codeseparator": null,
"id": "0:66 (ff103f #0)",
"input": 0,
"txfs": "ff103f",
"txhash": "874afe3e5a88a2cc3afc3239ea78e6d0cd91c83ae384880830f0daf1096838d1"
},
{
"codeseparator": null,
"id": "0:67 (ff103f #1)",
"input": 1,
"txfs": "ff103f",
"txhash": "7002a2f133407c98c08f17caac86fdeac6e5f2ae86c059567028a9e2f2718929"
},
{
"codeseparator": null,
"id": "0:68 (ff203f #0)",
"input": 0,
"txfs": "ff203f",
"txhash": "589f39f55732242d97de0fdb8aa8a3736b197d4f319885c32651cd565021da6b"
},
{
"codeseparator": null,
"id": "0:69 (ff203f #1)",
"input": 1,
"txfs": "ff203f",
"txhash": "46fc739044047fc00053ec7532ceee2ea53fe75029a2d65c90d5da2738937b8e"
},
{
"codeseparator": null,
"id": "0:70 (ff3f3f #0)",
"input": 0,
"txfs": "ff3f3f",
"txhash": "ece064b4f1551cfbcff6792e32842bb08335fb2cb5ee430f7707a00d15f89c41"
},
{
"codeseparator": null,
"id": "0:71 (ff3f3f #1)",
"input": 1,
"txfs": "ff3f3f",
"txhash": "e41fd96f9d8f48c6ac04ce5039d850535b668c3b8b83f3913e2a131edfe5b4df"
},
{
"codeseparator": null,
"id": "0:72 (ff01c0 #0)",
"input": 0,
"txfs": "ff01c0",
"txhash": "35aa24440a7e833ed0f6503688a7a7009ebc1999cebd58c10724a2d321d41174"
},
{
"codeseparator": null,
"id": "0:73 (ff01c0 #1)",
"input": 1,
"txfs": "ff01c0",
"txhash": "d3bbb1e58851725a94a5538189b5dad23c9c7cec53549f959e6f498dce737828"
},
{
"codeseparator": null,
"id": "0:74 (ff02c0 #0)",
"input": 0,
"txfs": "ff02c0",
"txhash": "79ee870774e05726bbf47780154ff33e9ded3c67bae7ec02a12663106adbcc68"
},
{
"codeseparator": null,
"id": "0:75 (ff02c0 #1)",
"input": 1,
"txfs": "ff02c0",
"txhash": "01bf86cb8dd28adf6807c505b4c538a2490c213be8b1224b55c7e4b5ab523d97"
},
{
"codeseparator": null,
"id": "0:76 (ff04c0 #0)",
"input": 0,
"txfs": "ff04c0",
"txhash": "8dbd343cd6dd7f92c0c9e0c278d6189f8ae08400e7ffbe0e932fb4675bc0d4f1"
},
{
"codeseparator": null,
"id": "0:77 (ff04c0 #1)",
"input": 1,
"txfs": "ff04c0",
"txhash": "8b566825b9c36b5e0b6916827ad7573cfe74f8a903c1ff06a06329aaa28b9c1d"
},
{
"codeseparator": null,
"id": "0:78 (ff08c0 #0)",
"input": 0,
"txfs": "ff08c0",
"txhash": "98d344d199bb540a91c6a9d70e3daa3ead46c30a377470ffbe1199d12a606aec"
},
{
"codeseparator": null,
"id": "0:79 (ff08c0 #1)",
"input": 1,
"txfs": "ff08c0",
"txhash": "b68c12f03396664d494b2af4363efc89667f76d9bf962e52c2a52fcb0ed877b9"
},
{
"codeseparator": null,
"id": "0:80 (ff10c0 #0)",
"input": 0,
"txfs": "ff10c0",
"txhash": "2fb64ddf05090b11ec14848963af6aac97ea2394623e66d8f9237eb712b5bbe8"
},
{
"codeseparator": null,
"id": "0:81 (ff10c0 #1)",
"input": 1,
"txfs": "ff10c0",
"txhash": "8eaa22ece3e6e61340a013c607ca487270b14143fdb666d021879f5c84fbf661"
},
{
"codeseparator": null,
"id": "0:82 (ff20c0 #0)",
"input": 0,
"txfs": "ff20c0",
"txhash": "70bf9abee31014fc3e454049535e115948ea16022323d58eda379801763b00c5"
},
{
"codeseparator": null,
"id": "0:83 (ff20c0 #1)",
"input": 1,
"txfs": "ff20c0",
"txhash": "5abbe67209f513d56380f45578dc5479ab76e3ed9121f4d100dca09793da2584"
},
{
"codeseparator": null,
"id": "0:84 (ff3fc0 #0)",
"input": 0,
"txfs": "ff3fc0",
"txhash": "791a302cbb5e2a711ef54911a62b9968223bfda2d6c1f91f72ad8680883b4568"
},
{
"codeseparator": null,
"id": "0:85 (ff3fc0 #1)",
"input": 1,
"txfs": "ff3fc0",
"txhash": "5449e0e4fd52db193c70b0804fafd53093753b936cbf6582c33e375ca0c55ed2"
},
{
"codeseparator": null,
"id": "0:86 (ff01bf #0)",
"input": 0,
"txfs": "ff01bf",
"txhash": "0c86d8789f7a98e7aed70940dd78a1ea6b42d3a4adf16fe343d6ddac78c5fdc3"
},
{
"codeseparator": null,
"id": "0:87 (ff01bf #1)",
"input": 1,
"txfs": "ff01bf",
"txhash": "770c254d1a603e09243bd0d193ec89aaaee20958abe3c2249c57565cfb3ebc90"
},
{
"codeseparator": null,
"id": "0:88 (ff02bf #0)",
"input": 0,
"txfs": "ff02bf",
"txhash": "b2f3145c3caaddb1344fd170e62eadd93b34adb5a8262c8e1c2d542f8ce0e045"
},
{
"codeseparator": null,
"id": "0:89 (ff02bf #1)",
"input": 1,
"txfs": "ff02bf",
"txhash": "fbf7a5bec0037e3ed35f0fe243688f6e0fe3583adce9ca221af02bed1cced8cb"
},
{
"codeseparator": null,
"id": "0:90 (ff04bf #0)",
"input": 0,
"txfs": "ff04bf",
"txhash": "d08f2c883d8bc078ee42aa2647307d455a53caeeda3a2d1ce1bcaaaf223b2dc8"
},
{
"codeseparator": null,
"id": "0:91 (ff04bf #1)",
"input": 1,
"txfs": "ff04bf",
"txhash": "0db8760a71982cf0c354be8b286e1a202695aac3c18a952ec0af6c79247a50bd"
},
{
"codeseparator": null,
"id": "0:92 (ff08bf #0)",
"input": 0,
"txfs": "ff08bf",
"txhash": "acb8c88af64ecd6c65931c7549e6e913c7eb8a6305f5abdea1c21ada1c57c1fb"
},
{
"codeseparator": null,
"id": "0:93 (ff08bf #1)",
"input": 1,
"txfs": "ff08bf",
"txhash": "528f4d8c24cc929b21b2bf2306c12225b4a58119a57b46905a4748117a1f671e"
},
{
"codeseparator": null,
"id": "0:94 (ff10bf #0)",
"input": 0,
"txfs": "ff10bf",
"txhash": "dfc30a7df4cd7f105274ce5913b56e1fdb15f842d16259cac5e2142b8e328b72"
},
{
"codeseparator": null,
"id": "0:95 (ff10bf #1)",
"input": 1,
"txfs": "ff10bf",
"txhash": "fc7eb663ecafee91eaeb327be8ce4141eba15be928411b13b1145e825a25c7a5"
},
{
"codeseparator": null,
"id": "0:96 (ff20bf #0)",
"input": 0,
"txfs": "ff20bf",
"txhash": "68ddc75edee9e075116b3a92da91934b873bc5319b7d843964a1bdbbcc98a3fc"
},
{
"codeseparator": null,
"id": "0:97 (ff20bf #1)",
"input": 1,
"txfs": "ff20bf",
"txhash": "70b258975fd720f72300eb935e9ad1d6cb627201535d205ea2547f6379290f2c"
},
{
"codeseparator": null,
"id": "0:98 (ff3fbf #0)",
"input": 0,
"txfs": "ff3fbf",
"txhash": "af99fb1bb1d843814f205517718b70ff2729c3cc0169e97863d4de1b5f97d102"
},
{
"codeseparator": null,
"id": "0:99 (ff3fbf #1)",
"input": 1,
"txfs": "ff3fbf",
"txhash": "d51e4053eae324623ac8b45e6c756f54dc4f674c9024b1739976e481b58e4c29"
},
{
"codeseparator": null,
"id": "0:100 (ffff3f3f #0)",
"input": 0,
"txfs": "ffff3f3f",
"txhash": "2b8b2247712581368099f351dc3c3fea0ee5a46158c2ab8ea023dfd02483656e"
},
{
"codeseparator": null,
"id": "0:101 (ffff3f3f #1)",
"input": 1,
"txfs": "ffff3f3f",
"txhash": "efc150fc72f4d9ade4c88c6bf507c85abcac3c09e6ffb6e57e2b372460a9b58b"
},
{
"codeseparator": null,
"id": "0:102 (ffff4040 #0)",
"input": 0,
"txfs": "ffff4040",
"txhash": "bbc351d3a61ff0531c48883202c347ba6e2e889d0dae526cc302a8978f54194f"
},
{
"codeseparator": null,
"id": "0:103 (ffff4040 #1)",
"input": 1,
"txfs": "ffff4040",
"txhash": "56789e76148add29a6e11a71f9eee1d587967f475a7b7adead3a38aad9753070"
},
{
"codeseparator": null,
"id": "0:104 (ff008080 #0)",
"input": 0,
"txfs": "ff008080",
"txhash": "fc87d178387418de163b5cf92d7ec20236bc4e64d8013926e8202d7ffd35eaff"
},
{
"codeseparator": null,
"id": "0:105 (ff008080 #1)",
"input": 1,
"txfs": "ff008080",
"txhash": "ef7074fa8f70e1c36b9c392afdca434320e9fd58a8e35a5b7722fb832f11cb15"
},
{
"codeseparator": null,
"id": "0:106 (ffffbfbf #0)",
"input": 0,
"txfs": "ffffbfbf",
"txhash": "d872d9eda08df40dc5a6761f90d886720c24b392307df90c00d1647902967ca7"
},
{
"codeseparator": null,
"id": "0:107 (ffffbfbf #1)",
"input": 1,
"txfs": "ffffbfbf",
"txhash": "b3d3393fd149ec4bb0ecf50119f36ba0621259b6d6288d9a2e8b8332bc75bcd7"
},
{
"codeseparator": null,
"id": "0:108 (ffffc0c0 #0)",
"input": 0,
"txfs": "ffffc0c0",
"txhash": "addc2bf0570b09cf5dae3b8535158261e3e7c91db0fb313133343763cd3958dd"
},
{
"codeseparator": null,
"id": "0:109 (ffffc0c0 #1)",
"input": 1,
"txfs": "ffffc0c0",
"txhash": "66e8cf6e41e1f2963d4dd1a78d3e19318b27f34abc5011ef6359ecf5151ab812"
},
{
"codeseparator": null,
"id": "0:110 (ffff403f #0)",
"input": 0,
"txfs": "ffff403f",
"txhash": "9413abd29279ea6ad5a0675d1007ccd3d6d61ef6633eb9415961282f271d6c31"
},
{
"codeseparator": null,
"id": "0:111 (ffff403f #1)",
"input": 1,
"txfs": "ffff403f",
"txhash": "8cd9e9133c585c31e207db07732fb5f6a3c392118c90b4d20e9e7dd470dc38ed"
},
{
"codeseparator": null,
"id": "0:112 (ffff3f40 #0)",
"input": 0,
"txfs": "ffff3f40",
"txhash": "404f72fe8f7365a27bc5b1c496dd11a689a2f7d0f3b7b3c9755a8f7bf11d7b89"
},
{
"codeseparator": null,
"id": "0:113 (ffff3f40 #1)",
"input": 1,
"txfs": "ffff3f40",
"txhash": "59628e1df03ce68564e9035f376ac9c76f7a11d5b1b0b71c5a593da5b4cf5c6d"
},
{
"codeseparator": null,
"id": "0:114 (ffff0182 #0)",
"input": 0,
"txfs": "ffff0182",
"txhash": "ab8c241a251a98288b1758710961c0924e1c27b0df974cd669b2e154101e36b5"
},
{
"codeseparator": null,
"id": "0:115 (ffff0182 #1)",
"input": 1,
"txfs": "ffff0182",
"txhash": "eb561e62a71274921a7e0025e66c51299d1904cfba98debb4a23cee2f49f9209"
},
{
"codeseparator": null,
"id": "0:116 (ffffc002 #0)",
"input": 0,
"txfs": "ffffc002",
"txhash": "d5c3e2f80a574f8f80c016c2ddd4bee2298f4e91a49d07fbf2ff96ee1ebdbbc2"
},
{
"codeseparator": null,
"id": "0:117 (ffffc002 #1)",
"input": 1,
"txfs": "ffffc002",
"txhash": "99efebafd498376dfced0515ae0d1949cb7673bff30bd73a693011edf1541db6"
},
{
"codeseparator": null,
"id": "0:118 (ffff4101420002 #0)",
"input": 0,
"txfs": "ffff4101420002",
"txhash": "72f86b1e8e4721e3aa8c4ddfc744e93e2f4628fe63116e1c592449608077d0ea"
},
{
"codeseparator": null,
"id": "0:119 (ffff4101420002 #1)",
"input": 1,
"txfs": "ffff4101420002",
"txhash": "6dfab74a32a90fd024f5faeab5935486de4c07b76ac788f3a80fb4e426e63dfc"
},
{
"codeseparator": null,
"id": "0:120 (ffffc101c20002 #0)",
"input": 0,
"txfs": "ffffc101c20002",
"txhash": "8bcbd63009fea26f96e1736f2f2b517c7274feef626b3d9524e2dce22b81ec97"
},
{
"codeseparator": null,
"id": "0:121 (ffffc101c20002 #1)",
"input": 1,
"txfs": "ffffc101c20002",
"txhash": "d801364c0d3d9468c17101f1906e89e84d0e325d904ce54a1305885296228055"
},
{
"codeseparator": null,
"id": "0:122 (ffff617f627f00 #1)",
"input": 1,
"txfs": "ffff617f627f00",
"txhash": "a6eab06ad0e6053b0221d50463c6fa5c87dd4926bdff88dfbaae60147fa91beb"
},
{
"codeseparator": null,
"id": "0:123 (ffffe17fe27f00 #1)",
"input": 1,
"txfs": "ffffe17fe27f00",
"txhash": "9f5dee0abdcbdfc6016e7186ad639b50728771eebbd7464e3ba0b5d8f3ef68ea"
},
{
"codeseparator": null,
"id": "0:124 ( #0)",
"input": 0,
"txfs": "",
"txhash": "a1601773a4ddd7a2a1117fffaa670bd67fb3b85f91e2793e25de8c4f848fe0d9"
},
{
"codeseparator": null,
"id": "0:125 ( #1)",
"input": 1,
"txfs": "",
"txhash": "6ae6fe854e08cbf0a25636b575d8bbe63c120ba496796dd30b4924b79f909fbd"
},
{
"codeseparator": null,
"id": "0:126 (ff #0)",
"input": 0,
"txfs": "ff",
"txhash": "45da8ae2f210c2d6985d5c3e1067817838273495da515941e18fa554dc5e740d"
},
{
"codeseparator": null,
"id": "0:127 (ff #1)",
"input": 1,
"txfs": "ff",
"txhash": "335bfdcf79f6ae2ccb7d4972e26106f043813de634ba9a752b4808192f5e8c38"
},
{
"codeseparator": null,
"id": "0:128 (f7 #0)",
"input": 0,
"txfs": "f7",
"txhash": "bba33c04d64d580f27ef181c3482ed7243212176a721613f522415234b194df6"
},
{
"codeseparator": null,
"id": "0:129 (f7 #1)",
"input": 1,
"txfs": "f7",
"txhash": "13b100680de28fd5d7ecd40389c49add2298ea464152c06b859150e7018ea9e6"
},
{
"codeseparator": null,
"id": "0:130 (f3 #0)",
"input": 0,
"txfs": "f3",
"txhash": "27163ce496cf96f4dd5a0dc275ed3aeb4f13fac742011ae657c64536b7523896"
},
{
"codeseparator": null,
"id": "0:131 (f3 #1)",
"input": 1,
"txfs": "f3",
"txhash": "4f45f4c2a2390634e6591cffba66bec810fa17c88734fedc6ce974f765533771"
},
{
"codeseparator": null,
"id": "0:132 (fd #0)",
"input": 0,
"txfs": "fd",
"txhash": "66b2523a0e8ccc2388b401043dcd08bcd9848ce07ba90309a3194a88cceefc58"
},
{
"codeseparator": null,
"id": "0:133 (fd #1)",
"input": 1,
"txfs": "fd",
"txhash": "bf51c6a7993a1abc7f62d92ceb1abaf03ce10df620cab77a9c68bc8b2d993768"
},
{
"codeseparator": null,
"id": "0:134 (f5 #0)",
"input": 0,
"txfs": "f5",
"txhash": "4ac1bd781328f1a24dc514d686b1c0ea78ca28bf4b37e60472f98e9b1c07568c"
},
{
"codeseparator": null,
"id": "0:135 (f5 #1)",
"input": 1,
"txfs": "f5",
"txhash": "be93ef8b84789a7e522f73bb3c0c00afe91075e3a02dc82fb766f31a5e2810db"
},
{
"codeseparator": null,
"id": "0:136 (f1 #0)",
"input": 0,
"txfs": "f1",
"txhash": "0d09ed34a6bf5fbb8d447549c88a9aba198498f8351ddc32c89450cb8e2be34a"
},
{
"codeseparator": null,
"id": "0:137 (f1 #1)",
"input": 1,
"txfs": "f1",
"txhash": "38d07d3216b3a2096ac879292cc4d2eca1eee87c3a8ed0d4e53b11adda28d7b6"
},
{
"codeseparator": null,
"id": "0:138 (ed #0)",
"input": 0,
"txfs": "ed",
"txhash": "4978bd282206c9ad2f781e0ca252e9a37e4a366ca619c09c0a1d37028c8f7f28"
},
{
"codeseparator": null,
"id": "0:139 (ed #1)",
"input": 1,
"txfs": "ed",
"txhash": "009af4edad039ac16da71104b4fdd715a8068a56bd5b27e08a7a5c1eedbfb4e4"
},
{
"codeseparator": null,
"id": "0:140 (e5 #0)",
"input": 0,
"txfs": "e5",
"txhash": "83dc16b7f5dc131be5b21057a9a411e24a773579e5777953598ccfeee3bebcaa"
},
{
"codeseparator": null,
"id": "0:141 (e5 #1)",
"input": 1,
"txfs": "e5",
"txhash": "a5a38488a0ac5600cb790ebc61200e92e4bd2421f0e9cb412e53634efdb4f014"
},
{
"codeseparator": null,
"id": "0:142 (e1 #0)",
"input": 0,
"txfs": "e1",
"txhash": "bcc69369370c5083a378d0c9d6501f30bf61bc9c2e53ca0703d4da81b629ea37"
},
{
"codeseparator": null,
"id": "0:143 (e1 #1)",
"input": 1,
"txfs": "e1",
"txhash": "8746f7789df6c561577f84965b6db3a12eb8f66f34af3006713fef6db9620455"
},
{
"codeseparator": null,
"id": "0:144 (cd #0)",
"input": 0,
"txfs": "cd",
"txhash": "4b75f5635bbceb991d5c3f9c0c2a3d367a9b6b12cb150b0db632e2a8d81e337c"
},
{
"codeseparator": null,
"id": "0:145 (cd #1)",
"input": 1,
"txfs": "cd",
"txhash": "e48d0a29d86078a17a9283f6f1c314499eab7343855f4b9f7140c68d4b346b9f"
},
{
"codeseparator": null,
"id": "0:146 (c5 #0)",
"input": 0,
"txfs": "c5",
"txhash": "6f774daf5b1b163f35b4ca367df2798aa8e66c2ff30b77ea9f2e98a5db2b0ec6"
},
{
"codeseparator": null,
"id": "0:147 (c5 #1)",
"input": 1,
"txfs": "c5",
"txhash": "b21e18937bbfadfb37ef10ebf9dacff13801503e475f2524e9c3bb620c0c1567"
},
{
"codeseparator": null,
"id": "0:148 (c1 #0)",
"input": 0,
"txfs": "c1",
"txhash": "4f3d9c36d74b027ce9487907e36a59076f6a6760c7c5902b4dccac1199379a05"
},
{
"codeseparator": null,
"id": "0:149 (c1 #1)",
"input": 1,
"txfs": "c1",
"txhash": "f6abfe1167fecd2809b28fb8d3b0fc98829c49a8f80f47492a0a910ff5799aa5"
}
]
}
]
================================================
FILE: bip-0346.md
================================================
```
BIP: 346
Layer: Consensus (soft fork)
Title: OP_TXHASH
Authors: Steven Roose
Brandon Black
Status: Draft
Type: Specification
Assigned: 2024-04-24
License: BSD-3-Clause
```
# Abstract
This BIP proposes a new opcode `OP_TXHASH`, to be activated as a change to the
semantics of `OP_SUCCESS189` in tapscript contexts.
This opcode provides a generalized method for introspecting certain details of
the spending transaction, which enables non-interactive enforcement of certain
properties of the transaction spending a certain UTXO.
Together with an opcode like `OP_CHECKSIGFROMSTACK`, this opcode effectively
provides a fully generalized signature hash construction, fully supporting
all existing SIGHASH flags, the proposed sighash flags from
[BIP-118](bip-0118.mediawiki) (`SIGHASH_ANYPREVOUT`) and many other new signature hash
combinations.
The constructions specified in this BIP also open up the way for other
potential updates; see Motivation section for more details.
# Specification
## OP_TXHASH
`OP_TXHASH` redefines the `OP_SUCCESS189` tapscript opcode (`0xbd`) as a soft
fork upgrade. This opcode is only active in tapscript contexts.
Note that `OP_SUCCESS187` is used by [BIP-443](bip-0443.mediawiki) (`OP_CHECKCONTRACTVERIFY`) and
`OP_SUCCESS188` was used by [BIP-345](bip-0345.mediawiki) (`OP_VAULT`) at the time of first draft
of this BIP, making `OP_SUCCESS189` the next available opcode for this purpose.
It has the following semantics:
* There is at least one element on the stack, fail otherwise.
* The element is interpreted as the TxFieldSelector and is popped off the stack.
* The TxFieldSelector must be valid, fail otherwise.
* The 32-byte TxHash of the transaction at the current input index, calculated
using the given TxFieldSelector is pushed onto the stack.
## TxFieldSelector
The TxFieldSelector has the following encoding. We will give a brief conceptual
summary, followed by a reference implementation of the CalculateTxHash function.
In the following specifications, the `|` operator is used for the bitwise OR
operation.
* There are two special cases for the TxFieldSelector:
* the empty value, zero bytes long: it is set equal to `TXFS_SPECIAL_TEMPLATE`,
the de-facto default value which means everything except the prevouts and
the prevout scriptPubkeys and amounts.
Special case `TXFS_SPECIAL_TEMPLATE` is 4 bytes long, as follows:
* 1: `TXFS_VERSION | TXFS_LOCKTIME | TXFS_CURRENT_INPUT_IDX`
* 2: `TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS | TXFS_OUTPUTS_ALL`
* 3: `TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL`
* 4: `TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL`
* If the TxFieldSelector has exactly 1 byte, we use a _short notation_.
It has its 8 bits assigned as follows, from lowest to highest:
* 2/1: Inputs
* 00: `TXFS_INOUT_SELECTION_NONE`
* 01: `TXFS_INOUT_SELECTION_CURRENT`
* 11: `TXFS_INOUT_SELECTION_ALL`
* 4/3: Outputs
* 00: `TXFS_INOUT_SELECTION_NONE`
* 01: `TXFS_INOUT_SELECTION_CURRENT`
* 11: `TXFS_INOUT_SELECTION_ALL`
* 5: `TXFS_INPUTS_PREVOUTS`
* 6: `TXFS_INPUTS_PREV_SCRIPTPUBKEYS | TXFS_INPUTS_PREV_VALUES`
* 7: `TXFS_CURRENT_INPUT_CONTROL_BLOCK | TXFS_CURRENT_INPUT_SPENTSCRIPT | TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS`
* 8: `TXFS_CURRENT_INPUT_IDX`
Additionally, it includes `TXFS_VERSION | TXFS_LOCKTIME | TXFS_CONTROL | TXFS_CURRENT_INPUT_TAPROOT_ANNEX`
as global fields and `TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS | TXFS_OUTPUTS_ALL`
as input and output fields.
These 1-byte selections allow the TxFieldSelector to emulate current
signature hashing modes and those defined in [BIP-118](bip-0118.mediawiki):
| BIP-341/118 sighash type | 1-byte TxFieldSelector |
| :--------------------------- | :--------------------- |
| `ALL` | `0b11111111` |
| `SINGLE` | `0b11110111` |
| `NONE` | `0b11110011` |
| `ALL\|ANYONECANPAY` | `0b11111101` |
| `SINGLE\|ANYONECANPAY` | `0b11110101` |
| `NONE\|ANYONECANPAY` | `0b11110001` |
| `ALL\|ANYPREVOUT` | `0b11101101` |
| `SINGLE\|ANYPREVOUT` | `0b11100101` |
| `NONE\|ANYPREVOUT` | `0b11100001` |
| `ALL\|ANYPREVOUTANYSCRIPT` | `0b11001101` |
| `SINGLE\|ANYPREVOUTANYSCRIPT`| `0b11000101` |
| `NONE\|ANYPREVOUTANYSCRIPT` | `0b11000001` |
* If the TxFieldSelector is longer than one byte, the first byte of the TxFieldSelector
has its 8 bits assigned as follows, from lowest to highest:
* 1: version (`TXFS_VERSION`)
* 2: locktime (`TXFS_LOCKTIME`)
* 3: current input index (`TXFS_CURRENT_INPUT_IDX`)
* 4: current input control block (`TXFS_CURRENT_INPUT_CONTROL_BLOCK`)
* 5: current input spent script (`TXFS_CURRENT_INPUT_SPENTSCRIPT`)
* 6: current script last `OP_CODESEPARATOR` position (or 0xffffffff)
(`TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS`)
* 7: current input annex including prefix byte (or empty) (`TXFS_CURRENT_INPUT_TAPROOT_ANNEX`)
* 8: `TXFS_CONTROL` (i.e. include TxFieldSelector into hash)
* The highest bit of the first byte (`TXFS_CONTROL`), we will call the
"control bit", and it can be used to control the behavior of the opcode. For
`OP_TXHASH`, the control bit is used to determine
whether the TxFieldSelector itself has to be included in the resulting hash.
(For potential other uses of the TxFieldSelector (like a hypothetical
`OP_TX`), this bit can be repurposed.)
* The second byte will be used to indicate fields from the inputs and outputs.
The 8 bits are assigned the following variables, from lowest to highest:
* Specifying which fields of the inputs will be selected:
* 1: prevouts (`TXFS_INPUTS_PREVOUTS`)
* 2: sequences (`TXFS_INPUTS_SEQUENCES`)
* 3: scriptSigs (`TXFS_INPUTS_SCRIPTSIGS`)
* 4: prevout scriptPubkeys (`TXFS_INPUTS_PREV_SCRIPTPUBKEYS`)
* 5: prevout values (`TXFS_INPUTS_PREV_VALUES`)
* 6: taproot annexes (`TXFS_INPUTS_TAPROOT_ANNEXES`)
* Specifying which fields of the outputs will be selected:
* 7: scriptPubkeys (`TXFS_OUTPUTS_SCRIPTPUBKEYS`)
* 8: values (`TXFS_OUTPUTS_VALUES`)
* We define as follows:
* `TXFS_ALL = TXFS_VERSION | TXFS_LOCKTIME | TXFS_CURRENT_INPUT_IDX | TXFS_CURRENT_INPUT_CONTROL_BLOCK | TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS | TXFS_CONTROL`
* `TXFS_INPUTS_ALL = TXFS_INPUTS_PREVOUTS | TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS | TXFS_INPUTS_PREV_SCRIPTPUBKEYS | TXFS_INPUTS_PREV_VALUES | TXFS_INPUTS_TAPROOT_ANNEXES`
* `TXFS_OUTPUTS_ALL = TXFS_OUTPUTS_SCRIPTPUBKEYS | TXFS_OUTPUTS_VALUES`
* For both inputs and then outputs, expect an additional byte as follows:
* The highest bit (`TXFS_INOUT_NUMBER`) indicates whether the "number of
in-/outputs" should be committed to.
* For the remaining bits, there are three exceptional values:
* 0x00 (`TXFS_INOUT_SELECTION_NONE`) means "no in/outputs" (hence only the
number of them as `0x80` (`TXFS_INOUT_NUMBER`)).
* `0x40` (`TXFS_INOUT_SELECTION_CURRENT`) means "select only the in/output
of the current input index" (it is invalid when current index exceeds
number of outputs).
* `0x3f` (`TXFS_INOUT_SELECTION_ALL`) means "select all in/outputs".
* The second highest bit (`TXFS_INOUT_SELECTION_MODE`) is the "specification mode":
* Set to 0 it means "leading mode".
* Set to 1 it means "individual mode".
* In "leading mode", the third highest bit (`TXFS_INOUT_LEADING_SIZE`) is
used to indicate the "index size", i.e. the number of bytes will be used to
represent the number of in/output.
* With "index size" set to 0, the remaining lowest 5 bits of the first byte
will be interpreted as the number of leading in/outputs to select.
* With "index size" set to 1, the remaining lowest 5 bits of the first byte
together with the 8 bits of the next byte will be interpreted as the
number of leading in/outputs to select.
* In "individual mode", the third highest bit (`TXFS_INOUT_INDIVIDUAL_MODE`)
indicates whether we are passing absolute indices (0) or indices relative
to the current input (1), the remaining lowest 5 bits will be interpreted
as `n`, the number of individual in/outputs follow.
* In absolute mode (second highest bit is 0), for each of the `n` indices,
at least one extra byte is expected.
* If that byte's highest bit is set to 0, the remaining 7 bits represent
the absolute index to select.
* If that byte's highest bit is set to 1, the remaining 7 bits, together
with the next byte's 8 bits represent the absolute index to select.
* In relative mode (second highest bit is 1), for each of the `n` indices,
at least one extra byte is expected.
* If that byte's highest bit is set to 0, the remaining 7 bits represent
the relative index in two's complement.
* If that byte's highest bit is set to 1, the remaining 7 bits, together
with the next byte's 8 bits represent the relative index in two's
complement.
Effectively, this allows a user to select
* all in/outputs
* the current input index
* the leading in/outputs up to 8,191
* up to 32 individually selected in/outputs
** using absolute indices up to 32,767
** using indices relative to the current input index from -16382 to +16383.
### TxFieldSelector malleability
It is possible to represent the same selected data using multiple different
TxFieldSelectors. For this reason, users are advised to always set the
`TXFS_CONTROL` field flag that commits to the TxFieldSelector that was used
to get the hash.
### Visualization
* first byte
```
1 1 1 1 1 1 1 1
| | | | | | | ^ version
| | | | | | ^ locktime
| | | | | ^ current input index
| | | | ^ current input control block
| | | ^ current input spent script
| | ^ current script last OP_CODESEPARATOR
| ^ current input taproot annex
^ control bit (ie. include TXFS in hash)
```
* second byte
```
<-> outputs
| | <---------> inputs
1 1 1 1 1 1 1 1
| | | | | | | ^ prevouts
| | | | | | ^ sequences
| | | | | ^ scriptSigs
| | | | ^ prevout scriptPubkeys
| | | ^ prevout values
| | ^ taproot annexes
| ^ scriptPubkeys
^ values
```
* in/output selector byte
"leading 3 in/outputs"
```
1 0 0 0 0 0 1 1
| | | <-------> integer 0b00011 == 3
| | ^ index size: single byte
| ^ leading mode
^ commit the number of in/outputs
```
"leading 257 in/outputs"
```
1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1
| | | <------------------------> integer 0b00001 00000001 == 257
| | ^ index size 1: two bytes
| ^ leading mode
^ commit the number of in/outputs
```
"indices 1 and 3"
```
0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1
| | | | <--------------> second idx: 3
| | | | <-------------> first idx: 1
| | | | <-----> selection count: 0b0010 == 2 indices
| | | ^ index size: single byte per index
| | ^ absolute index
| ^ individual mode
^ don't commit the number of in/outputs
```
* total example
```
ff ff c2 01 03 83
| | ^ commit number of outputs + leading 3 outputs
| | <------> commit number of inputs + inputs at indices 1 and 3
| ^ all input and output fields
^ all regular fields
```
## Resource limits
Using the same validation budget ("sigops budget") introduced in BIP-0342,
each TransactionHash decreases the validation budget by 25. If this brings the
budget below zero, the script fails immediately. The following
considerations should be made:
* All fields that can be of arbitrary size are cacheable as TransactionHash
always hashes their hashed values.
* In "individual mode", a user can at most commit 32 inputs or outputs,
which we don't consider excessive for potential repeated use.
* In "leading mode", a caching strategy can be used where the SHA256 context
is stored every N in/outputs so that multiple executions of the
TransactionHash function can use the caches and only have to hash an
additional N-1 items at most.
# Motivation
This BIP specifies a basic transaction introspection primitive that is useful
to either reduce interactivity in multi-user protocols or to enforce some basic
constraints on transactions.
Additionally, the constructions specified in this BIP can lay the groundwork for
some potential future upgrades:
* The TxFieldSelector construction would work well with a hypothetical opcode
`OP_TX` that allows for directly introspecting the transaction by putting the
fields selected on the stack instead of hashing them together.
* The TransactionHash obtained by `OP_TXHASH` can be combined with `OP_CHECKSIGFROMSTACK`
(see [BIP-348](bip-0348.md)) to effectively create an
incredibly flexible signature hash, which would enable constructions like
`SIGHASH_ANYPREVOUT`.
* The TransactionHash obtained by `OP_TXHASH` can be introduced as a native
sighash calculation in a future segwit upgrade, so that signatures using the
TransactionHash as their sighash can be used in keyspend context.
## Comparing with some alternative proposals
* This proposal strictly generalizes BIP-119's `OP_CHECKTEMPLATEVERIFY`, as the
default mode of our TxFieldSelector is semantically the same (though not
byte-for-byte identical) as what `OP_CTV` accomplishes, without costing any
additional bytes. Additionally, using `OP_TXHASH` allows for more
flexibility which can help in the case for
* enabling adding fees to a transaction without breaking a multi-tx protocol;
* multi-user protocols where users are only concerned about their own inputs and outputs.
* Constructions like `OP_IN_OUT_VALUE` used with `OP_EQUALVERIFY` can be
emulated by two `OP_TXHASH` instances by using the TxFieldSelector to select
a single input value first and a single output value second and enforcing
equality on the hashes. Neither of these alternatives can be used to enforce
small value differences without the availability of 64-bit arithmetic in
Script.
* Like mentioned above, `SIGHASH_ANYPREVOUT` can be emulated using `OP_TXHASH`
when combined with `OP_CHECKSIGFROMSTACK`:
` OP_TXHASH OP_CHECKSIGFROMSTACK` effectively emulates `SIGHASH_ANYPREVOUT`.
# Reference Implementation
A reference implementation in Rust is provided attached as part of this BIP
together with a JSON file of test vectors generated using the reference
implementation.
# Design Considerations
This specification in in _Draft_ and there is definitely still room for feedback
and improvements. Some considerations that were made but could be revisited:
- The `0b10` in/output selector for the shorthand is unused.
Could possibly be filled in with "current + next", "current + previous" or
any other semantics.
- The individual index selection semantics allow for absolute indices up to ~32k
and relative ones up to +/- ~16k, which is probably excessive. When removing
the second byte there would reduce that to just 256 and +/- 128 respectively.
- Similar to `OP_TEMPLATEHASH` (BIP number to be assigned, [PR](https://github.com/bitcoin/bips/pull/1974)),
we could not support `scriptSigs` anymore and remove
`TXFS_INPUTS_SCRIPTSIGS`. This field could then possibly be repurposed.
# Backwards Compatibility
`OP_TXHASH` replaces `OP_SUCCESS189`. The `SUCCESS` opcodes were
introduced in taproot (BIP-342) to support changing the semantics of opcodes in
ways that do allow the new semantics to change the stack. For this reason,
`OP_TXHASH` only works in tapscript context. Since it is overriding a `SUCCESS`
opcode, any older version of the software will always accept any script that
uses the opcode, while the new versions of the software will validate the
scripts according to the semantics outlined in this BIP. As such, this is also a
soft fork change.
## Interactions with other BIPs
This proposal interacts with several other BIPs:
* **[BIP-118](bip-0118.mediawiki) (SIGHASH_ANYPREVOUT)**: `OP_TXHASH` can be combined with
`OP_CHECKSIGFROMSTACK` (BIP-348) to emulate `SIGHASH_ANYPREVOUT` and other
signature hash modes defined in BIP-118. The 1-byte TxFieldSelector format
explicitly supports these modes.
* **[BIP-119](bip-0119.mediawiki) (OP_CHECKTEMPLATEVERIFY)**: `OP_TXHASH` with the empty
TxFieldSelector produces a hash semantically equivalent to BIP-119's
`OP_CHECKTEMPLATEVERIFY`, making this proposal a generalization of BIP-119.
* **[BIP-347](bip-0347.mediawiki) (OP_CAT)**: When combined with `OP_CAT`, `OP_TXHASH` enables
powerful transaction introspection capabilities. The bit encoding format is
designed to be explicit about endianness to ensure correct interaction with
concatenation operations.
* **[BIP-348](bip-0348.md) (OP_CHECKSIGFROMSTACK)**: Together with `OP_CHECKSIGFROMSTACK`,
`OP_TXHASH` provides a fully generalized signature hash construction,
enabling flexible covenant designs and multi-user protocols.
# Implementation
A reference implementation is included as part of the BIP, see
[here](./bip-0346/ref-impl/src/main.rs). This implementation focusses on clarity
and correctness, not on efficiency. A rudimentary set of test vectors is also
generated from this implementation and included
[here](./bip-0346/ref-impl/txhash_vectors.json).
Furthermore, following other implementation attempts exist:
* A proposed implementation for Bitcoin Core is available here:
https://github.com/bitcoin/bitcoin/pull/29050
* A proposed implementation for rust-bitcoin is available here:
https://github.com/rust-bitcoin/rust-bitcoin/pull/2275
NOTE: These implementations are slightly outdated as they were made for an
earlier version of this specification. Updates are in progress.
Both of the above implementations perform effective caching to avoid potential
denial-of-service attack vectors.
# Deployment
This BIP can be deployed using a BIP 9 VersionBits deployment. The specific
strategy and bit assignment are left unspecified and can later be amended to the
BIP depending on community preference.
# Acknowledgement
Credit for this proposal mostly goes to Jeremy Rubin for his work on BIP-119's
`OP_CHECKTEMPLATEVERIFY` and to Russell O'Connor for the original idea of
generalizing `OP_CHECKTEMPLATEVERIFY` into `OP_TXHASH`.
Additional thanks to Andrew Poelstra, Greg Sanders, Rearden Code, Rusty Russell
and others for their feedback on the specification.
# Copyright
This document is licensed under the 3-clause BSD license.
================================================
FILE: bip-0347.mediawiki
================================================
==Abstract==
This BIP introduces OP_CAT as a tapscript opcode which allows the concatenation of two values on the stack. OP_CAT would be activated via a soft fork by redefining the opcode OP_SUCCESS126 (126 in decimal and 0x7e in hexadecimal). This is the same opcode value used by the original OP_CAT.
== Copyright ==
This document is licensed under the 3-clause BSD license.
==Specification==
When evaluated, the OP_CAT instruction:
# Pops the top two values off the stack,
# concatenates the popped values together in stack order,
# and then pushes the concatenated value on the top of the stack.
Given the stack ''[x1, x2]'', where ''x2'' is at the top of the stack, OP_CAT will push ''x1 || x2'' onto the stack. By ''||'' we denote concatenation. OP_CAT fails if there are fewer than two values on the stack or if a concatenated value would have a combined size greater than the maximum script element size of 520 bytes.
This opcode would be activated via a soft fork by redefining the tapscript opcode OP_SUCCESS126 (126 in decimal and 0x7e in hexadecimal) to OP_CAT.
==Motivation==
Bitcoin Tapscript lacks a general purpose way of combining objects on the stack, restricting the expressiveness and power of Tapscript. This prevents, among many other things, the ability to construct and evaluate merkle trees and other hashed data structures in Tapscript. OP_CAT, by adding a general purpose way to concatenate stack values, would overcome this limitation and greatly increase the functionality of Tapscript.
OP_CAT aims to expand the toolbox of the tapscript developer with a simple, modular, and useful opcode in the spirit of Unix R. Pike and B. Kernighan, "Program design in the UNIX environment", 1983, https://harmful.cat-v.org/cat-v/unix_prog_design.pdf. To demonstrate the usefulness of OP_CAT below we provide a non-exhaustive list of some usecases that OP_CAT would enable:
* Bitstream, a protocol for the atomic swap (fair exchange) of bitcoins for decryption keys, that enables decentralized file hosting systems paid in Bitcoin. While such swaps are currently possible on Bitcoin without OP_CAT, they require the use of complex and computationally expensive Verifiable Computation cryptographic techniques. OP_CAT would remove this requirement on Verifiable Computation, making such protocols far more practical to build in Bitcoin. R. Linus, "BitStream: Decentralized File Hosting Incentivised via Bitcoin Payments", 2023, https://robinlinus.com/bitstream.pdf
* Tree signatures provide a multisignature script whose size can be logarithmic in the number of public keys and can encode spend conditions beyond n-of-m. For instance a transaction less than 1KB in size could support tree signatures with up to 4,294,967,296 public keys. This also enables generalized logical spend conditions. P. Wuille, "Multisig on steroids using tree signatures", 2015, https://blog.blockstream.com/en-treesignatures/
* Post-Quantum Lamport signatures in Bitcoin transactions. Lamport signatures merely require the ability to hash and concatenate values on the stack. J. Rubin, "[bitcoin-dev] OP_CAT Makes Bitcoin Quantum Secure [was CheckSigFromStack for Arithmetic Values]", 2021, https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-July/019233.html It has been proposed that if ECDSA is broken or a powerful computer was on the horizon, there might be an effort to protect ownership of bitcoins by allowing people to mark their taproot outputs as "script-path only" and then move their coins into such outputs with a leaf in the script tree requiring a Lamport signature. It is an open question if a tapscript commitment would preserve the quantum resistance of Lamport signatures. Beyond this question, the use of Lamport Signatures in taproot outputs is unlikely to be quantum resistant even if the script spend-path is made quantum resistant. This is because taproot outputs can also be spent with a key. An attacker with a sufficiently powerful quantum computer could bypass the taproot script spend-path by finding the discrete log of the taproot output and thus spending the output using the key spend-path. The use of "Nothing Up My Sleeve" (NUMS) points as described in [[bip-0341.mediawiki|BIP341]] to disable the key spend-path does not disable the key spend-path against a quantum attacker as NUMS relies on the hardness of finding discrete logs. We are not aware of any mechanism which could disable the key spend-path in a taproot output without a softfork change to taproot.
* Non-equivocation contracts T. Ruffing, A. Kate, D. Schröder, "Liar, Liar, Coins on Fire: Penalizing Equivocation by Loss of Bitcoins", 2015, https://web.archive.org/web/20221023121048/https://publications.cispa.saarland/565/1/penalizing.pdf in tapscript provide a mechanism to punish equivocation/double spending in Bitcoin payment channels. OP_CAT enables this by enforcing rules on the spending transaction's nonce. The capability is a useful building block for payment channels and other Bitcoin protocols.
* Vaults M. Moser, I. Eyal, and E. G. Sirer, Bitcoin Covenants, https://web.archive.org/web/20220203124718/https://fc16.ifca.ai/bitcoin/papers/MES16.pdf which are a specialized covenant that allows a user to block a malicious party who has compromised the user's secret key from stealing the funds in that output. As shown in A. Poelstra, "CAT and Schnorr Tricks II", 2021, https://www.wpsoftware.net/andrew/blog/cat-and-schnorr-tricks-ii.html OP_CAT is sufficient to build vaults in Bitcoin.
* Replicating CheckSigFromStack A. Poelstra, "CAT and Schnorr Tricks I", 2021, https://www.wpsoftware.net/andrew/blog/cat-and-schnorr-tricks-i.html which would allow the creation of simple covenants and other advanced contracts without having to presign spending transactions, possibly reducing complexity and the amount of data that needs to be stored. Originally shown to work with Schnorr signatures, this result has been extended to ECDSA signatures R. Linus, "Covenants with CAT and ECDSA", 2023, https://gist.github.com/RobinLinus/9a69f5552be94d13170ec79bf34d5e85#file-covenants_cat_ecdsa-md.
* OP_CAT would allow tapscript to perform arbitrary computation on stack elements larger than 32-bits such as signatures and public keys. While Collider Script E. Heilman, V. I. Kolobov, A. M. Levy, A. Poelstra, "ColliderScript: Covenants in Bitcoin via 160-bit hash collisions", 2024, https://eprint.iacr.org/2024/1802 showed that even without OP_CAT tapscript can perform arbitrary computation on stack elements larger than 32-bits, this approach is extremely computationally expensive. In practice, today's tapscript can only perform arbitrary computation on 32-bit stack elements. OP_CAT was not designed with this usecase in mind and OP_CAT an inefficient way to perform this task.
* BitVMR. Linus, L. Aumayr, A. Zamyatin, A. Pelosi, Z. Avarikioti, M. Maffei "BitVM2: Bridging Bitcoin to Second Layers", 2025, https://bitvm.org/bitvm_bridge.pdf improvements. OP_CAT would enable BitVM2 to eliminating the trusted setup from its proof system allow BitVM2 to reduce the size of transactions it uses.
OP_CAT was available in early versions of Bitcoin.
In 2010, a single commit disabled OP_CAT, along with another 15 opcodes.
Folklore states that OP_CAT was removed in this commit because it enabled the construction of a script whose evaluation could have memory usage exponential in the size of the script.
For example, a script that pushed a 1-byte value on the stack and then repeated the opcodes OP_DUP, OP_CAT 40 times would result in a stack element whose size was greater than 1 terabyte assuming no maximum stack element size. As Bitcoin at that time had a maximum stack element size of 5000 bytes, the effect of this expansion was limited to 5000 bytes.
This is no longer an issue because tapscript enforces a maximum stack element size of 520 bytes.
==Rationale==
Our decision to reenable OP_CAT by redefining a tapscript OP_SUCCESSx opcode to OP_CAT was motivated to leverage the tapscript softfork opcode upgrade path introduced in [[bip-0342.mediawiki|BIP342]].
We specifically choose to use OP_SUCCESS126 rather than another OP_SUCCESSx as OP_SUCCESS126 uses the same opcode value (126 in decimal and 0x7e in hexadecimal) that was used for OP_CAT prior to it being disabled in Bitcoin. This removes a potential source of confusion that would exist if we had a opcode value different from the one used in the original OP_CAT opcode.
While the OP_SUCCESSx opcode upgrade path could enable us to increase the stack element size while reenabling OP_CAT, we wanted to separate the decision to change the stack element size limit from the decision to reenable OP_CAT. This BIP takes no position in favor or against increasing the stack element size limit.
==Backwards Compatibility==
OP_CAT usage in a non-tapscript script will continue to trigger the SCRIPT_ERR_DISABLED_OPCODE. The only change would be to OP_CAT usage in tapscript. This change to tapscript would be activated as a soft fork that redefines an OP_SUCCESSx opcode (OP_SUCCESS126) to OP_CAT.
==Reference implementation==
The value of MAX_SCRIPT_ELEMENT_SIZE is 520.
This implementation is inspired by the original implementation of [https://github.com/bitcoin/bitcoin/blob/01cd2fdaf3ac6071304ceb80fb7436ac02b1059e/script.cpp#L381-L393 OP_CAT as it existed in the Bitcoin codebase] prior to the commit "misc changes" 4bd188cS. Nakamoto, "misc changes", Aug 25 2010, https://github.com/bitcoin/bitcoin/commit/4bd188c4383d6e614e18f79dc337fbabe8464c82#diff-27496895958ca30c47bbb873299a2ad7a7ea1003a9faa96b317250e3b7aa1fefR94 which disabled it:
An alternative implementation of OP_CAT can be found in Elements Roose S., Elements Project, "Re-enable several disabled opcodes", 2019, https://github.com/ElementsProject/elements/commit/13e1103abe3e328c5a4e2039b51a546f8be6c60a#diff-a0337ffd7259e8c7c9a7786d6dbd420c80abfa1afdb34ebae3261109d9ae3c19R740-R759.
==Test Vectors==
The following test vectors use Bitcoin-core JSON script-test format.
[
[
"78a11a1260c1101260",
"78a11a1260",
"c1101260",
"#SCRIPT# CAT EQUAL",
"#CONTROLBLOCK#",
0.00000001
],
"",
"0x51 0x20 #TAPROOTOUTPUT#",
"P2SH,WITNESS,TAPROOT,OP_CAT",
"OK",
"TAPSCRIPT CATs 78a11a1260 and c1101260 together and checks it is EQUAL to stack element 78a11a1260c1101260"
],
[
[
"51",
"bbbb",
"01",
"#SCRIPT# IF CAT ELSE DROP ENDIF",
"#CONTROLBLOCK#",
0.00000001
],
"",
"0x51 0x20 #TAPROOTOUTPUT#",
"P2SH,WITNESS,TAPROOT,OP_CAT",
"OK",
"TAPSCRIPT Tests CAT inside of an IF ELSE conditional (true IF)"
],
[
[
"",
"09ca7009ca7009ca7009ca7009ca70",
"#SCRIPT# CAT",
"#CONTROLBLOCK#",
0.00000001
],
"",
"0x51 0x20 #TAPROOTOUTPUT#",
"P2SH,WITNESS,TAPROOT,OP_CAT",
"OK",
"TAPSCRIPT (['', 09ca7009ca7009ca7009ca7009ca70], CAT) Tests CAT succeeds when one of the two values to concatenate is of size zero"
],
A full test suite with additional vectors can be found at the Bitcoin [https://github.com/bitcoin/bitcoin/pull/29247 OP_CAT PR].
==References==
==Changelog==
* __1.0.0__ (2026-03-01) - Marked as complete.
* __0.3.1__ (2026-01-23) - Made compliant with BIP 003, use cases added.
* __0.3.0__ (2024-05-06) - Merged to BIP repo
* __0.2.0__ (2024-04-24) - Assigned BIP number
* __0.1.0__ (2023-12-11) - Initial draft posted
May 6, 2024
==Acknowledgements==
We wish to acknowledge Dan Gould for encouraging and helping review this effort. We also want to thank Madars Virza, Jeremy Rubin, Andrew Poelstra, Bob Summerwill,
Tim Ruffing and Johan T. Halseth for their feedback, review and helpful comments.
================================================
FILE: bip-0348.md
================================================
```
BIP: 348
Layer: Consensus (soft fork)
Title: CHECKSIGFROMSTACK
Authors: Brandon Black
Jeremy Rubin
Status: Draft
Type: Specification
Assigned: 2024-11-26
License: BSD-3-Clause
```
## Abstract
This BIP describes a new opcode for the purpose of checking cryptographic
signatures in bitcoin scripts against data from the stack.
## Summary
When verifying taproot script spends having leaf version 0xc0 (as defined in
[BIP 342]), we propose `OP_CHECKSIGFROMSTACK` to replace `OP_SUCCESS204`
(0xcc).
`OP_CHECKSIGFROMSTACK` has semantics similar to `OP_CHECKSIG`, as specified
below. Briefly, it pops 3 elements from the stack: a 32-byte public key, a
message, and a signature. If the signature is valid for that public key and
message, 1 is pushed to the stack. If the signature is the empty vector, 0 is
pushed to the stack, and otherwise script execution fails.
Only 32-byte keys are constrained. Similar to [BIP 342] unknown key types, for
other key lengths no signature verification is performed and it is considered
successful.
## Specification
* If fewer than 3 elements are on the stack, the script MUST fail and terminate immediately.
* The public key (top element), message (second to top element), and signature (third from top element) are read from the stack.
* The top three elements are popped from the stack.
* If the public key size is zero, the script MUST fail and terminate immediately.
* If the public key size is 32 bytes, it is considered to be a public key as described in [BIP 340]:
* If the signature is not the empty vector, the signature is validated against the public key and message according to [BIP 340]. Validation failure in this case immediately terminates script execution with failure.
* If the public key size is not zero and not 32 bytes; the public key is of an unknown public key type. Signature verification for unknown public key types succeeds as if signature verification for a known public key type had succeeded.
* If the script did not fail and terminate before this step, regardless of the public key type:
* If the signature is the empty vector: An empty vector is pushed onto the stack, and execution continues with the next opcode.
* If the signature is not the empty vector:
* The opcode is counted towards the sigops budget as described in [BIP 342].
* A 1-byte value 0x01 is pushed onto the stack.
## Design Considerations
1. Message hashing: [BIP 340] is compatible with any size of message and does not require it to be a securely hashed input, so the message is not hashed prior to [BIP 340] verification.
2. Lack of verify semantics: Adding a single opcode for this purpose keeps the implementation and design simple. An earlier draft had a verify variant as a NOP upgrade, and if this functionality is later brought to legacy scripts, that would be a good time to add a verify variant.
3. Add/multisig: No concession is made to `OP_CHECKMULTISIG` or `OP_CHECKSIGADD` semantics with `OP_CHECKSIGFROMSTACK`. In Tapscript, add semantics can be implemented with 1 additional vByte per key (`OP_TOALTSTACK OP_CHECKSIGFROMSTACK OP_FROMALTSTACK OP_ADD`).
4. Splitting R/S on the stack: Implementing split/separate signatures is left as an exercise for other bitcoin upgrades, such as [BIP 347] (`OP_CAT`).
5. APO-style ([BIP 118]) Taproot internal key: Rather than introducing an additional key type in this change, we suggest implementing `OP_INTERNALKEY` ([BIP 349]) or separately introducing that key type for all Tapscript signature checking operations in a separate change.
## Resource Limits
These opcodes are treated identically to other signature checking opcodes and
count against the sigops and budget.
## Motivation
### LN Symmetry
When combined with [BIP 119] (`OP_CHECKTEMPLATEVERIFY`/CTV),
`OP_CHECKSIGFROMSTACK` (CSFS) can be used to implement Lightning Symmetry
channels. The construction `OP_CHECKTEMPLATEVERIFY
OP_CHECKSIGFROMSTACK` with a spend stack containing the CTV hash and a
signature for it is logically equivalent to ` OP_CHECKSIG` and
a signature over `SIGHASH_ALL|SIGHASH_ANYPREVOUTANYSCRIPT`. The
`OP_CHECKSIGFROMSTACK` construction is 8 vBytes larger.
Summary of alternatives:
* CTV+CSFS is the minimal functionality needed for Lightning Symmetry but requires the use of an `OP_RETURN` for data availability
* APO is the original design for Lightning Symmetry and uses the taproot annex for data availability.
* LNHANCE (CTV+CSFS+IKEY+PC) is the most efficient and direct way currently designed to implement Lightning Symmetry.
### Delegation
Using a script like:
` SWAP IF 2 PICK SWAP CSFS VERIFY ENDIF CHECKSIG`
either direct verification or delegation can be achieved by the following
unlock stacks: ` 0` or ` 1`
### Advanced delegation when combined with [OP_PAIRCOMMIT] or OP_CAT
Using a script like:
`CLTV OVER PAIRCOMMIT TOALT CHECKSIGVERIFY FROMALT CSFS`
or:
`CLTV SHA256 OVER CAT TOALT CHECKSIGVERIFY FROMALT CSFS`
with the unlock stack:
``
Delegates to a public key after a lock time, enabling delegation to various
keys after various associated times.
## Reference Implementation
A reference implementation is provided here:
https://github.com/bitcoin/bitcoin/pull/29270
## Backward Compatibility
By constraining the behavior of an OP_SUCCESS opcode,
deployment of the BIP can be done in a backwards compatible, soft-fork manner.
If anyone were to rely on the OP_SUCCESS behavior of
`OP_SUCCESS204`, `OP_CHECKSIGFROMSTACK` would invalidate
their spend.
## Deployment
TBD
## Credits
Reference implementation was made with reference to the implementation in
Elements and started by moonsettler.
## Copyright
This document is licensed under the 3-clause BSD license.
[BIP 119]: https://github.com/bitcoin/bips/blob/master/bip-0119.mediawiki
[BIP 118]: https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki
[BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
[BIP 342]: https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki
[BIP 349]: https://github.com/bitcoin/bips/blob/master/bip-0349.md
[BIP 347]: https://github.com/bitcoin/bips/blob/master/bip-0347.mediawiki
[OP_PAIRCOMMIT]: https://github.com/bitcoin/bips/pull/1699
[mailing list]: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-July/019192.html
================================================
FILE: bip-0349.md
================================================
```
BIP: 349
Layer: Consensus (soft fork)
Title: OP_INTERNALKEY
Authors: Brandon Black
Jeremy Rubin
Status: Draft
Type: Specification
Assigned: 2024-11-14
License: BSD-3-Clause
```
## Abstract
This BIP describes a new tapscript opcode (`OP_INTERNALKEY`) which
pushes the _taproot internal key_ to the stack.
## Specification
When verifying taproot script path spends having leaf version `0xc0` (as
defined in [BIP 342]), `OP_INTERNALKEY` replaces `OP_SUCCESS203` (0xcb).
`OP_INTERNALKEY` pushes the 32-byte x-only representation of the _taproot
internal key_ (referred to as _p_), as defined in [BIP 341], to the stack.
## Motivation
### Key spend with additional conditions
When building taproot outputs, especially those secured by an aggregate key
representing more than one signer, the parties may wish to collaborate on
signing with the _taproot internal key_, but only with additional script
restrictions. In this case, `OP_INTERNALKEY` saves 8 vBytes.
### Mitigated control block overhead for scripts using hash locks
In cases where key path spending is not desired, the internal key may be set to
a NUMS point whose bytes would otherwise be required in a tapscript. This could
be used with any hash locked transaction, for example, to save 8 vBytes.
Note: The internal key must be the X coordinate of a point on the SECP256K1
curve, so any such hash must be checked and modified until it is such an X
coordinate. This will typically take approximately 2 attempts.
### Re-Keying with Merkle Root Preservation
Consider a program such `CTV CSFS CLTV`. Such fragments are useful for LN-Symmetry applications.
Such a program would be embedded within a Taproot script path, such as `TR(X, {CTV CSFS CLTV})`.
Were the internal key to be updated from `X` to `Y`, the resulting program would be: `TR(Y, {CTV CSFS CLTV})`.
The key in the leaf and the key-path would be mismatched. Were `OP_INTERNALKEY` to be used,
the leaf would automatically re-key.
E.g., `TR(X, {CTV OP_INTERNALKEY CSFS CLTV})` is equivalent to `TR(X, {CTV CSFS CLTV})`
and `TR(Y, {CTV OP_INTERNALKEY CSFS CLTV})` is equivalent to `TR(Y, {CTV CSFS CLTV})`.
While this particular example is contrived, the general technique of using `OP_INTERNALKEY`
as updatable across an entire script tree is a helpful covenant primitive when it is desirable to
invalidate signatures from prior states. For example, the theoretical `OP_TAPLEAFUPDATEVERIFY` opcode
modifies the internal key directly to remove or add a participant, and `OP_INTERNALKEY` would ensure
that the tweaked key is used from all script paths where desired.
## Reference Implementation
A reference implementation is provided here:
https://github.com/bitcoin/bitcoin/pull/29269
## Backward Compatibility
By constraining the behavior of an OP_SUCCESS opcode, deployment of the BIP
can be done in a backwards compatible, soft-fork manner. If anyone were to
rely on the OP_SUCCESS behavior of `OP_SUCCESS203`, `OP_INTERNALKEY` would
invalidate their spend.
## Deployment
TBD
## Credits
The concept for INTERNALKEY first arose in a [discussion](https://gnusha.org/bitcoin-wizards/2022-01-05.log) between Russell O'Connor
and Jeremy Rubin in Bitcoin Wizards IRC, inspired by BIP-0118's key punning technique
for the internal key. It was later
drafted into this BIP by Brandon Black.
## Copyright
This document is licensed under the 3-clause BSD license.
[BIP 341]: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki
[BIP 342]: https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki
================================================
FILE: bip-0350.mediawiki
================================================
BIP: 350
Layer: Applications
Title: Bech32m format for v1+ witness addresses
Authors: Pieter Wuille
Status: Deployed
Type: Specification
Assigned: 2020-12-16
License: BSD-2-Clause
Discussion: 2021-01-05: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018338.html [bitcoin-dev] Bech32m BIP: new checksum, and usage for segwit address
Replaces: 173
==Introduction==
===Abstract===
This document defines an improved variant of Bech32 called '''Bech32m''', and amends BIP173 to use Bech32m for native segregated witness outputs of version 1 and later. Bech32 remains in use for segregated witness outputs of version 0.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
[[bip-0173.mediawiki|BIP173]] defined a generic checksummed base 32 encoded format called Bech32. It is in use for segregated witness outputs of version 0 (P2WPKH and P2WSH, see [[bip-0141.mediawiki|BIP141]]), and other applications.
Bech32 has an unexpected [https://github.com/sipa/bech32/issues/51 weakness]: whenever the final character is a 'p', inserting or deleting any number of 'q' characters immediately preceding it does not invalidate the checksum. This does not affect existing uses of witness version 0 BIP173 addresses due to their restriction to two specific lengths, but may affect future uses and/or other applications using the Bech32 encoding.
This document addresses that by specifying Bech32m, a variant of Bech32 that mitigates this insertion weakness and related issues.
==Specification==
We first specify the new checksum algorithm, and then document how it should be used for future Bitcoin addresses.
===Bech32m===
Bech32m modifies the checksum of the Bech32 specification, replacing the constant ''1'' that is xored into the checksum at the end with ''0x2bc830a3''. The resulting checksum verification and creation algorithm (in Python, cf. the code in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#Bech32|BIP173 Bech32 section]):
BECH32M_CONST = 0x2bc830a3
def bech32m_polymod(values):
GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
chk = 1
for v in values:
b = (chk >> 25)
chk = (chk & 0x1ffffff) << 5 ^ v
for i in range(5):
chk ^= GEN[i] if ((b >> i) & 1) else 0
return chk
def bech32m_hrp_expand(s):
return [ord(x) >> 5 for x in s] + [0] + [ord(x) & 31 for x in s]
def bech32m_verify_checksum(hrp, data):
return bech32m_polymod(bech32m_hrp_expand(hrp) + data) == BECH32M_CONST
def bech32m_create_checksum(hrp, data):
values = bech32m_hrp_expand(hrp) + data
polymod = bech32m_polymod(values + [0,0,0,0,0,0]) ^ BECH32M_CONST
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
All other aspects of Bech32 remain unchanged, including its human-readable parts (HRPs).
A combined function to decode both Bech32 and Bech32m simultaneously could be written using:
which returns either None for failure, or one of the BECH32 / BECH32M enumeration values to indicate successful decoding according to the respective standard.
===Addresses for segregated witness outputs===
Version 0 outputs (specifically, P2WPKH and P2WSH addresses) continue to use Bech32'''Why not permit both Bech32 and Bech32m for v0 addresses?''' Permitting both encodings reduces the error detection capabilities (it makes it equivalent to only have 29 bits of checksum). as specified in BIP173. Addresses for segregated witness outputs version 1 through 16 use Bech32m. Again, all other aspects of the encoding remain the same, including the 'bc' HRP.
To generate an address for a segregated witness output:
* If its witness version is 0, encode it using Bech32.
* If its witness version is 1 or higher, encode it using Bech32m.
To decode an address, client software should either decode with both a Bech32 and a Bech32m decoder'''Can a single string simultaneously be valid as Bech32 and Bech32m?''' No, a valid Bech32 and Bech32m string will always differ by at least 3 characters if they are the same length., or use a decoder that supports both simultaneously. In both cases, the address decoder has to verify that the encoding matches what is expected for the decoded witness version (Bech32 for version 0, Bech32m for others).
The following code demonstrates the checks that need to be performed. Refer to the Python code linked in the reference implementation section below for full details of the called functions.
def decode(hrp, addr):
hrpgot, data, spec = bech32_decode(addr)
if hrpgot != hrp:
return (None, None)
decoded = convertbits(data[1:], 5, 8, False)
# Witness programs are between 2 and 40 bytes in length.
if decoded is None or len(decoded) < 2 or len(decoded) > 40:
return (None, None)
# Witness versions are in range 0..16.
if data[0] > 16:
return (None, None)
# Witness v0 programs must be exactly length 20 or 32.
if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
return (None, None)
# Witness v0 uses Bech32; v1 through v16 use Bech32m.
if data[0] == 0 and spec != Encoding.BECH32 or data[0] != 0 and spec != Encoding.BECH32M:
return (None, None)
# Success.
return (data[0], decoded)
'''Error locating'''
Bech32m, like Bech32, does support locating'''What about error correction?''' As explained in BIP173, introducing error correction reduces the ability to detect errors. While it is technically possible to correct a small number of errors due to Bech32(m)'s nature as a BCH code, implementations should refrain from using this for more than indicating where an error may be present. the positions of a few substitution errors. To combine this functionality with
the segregated witness addresses proposed by this document, simply try locating errors for both Bech32 and Bech32m. If only one finds error locations, report that one. If both do (which should be very rare),
there are a number of options:
* Report the one that needs fewer corrections (if they differ).
* Eliminate the response(s) that are inconsistent. Any symbol that isn't on an error location can be checked. For example, if the witness version symbol is not an error location, and it doesn't correspond to the specification used (0 for Bech32, 1+ for Bech32m), that response can be eliminated.
See the fancy Javascript decoder below for example of the above.
==Compatibility==
This document introduces a new encoding for v1 segregated witness outputs and higher versions. There should not be any compatibility issues on the receiver side; no wallets are creating v1 segregated witness addresses yet, as the output type is not usable on mainnet.
On the other hand, the Bech32m proposal breaks forward-compatibility for sending to v1 and higher version segregated witness addresses. This incompatibility is [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-October/018236.html intentional]. An alternative design was [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-November/017460.html considered] where Bech32 remained in use for certain subsets of future addresses, but ultimately [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-December/018293.html discarded]. By introducing a clean break, we protect not only new software but also existing senders from the mutation issue, as new addresses will be incompatible with the existing Bech32 address validation. [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-November/018268.html Experiments] by Taproot proponents had shown that hardly any wallets and services supported sending to higher segregated witness output versions, so little is lost by [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-December/018298.html breaking] forward-compatibility. Furthermore, those experiments identified cases in which segregated witness implementations would have caused wallets to burn funds when sending to version 1 addresses. In case it is still in use, the chosen approach will prevent such software from destroying funds when attempting to send to a Bech32m address.
==Reference implementations==
* Reference encoder and decoder:
** [https://github.com/sipa/bech32/blob/master/ref/python Reference Python implementation]
** [https://github.com/sipa/bech32/blob/master/ref/c Reference C implementation]
** [https://github.com/sipa/bech32/blob/master/ref/c++ Reference C++ implementation]
** [https://github.com/bitcoin/bitcoin/pull/20861 Bitcoin Core C++ implementation]
** [https://github.com/sipa/bech32/blob/master/ref/javascript Reference Javascript implementation]
* Fancy decoder that localizes errors:
** [https://github.com/sipa/bech32/blob/master/ecc/javascript For JavaScript] ([http://bitcoin.sipa.be/bech32/demo/demo.html demo website])
==Test vectors==
'''Implementation advice''' Experiments testing BIP173 implementations found that many wallets and services did not support sending to higher version segregated witness outputs. In anticipation of the proposed [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki Taproot] soft fork introducing v1 segregated witness outputs on the network, we emphatically recommend employing the complete set of test vectors provided below as well as ensuring that your implementation supports sending to v1 '''and higher versions'''. All higher versions of native segregated witness outputs should be recognized as valid recipients. As higher versions are not defined on the network, no wallet should ever create them and no recipient should ever provide them to a sender. Nor should a recipient ever want to falsely provide them as the recipient would simply see a payment intended to themselves burned instead. However, by defining higher versions as valid recipients now, future soft forks introducing higher versions of native segwit outputs will be forward-compatible to all wallets correctly implementing the Bech32m specification.
===Test vectors for Bech32m===
The following strings are valid Bech32m:
* A1LQFN3A
* a1lqfn3a
* an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6
* abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx
* 11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8
* split1checkupstagehandshakeupstreamerranterredcaperredlc445v
* ?1v759aa
No string can be simultaneously valid Bech32 and Bech32m, so the above examples also serve as invalid test vectors for Bech32.
The following string are not valid Bech32m (with reason for invalidity):
* 0x20 + 1xj0phk: HRP character out of range
* 0x7F + 1g6xzxy: HRP character out of range
* 0x80 + 1vctc34: HRP character out of range
* an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4: overall max length exceeded
* qyrz8wqd2c9m: No separator character
* 1qyrz8wqd2c9m: Empty HRP
* y1b0jsk6g: Invalid data character
* lt1igcx5c0: Invalid data character
* in1muywd: Too short checksum
* mm1crxm3i: Invalid character in checksum
* au1s5cgom: Invalid character in checksum
* M1VUXWEZ: checksum calculated with uppercase form of HRP
* 16plkw9: empty HRP
* 1p2gdwpf: empty HRP
===Test vectors for v0-v16 native segregated witness addresses===
The following list gives valid segwit addresses and the scriptPubKey that they
translate to in hex.
* BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4: 0014751e76e8199196d454941c45d1b3a323f1433bd6
* tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7: 00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262
* bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y: 5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6
* BC1SW50QGDZ25J: 6002751e
* bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs: 5210751e76e8199196d454941c45d1b3a323
* tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy: 0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433
* tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c: 5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433
* bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0: 512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
The following list gives invalid segwit addresses and the reason for
their invalidity.
* tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut: Invalid human-readable part
* bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd: Invalid checksum (Bech32 instead of Bech32m)
* tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf: Invalid checksum (Bech32 instead of Bech32m)
* BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL: Invalid checksum (Bech32 instead of Bech32m)
* bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh: Invalid checksum (Bech32m instead of Bech32)
* tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47: Invalid checksum (Bech32m instead of Bech32)
* bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4: Invalid character in checksum
* BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R: Invalid witness version
* bc1pw5dgrnzv: Invalid program length (1 byte)
* bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav: Invalid program length (41 bytes)
* BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P: Invalid program length for witness version 0 (per BIP141)
* tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq: Mixed case
* bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf: zero padding of more than 4 bits
* tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j: Non-zero padding in 8-to-5 conversion
* bc1gmk9yu: Empty data section
==Appendix: checksum design & properties==
Checksums are used to detect errors introduced into data during transfer. A hash function-based checksum such as Base58Check detects any type of error uniformly, but not all classes of errors are equally likely to occur in practice. Bech32 prioritizes detection of substitution errors, but improving detection of one error class inevitably worsens detection of other error classes. During the design of Bech32, it was assumed that other simple error patterns beside substitutions would have a similar detection rate as in a hash function-based design, and detection would only be worse for complex, impractical errors. The discovered insertion weakness shows that this is not the case.
For Bech32m, we aim to retain Bech32's guarantees for substitution errors, but make sure that other common errors don't perform worse than a hash function-based checksum would. To make sure the new standard is easy to implement, we restrict the design space to only amending the final constant that is xored in, as it was [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-December/017521.html observed] that is sufficient to mitigate the 'q' insertion issue while retaining the intended substitution error detection. In what follows, we explain how the new constant ''0x2bc830a3'' was chosen.
===Error patterns & detection probability===
We define an error pattern as a sequence of first one or more deletions, then swaps of adjacent characters, followed by substitutions, insertions, and duplications, in that order, all in specific positions, applied to a string with valid checksum that is otherwise randomly chosen. For insertions and substitutions we assume a uniformly random new character. For example, "delete the 17th character, swap the 11th character with the 12th character, and insert a random character in the 24th position" is an error pattern. "Replace the 43rd through 48th character with 'aardvark'" is not a valid error pattern, because the new characters are not random and there is no reason why this particular string is more likely than any other to be substituted.
A hash function-based checksum design with a 30-bit hash would have a probability of incorrectly accepting equal to ''2-30'', for every error pattern. Bech32 has a probability of 0 to incorrectly accept error patterns consisting of up to 4 substitutions—they are always detected. The 'q'-insertion issue shows that for Bech32 a simple error pattern ("insert a random character in the penultimate position") with probability ''2-10'' exists: it requires the final character to be 'p' (leaving only 1 in 32 strings), and requires the inserted character to be 'q' (permitting only 1 of 32 possible inserted characters).
Note that the choice of ''what'' the error pattern is (which types of errors, and where) isn't part of our probabilities: we try to make sure that ''every'' pattern behaves well, not just randomly chosen ones, because presumably humans
make some kinds of errors more than others, and we cannot easily model which ones.
===Detection properties of Bech32m===
The table below shows the error detection properties of Bech32m, and a comparison with Bech32. The code used for this analysis can be found [https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e#file-const_analysis-cpp here]. Every row specifies one error pattern via the constraints in the left four columns. The remaining columns report what percentage of those patterns have certain probabilities of not being detected. The columns are:
* '''errors''' The maximum number of individual errors considered
* '''of type''' What type of errors are considered (either "subst. only" for just substitutions, or "any" to also include deletions, swaps, insertions, and duplications)
* '''window''' The maximum size of the window in which the errors have to occur'''What is an error pattern’s window size?''' The window size of an error pattern is the length of the smallest consecutive range of characters that contains all modified characters (on input or output; whichever is larger). For example, an error pattern that turns "abcdef" into "accdbef" has a window size of 4, as it is replacing "bcd" with "ccdb", a 4 character string. Window size is only meaningful when the pattern consists of two or more errors.
* '''code/verifier''' Whether this line is about Bech32 or Bech32m encoded strings, and whether those are evaluated regarding their probability of being accepted by either a Bech32 or a Bech32m verifier.'''Why do we care about probability of accepting Bech32m strings in Bech32 verifiers?''' For applications where Bech32m replaces an existing use of Bech32 (such as segregated witness addresses), we want to make sure that a Bech32m string created by new software won’t be erroneously accepted by old software that assumes Bech32 - even when a small number of errors were introduced as well.'''Should we also take into account failures that occur due to taking a valid Bech32m string, and after errors it becoming acceptable to a Bech32 verifier?''' This situation may in theory occur for segregated witness addresses when errors occur that change the version number in a v1+ address to v0. Due to the specificity of this type of error, plus the additional constraints that apply for v0 addresses, this is both unlikely and hard to analyze.
* '''error patterns with failure probability''' For each probability (''0'', ''2-30'', ''2-25'', ''2-20'', ''2-15'', and ''2-10'') this reports what percentage of error patterns restricted by the constraints in the previous columns have those probabilities of being incorrectly accepted.
The properties are divided into two classes: those that hold over all strings when averaged over all possible HRPs (human readable parts), and those specific to the "bc1" HRP with the length restrictions imposed by segregated witness addresses'''What restrictions were taken into account for the "bc1"-specific analysis?''' The minimum length (due to witness programs being at least 2 bytes), the maximum length (due to witness programs being at most 40 bytes), and the fact that the witness programs are a multiple of 8 bits. The fact that the first data symbol cannot be over 16, or that the padding has to be 0, is not taken into account..
{| class="wikitable"
! rowspan="2" | errors
! rowspan="2" | of type
! rowspan="2" | window
! rowspan="2" | code/verifier
! colspan="6" | error patterns with failure probability
|-
! ''0'' !! ''2-30'' !! ''2-25'' !! ''2-20'' !! ''2-15'' !! ''2-10''
|-
! colspan="10" | Properties averaged over all HRPs
|-
| ≤ 4 || only subst. || any || rowspan="6" | Bech32m/Bech32m || 100.00%|| colspan="5" | none(a)
|-
| any || any || ≤ 4 || 56.16%|| 43.84%|| colspan="4" | none(b)
|-
| ≤ 2 || any || ≤ 68 || 7.71%|| 92.28%|| colspan="4" | none(b)
|-
| ≤ 2 || any || any || 7.79%|| 92.20%|| 0.004%|| colspan="3" | none(b)
|-
| ≤ 3 || any || ≤ 69 || 7.73%|| 92.23%|| 0.033%(d) || colspan="3" | none(b)
|-
| ≤ 3 || any || any || 7.77%|| 92.19%|| 0.034%|| 0.000065% || colspan="2" | none(b)
|-
| ≤ 4 || only subst. || any || rowspan="6" | Bech32/Bech32 || 100.00%|| colspan="5" | none
|-
| any || any || ≤ 4 || 54.00%|| 43.84%|| 1.08%|| 0.90%|| 0.17%|| 0.0091%
|-
| ≤ 2 || any || ≤ 68 || 4.59%|| 92.29%|| 1.09%|| 1.01%|| 0.99%|| 0.039%
|-
| ≤ 2 || any || any || 4.58%|| 92.21%|| 1.11%|| 1.04%|| 1.02%|| 0.038%
|-
| ≤ 3 || any || ≤ 69 || 6.69%|| 92.23%|| 0.56%|| 0.48%|| 0.041%|| 0.00055%
|-
| ≤ 3 || any || any || 6.66%|| 92.19%|| 0.59%|| 0.52%|| 0.041%|| 0.00053%
|-
| 0 || - || - || rowspan="3" | Bech32m/Bech32 || 100.00%|| colspan="5" | none(a)
|-
| 1 || any || - || 46.53%|| 53.46%|| colspan="4" | none(b)
|-
| ≤ 2 || any || any || 22.18%|| 77.77%|| 0.048%|| colspan="3" | none(b)
|-
! colspan="10" | Properties for segregated witness addresses with HRP "bc"
|-
| ≤ 4 || only subst. || any || rowspan="6" | Bech32m/Bech32m || 100.00%|| colspan="5" | none(a)
|-
| 1 || any || - || 24.34%|| 75.66%|| colspan="4" | none(c)
|-
| ≤ 2 || any || ≤ 28 || 16.85%|| 83.15%|| colspan="4" | none(c)
|-
| any || any || ≤ 4 || 74.74%|| 25.25%|| 0.0016%|| colspan="3" | none(c)
|-
| ≤ 2 || any || any || 15.72%|| 84.23%|| 0.039%|| 0.0053%|| colspan="2" | none(c)
|-
| ≤ 3 || any || any || 13.98%|| 85.94%|| 0.078%|| 0.00063%|| colspan="2" | none(c)
|-
| ≤ 4 || only subst. || any || rowspan="6" | Bech32/Bech32 || 100.00%|| colspan="5" | none
|-
| 1 || any || - || 14.63%|| 75.71%|| 2.43%|| 2.43%|| 2.43%|| 2.38%
|-
| ≤ 2 || any || ≤ 28 || 14.22%|| 83.15%|| 0.94%|| 0.84%|| 0.79%|| 0.054%
|-
| any || any || ≤ 4 || 73.23%|| 25.26%|| 0.76%|| 0.63%|| 0.12%|| 0.0064%
|-
| ≤ 2 || any || any || 12.79%|| 84.24%|| 1.06%|| 0.95%|| 0.92%|| 0.041%
|-
| ≤ 3 || any || any || 13.00%|| 85.94%|| 0.57%|| 0.45%|| 0.044%|| 0.00067%
|-
| ≤ 3 || only subst. || any || rowspan="3" | Bech32m/Bech32 || 100.00%|| colspan="5" | none(c)
|-
| 1 || any || - || 70.89%|| 29.11%|| colspan="4" | none(c)
|-
| ≤ 2 || any || any || 36.12%|| 63.79%|| 0.092%|| 0.00049%|| colspan="2" | none(c)
|}
The numbers in this table, as well as a comparison with the numbers for the ‘’1’’ constant and earlier proposed improved constants, can be found [https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e#file-results_final-txt here].
===Selection process===
The details of the selection process can be found [https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e here], but in short:
* Start with the set of all ''230-1'' constants different from Bech32's ''1''. All of these satisfy the properties marked (a) in the table above.
* Through exhaustive analysis, reject all constants that do not exhibit the properties'''How were the properties to select for chosen?''' All these properties are as strong as they can be without rejecting every constant: rejecting constants with lower probabilities, or more errors, or wider windows all result in nothing left. marked (b) in the table above (e.g. all constants that permit any error pattern of 2 errors or less in a window of 68 characters or less with a detection probability ''≥ 2-20''). This selection leaves us with 12054 candidates.
* Reject all constants that do not exhibit the (c) properties in the table above'''Why optimize for segregated witness addresses (with HRP "bc1") specifically?''' Our analysis for generic HRP has limitations (see the detailed description [https://gist.github.com/sipa/14c248c288c3880a3b191f978a34508e#file-bech32m_mail-txt here], under "Technical details"). We optimize for generic usage first, but optimize for segregated witness addresses as a tiebreaker.. This leaves us with 79 candidates.
* Finally, select the candidate that minimizes the number of error classes matching (d) in the table above as a final tiebreaker. The result is the single constant ''0x2bc830a3''.
==Footnotes==
==Acknowledgements==
Thanks to Greg Maxwell for doing most of the computation for code selection and analysis, and comments.
Thanks to Mark Erhardt for help with writing and editing this document.
Thanks to Rusty Russell and others on the bitcoin-dev list for the discussion around intentionally breaking compatibility with existing senders, which is used in this specification.
================================================
FILE: bip-0351.mediawiki
================================================
BIP: 351
Layer: Applications
Title: Private Payments
Authors: Alfred Hodler
Clark Moody
Status: Draft
Type: Informational
Assigned: 2022-07-10
License: MIT
==Abstract==
This BIP makes it possible for two parties to transact using addresses that only they can calculate. This is done using exclusively on-chain methods and in a manner that minimizes blockchain footprint. Receiving parties can share their payment codes publicly without a loss of privacy, as every sender will calculate a unique set of addresses for each payment code.
==Motivation==
A recipient that wishes to receive funds privately has several options. Each has tradeoffs in terms of chain analysis potential, recoverability, and wallet complexity.
'''Sharing a static address''' works well enough for one-time payments between two parties as long as the address is shared through a private channel. It does not work well for recurring payments because address reuse leads to a loss of privacy. Using this method for donations exacerbates the problem since the address will serve as a focal point for data collection and analysis. Wallets must not reissue the same address to multiple recipients.
'''Sharing a BIP32 extended public key''' works for recurring payments between two parties only. The same key cannot be shared to any other party without leaking the chain of payments. Furthermore, an extended public key does not say anything about address types and makes it possible for a sender to send to a script that a recipient cannot spend from. Alternate [https://github.com/satoshilabs/slips/blob/master/slip-0132.md version bytes] have been proposed to specify address types, but wallet adoption is limited.
'''Sharing a BIP380 descriptor containing an extended public key''' solves the address type issue from sharing a raw BIP32 extended key. The drawback is that descriptor support is not widespread, especially in mobile wallets.
'''Using a payment server''' works in the case of recipients that have the resources to set up and maintain a payment server that will generate a fresh address for each payment. These are usually businesses and the method is usually out of reach for the average user. The centralized server is vulnerable to takedown remotely and physically.
'''Sharing a BIP47 payment code''' addresses most of the above shortcomings. However, it introduces the following problems:
* The BIP uses a notification mechanism that relies on publicly known per-recipient notification addresses. If Alice wants to send funds to Bob, she has to use the same notification address that everyone else uses to notify Bob. If Alice is not careful with coin selection, i.e. ensuring that her notification UTXO is not linked to her, she will publicly expose herself as someone who is trying to send funds to Bob and their relationship becomes permanently visible on the blockchain.
* The BIP does not say anything about address types. Receiving wallets therefore have to watch all address types that can be created from a single public key. Even then, a sender could send to a script that a recipient cannot spend from.
==Method==
When Alice wants to start paying Bob in private, she imports his payment code into a compatible wallet. Her wallet extracts Bob's public key from the payment code and sends a notification transaction. If Bob finds a notification transaction addressed to himself, he imports Alice's public key contained therein and stores it. Bob then performs ECDH using Alice's public key and his own private key in order to calculate a common set of addresses to watch. Alice calculates the same set of addresses on her end and uses them to send coins to Bob. If Alice engages in coin control, both the initial notification transaction and subsequent payment transactions cannot be attributed to either party. Even if Alice uses coins that are already associated with her, chain analysis will identify her as a sender but Bob's privacy will remain entirely preserved.
==Specification==
===Definitions===
* Alice: sender
* Bob: recipient
* Payment code: static string that Bob generates and shares with others so that he can receive payments
* ''P'': public key contained in Bob's payment code
* ''p'': private key associated with Bob's public key ''P''
* ''N'': extended public key used by Alice to derive child keys for each Bob she wants to transact with
* ''n'': private key associated with Alice's public key ''N''
* ''x'': Alice's secret recipient index, unique for each Bob
* ''Nx'': child public key derived from ''N'' at index ''x'' (non-hardened)
* ''nx'': private key associated with ''Nx''
* ''c'': Alice's transaction count toward Bob
* ''Pc'': Bob's public key at index ''c''
* ''pc'': Bob's private key at index ''c''
* ''Ac'': Bob's receive address at index ''c''
* ''H'': SHA256 hash function
* ''*'': EC multiplication
* ''+'': EC addition
* ''|'': string concatenation
* ''[a..b]'': string slicing (inclusive of ''a'', exclusive of ''b'')
===Public Key Derivation Path===
The derivation path for this BIP follows BIP44. The following BIP32 path levels are defined:
m / purpose' / coin_type' / account'
purpose is set to 351.
''(p, P)'' and ''(n, N)'' are keys associated with the above path, depending on which side is performing the calculation.
''Nx'' keys are the direct non-hardened children of ''N''. For instance, the path of ''N0'' from ''N'' is ''m / 0''.
===Payment Code Structure and Encoding===
* bytes [0..2]: address type flags (2 bytes)
* bytes [2..35]: compressed public key P (33 bytes)
Payment codes are encoded in bech32m and the human readable part is "pay" for mainnet and "payt" for testnet (all types), resulting in payment codes that look like "pay1cqqq8d29g0a7m8ghmycqk5yv24mfh3xg8ptzqcn8xz6d2tjl8ccdnfkpjl7p84".
===Address Types===
Address type flags determine which address types a payment code accepts. This is represented by big-endian ordered 16 bits. For instance, a hypothetical payment code that handles all address types will have all defined bits set to 1 (0xffff).
Currently defined flags:
{| class="wikitable"
! Address Type !! Flag !! Flag Value !! Ordinal Value
|-
| P2PKH || 1 << 0 || 0x0001 || 0
|-
| P2WPKH || 1 << 1 || 0x0002 || 1
|-
| P2TR || 1 << 2 || 0x0004 || 2
|}
The remaining flags are reserved for future address types.
While payment codes use 2-byte bitflag arrays, notifications use ordinal values in the form of a single byte.
All keys are compressed. Using uncompressed keys at any point is illegal.
===Notifications===
Notifications are performed by publishing transactions that contain a 40-byte OP_RETURN output. The value of the OP_RETURN is constructed using the following formula:
''search_key | notification_code | Nx | address_type''
* ''search_key'' equals "PP" and is a static ASCII-encoded string (2 bytes)
* ''notification_code'' is ''H(nx * P)[0..4]'' (4 bytes)
* ''Nx'' is the unique public key a sender is using for a particular recipient (33 bytes)
* ''address_type'' is the '''ordinal''' value of a single address type that a sender wants to send to (1 byte). This must be selected from the recipient's accepted address types.
When Alice wants to notify Bob that he will receive future payments from her, she performs the following procedure:
# Assigns an unused, unique index ''x'' to Bob (''0'' if Bob is the first party she is notifying).
# Calculates a 4-byte notification code: ''notification_code = H(nx * P)[0..4]''
# Commits to one of Bob's accepted address types by choosing its ordinal value. Going forward Alice must not send to address types other than the one she committed to in the notification.
# Constructs a notification payload by concatenating the above values according to the formula.
# Selects any UTXO in her wallet, preferably not associated with her.
# Sends a transaction including an OP_RETURN output whose value is set to the constructed payload.
When Bob notices a 40-byte OP_RETURN starting with ''search key'', he performs the following procedure:
# Breaks down the payload into its four constituent parts.
# Discards the ''search_key'' (item #0).
# Selects ''Nx'' (item #2) and performs ''H(Nx * p)'' (Bob does not know the value of ''x''). Bob takes the first four bytes of the calculated value.
# If the four bytes match the notification value (item #1), Bob found a notification addressed to himself and stores ''Nx'' together with ''address_type''.
# If this process fails for any reason, Bob assumes a spurious notification or one not addressed to himself and gives up.
Since changing ''x'' yields a completely different sender identity, Alice can always re-notify Bob from a different index when she does not want to be associated with her previous identity. Alice can also re-notify Bob when she wants to start sending to a different address type. Bob must be able to update his watchlist in that case and he can stop watching addresses associated with the old address type.
Out-of-band notifications between Alice and Bob are legal (in fact, they may not be prevented), but in that case Bob loses the ability to restore his wallet from OP_RETURN outputs embedded in the blockchain. In that case, Bob has the burden of keeping a valid backup of any out-of-band notifications.
===Allowing Notification Collisions===
Since ''notification_code'' is a 4-byte truncation of the full value, Bob has a 1 in ~4.3 billion chance of detecting a spurious notification. This is considered acceptable because the cost of doing so is adding a few more addresses to Bob's watchlist. The benefit of this approach is that is saves 28 bytes per notification.
===Scanning Requirement===
There is a scanning requirement on the recipient side in that the recipient must have access to full blocks in order to be able to search them for OP_RETURN outputs containing notifications. For more information on how light clients can get around this limitation and still use the standard, see Appendix B.
Recipients that do not want to decode raw block data can quickly search for notifications in a block by looking for the following byte array: [106, 40, 80, 80]. The first two bytes represent ''OP_RETURN'' and ''OP_PUSHBYTES_40'', followed by the ASCII value of ''search_key''.
===Transacting===
Alice initializes counter ''c'' which is unique to Bob and increments with each transaction. ''c'' is a 64-bit integer and must be inputted into a hasher as a big-endian encoded array of 8 bytes.
1. Alice calculates a secret point (constant between Alice and Bob):
''S = nx * P''
2. Alice calculates a shared secret:
''s = H(S | c)''
3. Alice calculates Bob's ephemeral public key and its associated address where the funds will be sent:
''Pc = P + s*G''
4. Alice constructs an address using the key ''Pc'', using one of the address types she committed to in the notification transaction.
Bob constructs his watchlist by mirroring this process on his end, except that his method of calculating ''S'' is:
''S = Nx * p''
When Bob wants to spend from such addresses, he calculates his private keys in the following manner:
''pc = p + s''
==Backward Compatibility==
Private Payments is a new standard which is not compatible with any previous standard based on static payment codes, such as BIP47.
While the standard does not support versioning, it reserves unused bits in the address type bitflag array which can be allocated to new address types once they are deemed ubiquitous. Older payment codes (i.e. those generated when fewer address types were available) are readable by software supporting new address types. The reverse is also supported since older software will ignore newer address type flags that are not understood.
==Appendix A: Test Vectors==
===Alice's Wallet===
'''BIP32 seed:''' 0xfe
'''Master xprv:''' xprv9s21ZrQH143K2qVytoy3eZSSuc1gfzFrkV4bgoHzYTkgge4UoNP62eV8jkHYNqddaaefpnjwkz71P5m4EW6RuQBJeP9pdfa9WBnjP6XUivG
'''n:''' xprv9zNFGn56Wm1s89ycTCg4hB615ehu6ZvNL4mxUEAL28pNhBAb6SZgLdsgmQd1ECgAiCjy6XxTTRyBdPAhH1oMfLhv2bSwfiCYhL9s9ahEehf
'''N:''' xpub6DMbgHbzM8aALe45ZED54K2jdgYPW2eDhHhZGcZwaUMMZyVjdysvtSCAcfPYiqB5Zw41EyLWPxCXko6iEckwRdF5CD2ZKdTxUKigPXsnpaE
'''x:''' 0
'''nx:''' be9518016ec15762877de7d2ce7367a2087cf5682e72bbffa89535d73bb42f40
'''Nx:''' 02e3217349724307eed5514b53b1f53f0802672a9913d9bbb76afecc86be23f464
===Bob's Wallet===
'''BIP32 seed:''' 0xff
'''Master xprv:''' xprv9s21ZrQH143K47bRNtc26e8Gb3wkUiJ4fH3ewYgJeiGABp7vQtTKsLBzHM2fsfiK7Er6uMrWbdDwwrdcVn5TDC1T1npTFFkdEVoMgTwfVuR
'''p:''' 0x26c610e7d0ed4395be3f0664073d66b0a3442b49e1ec13faf2dd9b7d3c335441
'''P:''' 0x0302be8bff520f35fae3439f245c52afb9085a7bf62d099c1f5e9e1b15a7e2121a
'''Accepted scripts:''' 0x03 (legacy + segwit) (0x01 | 0x02)
'''Payment code:''' pay1qqpsxq4730l4yre4lt3588eyt3f2lwggtfalvtgfns04a8smzkn7yys6xv2gs8
===Alice notifying Bob===
'''S:''' 0x02c0892d6ba30b5b1eafebd47172e46d358721f294698f9f59b4d96b781da09a62
'''Notification code:''' 0x49cb55bb
'''Address type commitment:''' 1 (segwit)
'''Notification output script:''' OP_RETURN OP_PUSHBYTES_40 505049cb55bb02e3217349724307eed5514b53b1f53f0802672a9913d9bbb76afecc86be23f46401
===Alice sending to Bob===
'''c:''' 0
'''s:''' 0x5dbe5efee4a5b9df73708241858f2bf7ec65f141dbd229ea8e2f9f51804a18f2
'''s*G:''' 0x039362033c1bc3f05e081d4d7f76d5ffebde349b0f6a4d2e8ffc5c065c17233247
'''Pc:''' 0x03e669bd1705691a080840b07d76713d040934a37f2e8dde2fe02f5d3286a49219
'''Ac:''' bc1qw7ld5h9tj2ruwxqvetznjfq9g5jyp0gjhrs30w
===Bob spending===
'''c:''' 0
'''pc:''' 0x84846fe6b592fd7531af88a58ccc92a88faa1c8bbdbe3de5810d3acebc7d6d33
==Appendix B: Potential OP_RETURN Services==
Compact Block Filters, as formulated in BIP-0158, do not cover OP_RETURN data payloads. In support of light wallets, an external service could publish transaction proofs for all transactions that include the tagged notification payload. Light wallets would download all such transactions, filter for matches against their payment code, then verify the transaction proofs against the block headers obtained over the P2P network.
==Appendix C: Potential Notification Transaction Services==
No specific instruction is given as to the details of the notification transaction beyond simply including the single OP_RETURN payload. Since no restriction exists for other inputs or outputs of this transaction, there is an opportunity for an external service to include this payload in a transaction completely unrelated to Alice's wallet. Such a service could charge a fee out-of-band to help cover fees.
Another opportunity exists for an existing business to attach notification payloads to transactions sent during the normal course of operations. Large withdrawal transactions from mining pools or exchanges could include a marginal notification payload without affecting overall fees.
==Reference Implementation==
Reference implementation is available at https://github.com/private-payments/rust-private-payments
==Reference==
* [[bip-0032.mediawiki|BIP32 - Hierarchical Deterministic Wallets]]
* [[bip-0043.mediawiki|BIP43 - Purpose Field for Deterministic Wallets]]
* [[bip-0044.mediawiki|BIP44 - Multi-Account Hierarchy for Deterministic Wallets]]
* [[bip-0047.mediawiki|BIP47 - Reusable Payment Codes for Hierarchical Deterministic Wallets]]
* [[bip-0157.mediawiki|BIP157 - Client Side Block Filtering]]
* [[bip-0158.mediawiki|BIP158 - Compact Block Filters for Light Clients]]
* [https://gist.github.com/RubenSomsen/21c477c90c942acf45f8e8f5c1ad4fae BIP47 Prague Discussion (acknowledgements: @rubensomsen, @afilini, @kixunil])
================================================
FILE: bip-0352/bech32m.py
================================================
# Copyright (c) 2017, 2020 Pieter Wuille
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Reference implementation for Bech32/Bech32m and segwit addresses."""
from enum import Enum
class Encoding(Enum):
"""Enumeration type to list the various supported encodings."""
BECH32 = 1
BECH32M = 2
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
BECH32M_CONST = 0x2bc830a3
def bech32_polymod(values):
"""Internal function that computes the Bech32 checksum."""
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
chk = 1
for value in values:
top = chk >> 25
chk = (chk & 0x1ffffff) << 5 ^ value
for i in range(5):
chk ^= generator[i] if ((top >> i) & 1) else 0
return chk
def bech32_hrp_expand(hrp):
"""Expand the HRP into values for checksum computation."""
return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
def bech32_verify_checksum(hrp, data):
"""Verify a checksum given HRP and converted data characters."""
const = bech32_polymod(bech32_hrp_expand(hrp) + data)
if const == 1:
return Encoding.BECH32
if const == BECH32M_CONST:
return Encoding.BECH32M
return None
def bech32_create_checksum(hrp, data, spec):
"""Compute the checksum values given HRP and data."""
values = bech32_hrp_expand(hrp) + data
const = BECH32M_CONST if spec == Encoding.BECH32M else 1
polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
def bech32_encode(hrp, data, spec):
"""Compute a Bech32 string given HRP and data values."""
combined = data + bech32_create_checksum(hrp, data, spec)
return hrp + '1' + ''.join([CHARSET[d] for d in combined])
def bech32_decode(bech):
"""Validate a Bech32/Bech32m string, and determine HRP and data."""
if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
(bech.lower() != bech and bech.upper() != bech)):
return (None, None, None)
bech = bech.lower()
pos = bech.rfind('1')
# remove the requirement that bech32m be less than 90 chars
if pos < 1 or pos + 7 > len(bech):
return (None, None, None)
if not all(x in CHARSET for x in bech[pos+1:]):
return (None, None, None)
hrp = bech[:pos]
data = [CHARSET.find(x) for x in bech[pos+1:]]
spec = bech32_verify_checksum(hrp, data)
if spec is None:
return (None, None, None)
return (hrp, data[:-6], spec)
def convertbits(data, frombits, tobits, pad=True):
"""General power-of-2 base conversion."""
acc = 0
bits = 0
ret = []
maxv = (1 << tobits) - 1
max_acc = (1 << (frombits + tobits - 1)) - 1
for value in data:
if value < 0 or (value >> frombits):
return None
acc = ((acc << frombits) | value) & max_acc
bits += frombits
while bits >= tobits:
bits -= tobits
ret.append((acc >> bits) & maxv)
if pad:
if bits:
ret.append((acc << (tobits - bits)) & maxv)
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
return None
return ret
def decode(hrp, addr):
"""Decode a segwit address."""
hrpgot, data, spec = bech32_decode(addr)
if hrpgot != hrp:
return (None, None)
decoded = convertbits(data[1:], 5, 8, False)
if decoded is None or len(decoded) < 2:
return (None, None)
if data[0] > 16:
return (None, None)
return (data[0], decoded)
def encode(hrp, witver, witprog):
"""Encode a segwit address."""
spec = Encoding.BECH32 if witver == 0 else Encoding.BECH32M
ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5), spec)
if decode(hrp, ret) == (None, None):
return None
return ret
================================================
FILE: bip-0352/bitcoin_utils.py
================================================
import hashlib
import struct
from io import BytesIO
from ripemd160 import ripemd160
from secp256k1lab.secp256k1 import Scalar
from typing import Union
def from_hex(hex_string):
"""Deserialize from a hex string representation (e.g. from RPC)"""
return BytesIO(bytes.fromhex(hex_string))
def ser_uint32(u: int) -> bytes:
return u.to_bytes(4, "big")
def ser_uint256(u):
return u.to_bytes(32, 'little')
def deser_uint256(f):
return int.from_bytes(f.read(32), 'little')
def deser_txid(txid: str):
# recall that txids are serialized little-endian, but displayed big-endian
# this means when converting from a human readable hex txid, we need to first
# reverse it before deserializing it
dixt = "".join(map(str.__add__, txid[-2::-2], txid[-1::-2]))
return bytes.fromhex(dixt)
def deser_compact_size(f: BytesIO):
view = f.getbuffer()
nbytes = view.nbytes
view.release()
if (nbytes == 0):
return 0 # end of stream
nit = struct.unpack(" bytes:
return ripemd160(hashlib.sha256(s).digest())
def is_p2tr(spk: bytes) -> bool:
if len(spk) != 34:
return False
# OP_1 OP_PUSHBYTES_32 <32 bytes>
return (spk[0] == 0x51) & (spk[1] == 0x20)
def is_p2wpkh(spk: bytes) -> bool:
if len(spk) != 22:
return False
# OP_0 OP_PUSHBYTES_20 <20 bytes>
return (spk[0] == 0x00) & (spk[1] == 0x14)
def is_p2sh(spk: bytes) -> bool:
if len(spk) != 23:
return False
# OP_HASH160 OP_PUSHBYTES_20 <20 bytes> OP_EQUAL
return (spk[0] == 0xA9) & (spk[1] == 0x14) & (spk[-1] == 0x87)
def is_p2pkh(spk: bytes) -> bool:
if len(spk) != 25:
return False
# OP_DUP OP_HASH160 OP_PUSHBYTES_20 <20 bytes> OP_EQUALVERIFY OP_CHECKSIG
return (spk[0] == 0x76) & (spk[1] == 0xA9) & (spk[2] == 0x14) & (spk[-2] == 0x88) & (spk[-1] == 0xAC)
================================================
FILE: bip-0352/reference.py
================================================
#!/usr/bin/env python3
# For running the test vectors, run this script:
# ./reference.py send_and_receive_test_vectors.json
import json
from pathlib import Path
import sys
from typing import List, Tuple, Dict, cast
# import the vendored copy of secp256k1lab
sys.path.insert(0, str(Path(__file__).parent / "secp256k1lab/src"))
from secp256k1lab.bip340 import schnorr_sign, schnorr_verify
from secp256k1lab.secp256k1 import G, GE, Scalar
from secp256k1lab.util import tagged_hash, hash_sha256
from bech32m import convertbits, bech32_encode, decode, Encoding
from bitcoin_utils import (
deser_txid,
from_hex,
hash160,
is_p2pkh,
is_p2sh,
is_p2wpkh,
is_p2tr,
ser_uint32,
COutPoint,
CTxInWitness,
VinInfo,
)
K_max = 2323 # per-group recipient limit
NUMS_H = 0x50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0
def get_pubkey_from_input(vin: VinInfo) -> GE:
if is_p2pkh(vin.prevout):
# skip the first 3 op_codes and grab the 20 byte hash
# from the scriptPubKey
spk_hash = vin.prevout[3:3 + 20]
for i in range(len(vin.scriptSig), 0, -1):
if i - 33 >= 0:
# starting from the back, we move over the scriptSig with a 33 byte
# window (to match a compressed pubkey). we hash this and check if it matches
# the 20 byte hash from the scriptPubKey. for standard scriptSigs, this will match
# right away because the pubkey is the last item in the scriptSig.
# if its a non-standard (malleated) scriptSig, we will still find the pubkey if its
# a compressed pubkey.
#
# note: this is an incredibly inefficient implementation, for demonstration purposes only.
pubkey_bytes = vin.scriptSig[i - 33:i]
pubkey_hash = hash160(pubkey_bytes)
if pubkey_hash == spk_hash:
try:
return GE.from_bytes_compressed(pubkey_bytes)
except ValueError:
pass
if is_p2sh(vin.prevout):
redeem_script = vin.scriptSig[1:]
if is_p2wpkh(redeem_script):
try:
return GE.from_bytes_compressed(vin.txinwitness.scriptWitness.stack[-1])
except (ValueError, AssertionError):
pass
if is_p2wpkh(vin.prevout):
try:
return GE.from_bytes_compressed(vin.txinwitness.scriptWitness.stack[-1])
except (ValueError, AssertionError):
pass
if is_p2tr(vin.prevout):
witnessStack = vin.txinwitness.scriptWitness.stack
if (len(witnessStack) >= 1):
if (len(witnessStack) > 1 and witnessStack[-1][0] == 0x50):
# Last item is annex
witnessStack.pop()
if (len(witnessStack) > 1):
# Script-path spend
control_block = witnessStack[-1]
# control block is <32 byte internal key> and 0 or more <32 byte hash>
internal_key = control_block[1:33]
if (internal_key == NUMS_H.to_bytes(32, 'big')):
# Skip if NUMS_H
return GE()
try:
return GE.from_bytes_xonly(vin.prevout[2:])
except ValueError:
pass
return GE()
def get_input_hash(outpoints: List[COutPoint], sum_input_pubkeys: GE) -> bytes:
lowest_outpoint = sorted(outpoints, key=lambda outpoint: outpoint.serialize())[0]
return tagged_hash("BIP0352/Inputs", lowest_outpoint.serialize() + sum_input_pubkeys.to_bytes_compressed())
def encode_silent_payment_address(B_scan: GE, B_m: GE, hrp: str = "tsp", version: int = 0) -> str:
data = convertbits(B_scan.to_bytes_compressed() + B_m.to_bytes_compressed(), 8, 5)
return bech32_encode(hrp, [version] + cast(List[int], data), Encoding.BECH32M)
def generate_label(b_scan: Scalar, m: int) -> Scalar:
return Scalar.from_bytes_checked(tagged_hash("BIP0352/Label", b_scan.to_bytes() + ser_uint32(m)))
def create_labeled_silent_payment_address(b_scan: Scalar, B_spend: GE, m: int, hrp: str = "tsp", version: int = 0) -> str:
B_scan = b_scan * G
B_m = B_spend + generate_label(b_scan, m) * G
labeled_address = encode_silent_payment_address(B_scan, B_m, hrp, version)
return labeled_address
def decode_silent_payment_address(address: str, hrp: str = "tsp") -> Tuple[GE, GE]:
_, data = decode(hrp, address)
if data is None:
return GE(), GE()
B_scan = GE.from_bytes_compressed(data[:33])
B_spend = GE.from_bytes_compressed(data[33:])
return B_scan, B_spend
def create_outputs(input_priv_keys: List[Tuple[Scalar, bool]], outpoints: List[COutPoint], recipients: List[str], expected: Dict[str, any] = None, hrp="tsp") -> List[str]:
negated_keys = []
for key, is_xonly in input_priv_keys:
k = Scalar.from_bytes_checked(key.to_bytes())
if is_xonly and not (k * G).has_even_y():
k = -k
negated_keys.append(k)
a_sum = Scalar.sum(*negated_keys)
if a_sum == 0:
# Input privkeys sum is zero -> fail
return []
assert Scalar.from_bytes_checked(bytes.fromhex(expected.get("input_private_key_sum"))) == a_sum, "a_sum did not match expected input_private_key_sum"
input_hash_scalar = Scalar.from_bytes_checked(get_input_hash(outpoints, a_sum * G))
silent_payment_groups: Dict[GE, List[GE]] = {}
for recipient in recipients:
B_scan, B_m = decode_silent_payment_address(recipient["address"], hrp=hrp)
# Verify decoded intermediate keys for recipient
expected_B_scan = GE.from_bytes_compressed(bytes.fromhex(recipient["scan_pub_key"]))
expected_B_m = GE.from_bytes_compressed(bytes.fromhex(recipient["spend_pub_key"]))
assert expected_B_scan == B_scan, "B_scan did not match expected recipient.scan_pub_key"
assert expected_B_m == B_m, "B_m did not match expected recipient.spend_pub_key"
if B_scan in silent_payment_groups:
silent_payment_groups[B_scan].append(B_m)
else:
silent_payment_groups[B_scan] = [B_m]
# Fail if per-group recipient limit (K_max) is exceeded
if any([len(group) > K_max for group in silent_payment_groups.values()]):
return []
outputs = []
for B_scan, B_m_values in silent_payment_groups.items():
ecdh_shared_secret = input_hash_scalar * a_sum * B_scan
expected_shared_secrets = expected.get("shared_secrets", {})
# Find the recipient address that corresponds to this B_scan and get its index
for recipient_idx, recipient in enumerate(recipients):
recipient_B_scan = GE.from_bytes_compressed(bytes.fromhex(recipient["scan_pub_key"]))
if recipient_B_scan == B_scan:
expected_shared_secret_hex = expected_shared_secrets[recipient_idx]
assert ecdh_shared_secret.to_bytes_compressed().hex() == expected_shared_secret_hex, f"ecdh_shared_secret did not match expected, recipient {recipient_idx} ({recipient['address']}): expected={expected_shared_secret_hex}"
break
k = 0
for B_m in B_m_values:
t_k = Scalar.from_bytes_checked(tagged_hash("BIP0352/SharedSecret", ecdh_shared_secret.to_bytes_compressed() + ser_uint32(k)))
P_km = B_m + t_k * G
outputs.append(P_km.to_bytes_xonly().hex())
k += 1
return list(set(outputs))
def scanning(b_scan: Scalar, B_spend: GE, A_sum: GE, input_hash: bytes, outputs_to_check: List[bytes], labels: Dict[str, str] = None, expected: Dict[str, any] = None) -> List[Dict[str, str]]:
input_hash_scalar = Scalar.from_bytes_checked(input_hash)
computed_tweak_point = input_hash_scalar * A_sum
assert computed_tweak_point.to_bytes_compressed().hex() == expected.get("tweak"), "tweak did not match expected"
ecdh_shared_secret = input_hash_scalar * b_scan * A_sum
assert ecdh_shared_secret.to_bytes_compressed().hex() == expected.get("shared_secret"), "ecdh_shared_secret did not match expected shared_secret"
k = 0
wallet = []
while True:
if k == K_max: # Don't look further than the per-group recipient limit (K_max)
break
t_k = Scalar.from_bytes_checked(tagged_hash("BIP0352/SharedSecret", ecdh_shared_secret.to_bytes_compressed() + ser_uint32(k)))
P_k = B_spend + t_k * G
for output in outputs_to_check:
output_ge = GE.from_bytes_xonly(output)
if P_k.to_bytes_xonly() == output:
wallet.append({"pub_key": P_k.to_bytes_xonly().hex(), "priv_key_tweak": t_k.to_bytes().hex()})
outputs_to_check.remove(output)
k += 1
break
elif labels:
m_G_sub = output_ge - P_k
if m_G_sub.to_bytes_compressed().hex() in labels:
P_km = P_k + m_G_sub
wallet.append({
"pub_key": P_km.to_bytes_xonly().hex(),
"priv_key_tweak": (t_k + Scalar.from_bytes_checked(
bytes.fromhex(labels[m_G_sub.to_bytes_compressed().hex()])
)).to_bytes().hex(),
})
outputs_to_check.remove(output)
k += 1
break
else:
m_G_sub = -output_ge - P_k
if m_G_sub.to_bytes_compressed().hex() in labels:
P_km = P_k + m_G_sub
wallet.append({
"pub_key": P_km.to_bytes_xonly().hex(),
"priv_key_tweak": (t_k + Scalar.from_bytes_checked(
bytes.fromhex(labels[m_G_sub.to_bytes_compressed().hex()])
)).to_bytes().hex(),
})
outputs_to_check.remove(output)
k += 1
break
else:
break
return wallet
if __name__ == "__main__":
if len(sys.argv) != 2 or sys.argv[1] in ('-h', '--help'):
print("Usage: ./reference.py send_and_receive_test_vectors.json")
sys.exit(0)
with open(sys.argv[1], "r") as f:
test_data = json.loads(f.read())
for case in test_data:
print(case["comment"])
# Test sending
for sending_test in case["sending"]:
given = sending_test["given"]
expected = sending_test["expected"]
vins = [
VinInfo(
outpoint=COutPoint(hash=deser_txid(input["txid"]), n=input["vout"]),
scriptSig=bytes.fromhex(input["scriptSig"]),
txinwitness=CTxInWitness().deserialize(from_hex(input["txinwitness"])),
prevout=bytes.fromhex(input["prevout"]["scriptPubKey"]["hex"]),
private_key=Scalar.from_bytes_checked(bytes.fromhex(input["private_key"])),
)
for input in given["vin"]
]
# Convert the tuples to lists so they can be easily compared to the json list of lists from the given test vectors
input_priv_keys = []
input_pub_keys = []
for vin in vins:
pubkey = get_pubkey_from_input(vin)
if pubkey.infinity:
continue
input_priv_keys.append((
vin.private_key,
is_p2tr(vin.prevout),
))
input_pub_keys.append(pubkey)
assert [pk.to_bytes_compressed().hex() for pk in input_pub_keys] == expected.get("input_pub_keys"), "input_pub_keys did not match expected"
sending_outputs = []
if (len(input_pub_keys) > 0):
outpoints = [vin.outpoint for vin in vins]
recipients = [] # expand given recipient entries to full list
for recipient_entry in given["recipients"]:
count = recipient_entry.get("count", 1)
recipients.extend([recipient_entry] * count)
sending_outputs = create_outputs(input_priv_keys, outpoints, recipients, expected=expected, hrp="sp")
# Note: order doesn't matter for creating/finding the outputs. However, different orderings of the recipient addresses
# will produce different generated outputs if sending to multiple silent payment addresses belonging to the
# same sender but with different labels. Because of this, expected["outputs"] contains all possible valid output sets,
# based on all possible permutations of recipient address orderings. Must match exactly one of the possible output sets.
assert(any(set(sending_outputs) == set(lst) for lst in expected["outputs"])), "Sending test failed"
else:
assert(sending_outputs == expected["outputs"][0] == []), "Sending test failed"
# Test receiving
msg = hash_sha256(b"message")
aux = hash_sha256(b"random auxiliary data")
for receiving_test in case["receiving"]:
given = receiving_test["given"]
expected = receiving_test["expected"]
outputs_to_check = [
bytes.fromhex(p) for p in given["outputs"]
]
vins = [
VinInfo(
outpoint=COutPoint(hash=deser_txid(input["txid"]), n=input["vout"]),
scriptSig=bytes.fromhex(input["scriptSig"]),
txinwitness=CTxInWitness().deserialize(from_hex(input["txinwitness"])),
prevout=bytes.fromhex(input["prevout"]["scriptPubKey"]["hex"]),
)
for input in given["vin"]
]
# Check that the given inputs for the receiving test match what was generated during the sending test
receiving_addresses = []
b_scan = Scalar.from_bytes_checked(bytes.fromhex(given["key_material"]["scan_priv_key"]))
b_spend = Scalar.from_bytes_checked(bytes.fromhex(given["key_material"]["spend_priv_key"]))
B_scan = b_scan * G
B_spend = b_spend * G
receiving_addresses.append(
encode_silent_payment_address(B_scan, B_spend, hrp="sp")
)
if given["labels"]:
for label in given["labels"]:
receiving_addresses.append(
create_labeled_silent_payment_address(
b_scan, B_spend, m=label, hrp="sp"
)
)
# Check that the silent payment addresses match for the given BIP32 seed and labels dictionary
assert (receiving_addresses == expected["addresses"]), "Receiving addresses don't match"
input_pub_keys = []
for vin in vins:
pubkey = get_pubkey_from_input(vin)
if pubkey.infinity:
continue
input_pub_keys.append(pubkey)
add_to_wallet = []
if (len(input_pub_keys) > 0):
A_sum = GE.sum(*input_pub_keys)
if A_sum.infinity:
# Input pubkeys sum is point at infinity -> skip tx
assert expected["outputs"] == []
continue
assert A_sum.to_bytes_compressed().hex() == expected.get("input_pub_key_sum"), "A_sum did not match expected input_pub_key_sum"
input_hash = get_input_hash([vin.outpoint for vin in vins], A_sum)
pre_computed_labels = {
(generate_label(b_scan, label) * G).to_bytes_compressed().hex(): generate_label(b_scan, label).to_bytes().hex()
for label in given["labels"]
}
add_to_wallet = scanning(
b_scan=b_scan,
B_spend=B_spend,
A_sum=A_sum,
input_hash=input_hash,
outputs_to_check=outputs_to_check,
labels=pre_computed_labels,
expected=expected,
)
# Check that the private key is correct for the found output public key
for output in add_to_wallet:
pub_key = GE.from_bytes_xonly(bytes.fromhex(output["pub_key"]))
full_private_key = b_spend + Scalar.from_bytes_checked(bytes.fromhex(output["priv_key_tweak"]))
if not (full_private_key * G).has_even_y():
full_private_key = -full_private_key
sig = schnorr_sign(msg, full_private_key.to_bytes(), aux)
assert schnorr_verify(msg, pub_key.to_bytes_xonly(), sig), f"Invalid signature for {pub_key}"
output["signature"] = sig.hex()
# Note: order doesn't matter for creating/finding the outputs. However, different orderings of the recipient addresses
# will produce different generated outputs if sending to multiple silent payment addresses belonging to the
# same sender but with different labels. Because of this, expected["outputs"] contains all possible valid output sets,
# based on all possible permutations of recipient address orderings. Must match exactly one of the possible found output
# sets in expected["outputs"]
if "outputs" in expected: # detailed check against expected outputs
generated_set = {frozenset(d.items()) for d in add_to_wallet}
expected_set = {frozenset(d.items()) for d in expected["outputs"]}
assert generated_set == expected_set, "Receive test failed"
elif "n_outputs" in expected: # only check the number of found outputs
assert len(add_to_wallet) == expected["n_outputs"], "Receive test failed"
else:
assert False, "either 'outputs' or 'n_outputs' must be specified in 'expected' field of receiving test vector"
print("All tests passed")
================================================
FILE: bip-0352/ripemd160.py
================================================
# Copyright (c) 2021 Pieter Wuille
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test-only pure Python RIPEMD160 implementation."""
import unittest
# Message schedule indexes for the left path.
ML = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
]
# Message schedule indexes for the right path.
MR = [
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
]
# Rotation counts for the left path.
RL = [
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
]
# Rotation counts for the right path.
RR = [
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
]
# K constants for the left path.
KL = [0, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]
# K constants for the right path.
KR = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0]
def fi(x, y, z, i):
"""The f1, f2, f3, f4, and f5 functions from the specification."""
if i == 0:
return x ^ y ^ z
elif i == 1:
return (x & y) | (~x & z)
elif i == 2:
return (x | ~y) ^ z
elif i == 3:
return (x & z) | (y & ~z)
elif i == 4:
return x ^ (y | ~z)
else:
assert False
def rol(x, i):
"""Rotate the bottom 32 bits of x left by i bits."""
return ((x << i) | ((x & 0xffffffff) >> (32 - i))) & 0xffffffff
def compress(h0, h1, h2, h3, h4, block):
"""Compress state (h0, h1, h2, h3, h4) with block."""
# Left path variables.
al, bl, cl, dl, el = h0, h1, h2, h3, h4
# Right path variables.
ar, br, cr, dr, er = h0, h1, h2, h3, h4
# Message variables.
x = [int.from_bytes(block[4*i:4*(i+1)], 'little') for i in range(16)]
# Iterate over the 80 rounds of the compression.
for j in range(80):
rnd = j >> 4
# Perform left side of the transformation.
al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el
al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl
# Perform right side of the transformation.
ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er
ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr
# Compose old state, left transform, and right transform into new state.
return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr
def ripemd160(data):
"""Compute the RIPEMD-160 hash of data."""
# Initialize state.
state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0)
# Process full 64-byte blocks in the input.
for b in range(len(data) >> 6):
state = compress(*state, data[64*b:64*(b+1)])
# Construct final blocks (with padding and size).
pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63)
fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little')
# Process final blocks.
for b in range(len(fin) >> 6):
state = compress(*state, fin[64*b:64*(b+1)])
# Produce output.
return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state)
class TestFrameworkKey(unittest.TestCase):
def test_ripemd160(self):
"""RIPEMD-160 test vectors."""
# See https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
for msg, hexout in [
(b"", "9c1185a5c5e9fc54612808977ee8f548b2258d31"),
(b"a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
(b"abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
(b"message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36"),
(b"abcdefghijklmnopqrstuvwxyz",
"f71c27109c692c1b56bbdceb5b9d2865b3708dbc"),
(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"12a053384a9c0c88e405a06c27dcf49ada62eb2b"),
(b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"b0e20b6e3116640286ed3a87a5713079b21f5189"),
(b"1234567890" * 8, "9b752e45573d4b39f4dbd3323cab82bf63326bfb"),
(b"a" * 1000000, "52783243c1697bdbe16d37f97f68f08325dc1528")
]:
self.assertEqual(ripemd160(msg).hex(), hexout)
================================================
FILE: bip-0352/secp256k1lab/.github/workflows/main.yml
================================================
name: Tests
on: [push, pull_request]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
- run: uvx ruff check .
mypy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
- run: uvx mypy .
================================================
FILE: bip-0352/secp256k1lab/.python-version
================================================
3.9
================================================
FILE: bip-0352/secp256k1lab/CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2025-03-31
Initial release.
================================================
FILE: bip-0352/secp256k1lab/COPYING
================================================
The MIT License (MIT)
Copyright (c) 2009-2024 The Bitcoin Core developers
Copyright (c) 2009-2024 Bitcoin Developers
Copyright (c) 2025- The secp256k1lab Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: bip-0352/secp256k1lab/README.md
================================================
secp256k1lab
============

An INSECURE implementation of the secp256k1 elliptic curve and related cryptographic schemes written in Python, intended for prototyping, experimentation and education.
Features:
* Low-level secp256k1 field and group arithmetic.
* Schnorr signing/verification and key generation according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
* ECDH key exchange.
WARNING: The code in this library is slow and trivially vulnerable to side channel attacks.
================================================
FILE: bip-0352/secp256k1lab/pyproject.toml
================================================
[project]
name = "secp256k1lab"
version = "1.0.0"
description = "An INSECURE implementation of the secp256k1 elliptic curve and related cryptographic schemes, intended for prototyping, experimentation and education"
readme = "README.md"
authors = [
{ name = "Pieter Wuille", email = "pieter@wuille.net" },
{ name = "Tim Ruffing", email = "me@real-or-random.org" },
{ name = "Jonas Nick", email = "jonasd.nick@gmail.com" },
{ name = "Sebastian Falbesoner", email = "sebastian.falbesoner@gmail.com" }
]
maintainers = [
{ name = "Tim Ruffing", email = "me@real-or-random.org" },
{ name = "Jonas Nick", email = "jonasd.nick@gmail.com" },
{ name = "Sebastian Falbesoner", email = "sebastian.falbesoner@gmail.com" }
]
requires-python = ">=3.9"
license = "MIT"
license-files = ["COPYING"]
keywords = ["secp256k1", "elliptic curves", "cryptography", "Bitcoin"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Topic :: Security :: Cryptography",
]
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/__init__.py
================================================
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/bip340.py
================================================
# The following functions are based on the BIP 340 reference implementation:
# https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py
from .secp256k1 import FE, GE, G
from .util import int_from_bytes, bytes_from_int, xor_bytes, tagged_hash
def pubkey_gen(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
P = d0 * G
assert not P.infinity
return P.to_bytes_xonly()
def schnorr_sign(
msg: bytes, seckey: bytes, aux_rand: bytes, tag_prefix: str = "BIP0340"
) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
if len(aux_rand) != 32:
raise ValueError("aux_rand must be 32 bytes instead of %i." % len(aux_rand))
P = d0 * G
assert not P.infinity
d = d0 if P.has_even_y() else GE.ORDER - d0
t = xor_bytes(bytes_from_int(d), tagged_hash(tag_prefix + "/aux", aux_rand))
k0 = (
int_from_bytes(tagged_hash(tag_prefix + "/nonce", t + P.to_bytes_xonly() + msg))
% GE.ORDER
)
if k0 == 0:
raise RuntimeError("Failure. This happens only with negligible probability.")
R = k0 * G
assert not R.infinity
k = k0 if R.has_even_y() else GE.ORDER - k0
e = (
int_from_bytes(
tagged_hash(
tag_prefix + "/challenge", R.to_bytes_xonly() + P.to_bytes_xonly() + msg
)
)
% GE.ORDER
)
sig = R.to_bytes_xonly() + bytes_from_int((k + e * d) % GE.ORDER)
assert schnorr_verify(msg, P.to_bytes_xonly(), sig, tag_prefix=tag_prefix)
return sig
def schnorr_verify(
msg: bytes, pubkey: bytes, sig: bytes, tag_prefix: str = "BIP0340"
) -> bool:
if len(pubkey) != 32:
raise ValueError("The public key must be a 32-byte array.")
if len(sig) != 64:
raise ValueError("The signature must be a 64-byte array.")
try:
P = GE.from_bytes_xonly(pubkey)
except ValueError:
return False
r = int_from_bytes(sig[0:32])
s = int_from_bytes(sig[32:64])
if (r >= FE.SIZE) or (s >= GE.ORDER):
return False
e = (
int_from_bytes(tagged_hash(tag_prefix + "/challenge", sig[0:32] + pubkey + msg))
% GE.ORDER
)
R = s * G - e * P
if R.infinity or (not R.has_even_y()) or (R.x != r):
return False
return True
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/ecdh.py
================================================
import hashlib
from .secp256k1 import GE, Scalar
def ecdh_compressed_in_raw_out(seckey: bytes, pubkey: bytes) -> GE:
"""TODO"""
shared_secret = Scalar.from_bytes_checked(seckey) * GE.from_bytes_compressed(pubkey)
assert not shared_secret.infinity # prime-order group
return shared_secret
def ecdh_libsecp256k1(seckey: bytes, pubkey: bytes) -> bytes:
"""TODO"""
shared_secret = ecdh_compressed_in_raw_out(seckey, pubkey)
return hashlib.sha256(shared_secret.to_bytes_compressed()).digest()
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/keys.py
================================================
from .secp256k1 import GE, G
from .util import int_from_bytes
# The following function is based on the BIP 327 reference implementation
# https://github.com/bitcoin/bips/blob/master/bip-0327/reference.py
# Return the plain public key corresponding to a given secret key
def pubkey_gen_plain(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
P = d0 * G
assert not P.infinity
return P.to_bytes_compressed()
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/py.typed
================================================
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/secp256k1.py
================================================
# Copyright (c) 2022-2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test-only implementation of low-level secp256k1 field and group arithmetic
It is designed for ease of understanding, not performance.
WARNING: This code is slow and trivially vulnerable to side channel attacks. Do not use for
anything but tests.
Exports:
* FE: class for secp256k1 field elements
* GE: class for secp256k1 group elements
* G: the secp256k1 generator point
"""
# TODO Docstrings of methods still say "field element"
class APrimeFE:
"""Objects of this class represent elements of a prime field.
They are represented internally in numerator / denominator form, in order to delay inversions.
"""
# The size of the field (also its modulus and characteristic).
SIZE: int
def __init__(self, a=0, b=1):
"""Initialize a field element a/b; both a and b can be ints or field elements."""
if isinstance(a, type(self)):
num = a._num
den = a._den
else:
num = a % self.SIZE
den = 1
if isinstance(b, type(self)):
den = (den * b._num) % self.SIZE
num = (num * b._den) % self.SIZE
else:
den = (den * b) % self.SIZE
assert den != 0
if num == 0:
den = 1
self._num = num
self._den = den
def __add__(self, a):
"""Compute the sum of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._den + self._den * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num + self._den * a, self._den)
return NotImplemented
def __radd__(self, a):
"""Compute the sum of an integer and a field element."""
return type(self)(a) + self
@classmethod
# REVIEW This should be
# def sum(cls, *es: Iterable[Self]) -> Self:
# but Self needs the typing_extension package on Python <= 3.12.
def sum(cls, *es):
"""Compute the sum of field elements.
sum(a, b, c, ...) is identical to (0 + a + b + c + ...)."""
return sum(es, start=cls(0))
def __sub__(self, a):
"""Compute the difference of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._den - self._den * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num - self._den * a, self._den)
return NotImplemented
def __rsub__(self, a):
"""Compute the difference of an integer and a field element."""
return type(self)(a) - self
def __mul__(self, a):
"""Compute the product of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num * a, self._den)
return NotImplemented
def __rmul__(self, a):
"""Compute the product of an integer with a field element."""
return type(self)(a) * self
def __truediv__(self, a):
"""Compute the ratio of two field elements (second may be int)."""
if isinstance(a, type(self)) or isinstance(a, int):
return type(self)(self, a)
return NotImplemented
def __pow__(self, a):
"""Raise a field element to an integer power."""
return type(self)(pow(self._num, a, self.SIZE), pow(self._den, a, self.SIZE))
def __neg__(self):
"""Negate a field element."""
return type(self)(-self._num, self._den)
def __int__(self):
"""Convert a field element to an integer in range 0..SIZE-1. The result is cached."""
if self._den != 1:
self._num = (self._num * pow(self._den, -1, self.SIZE)) % self.SIZE
self._den = 1
return self._num
def sqrt(self):
"""Compute the square root of a field element if it exists (None otherwise)."""
raise NotImplementedError
def is_square(self):
"""Determine if this field element has a square root."""
# A more efficient algorithm is possible here (Jacobi symbol).
return self.sqrt() is not None
def is_even(self):
"""Determine whether this field element, represented as integer in 0..SIZE-1, is even."""
return int(self) & 1 == 0
def __eq__(self, a):
"""Check whether two field elements are equal (second may be an int)."""
if isinstance(a, type(self)):
return (self._num * a._den - self._den * a._num) % self.SIZE == 0
return (self._num - self._den * a) % self.SIZE == 0
def to_bytes(self):
"""Convert a field element to a 32-byte array (BE byte order)."""
return int(self).to_bytes(32, 'big')
@classmethod
def from_int_checked(cls, v):
"""Convert an integer to a field element (no overflow allowed)."""
if v >= cls.SIZE:
raise ValueError
return cls(v)
@classmethod
def from_int_wrapping(cls, v):
"""Convert an integer to a field element (reduced modulo SIZE)."""
return cls(v % cls.SIZE)
@classmethod
def from_bytes_checked(cls, b):
"""Convert a 32-byte array to a field element (BE byte order, no overflow allowed)."""
v = int.from_bytes(b, 'big')
return cls.from_int_checked(v)
@classmethod
def from_bytes_wrapping(cls, b):
"""Convert a 32-byte array to a field element (BE byte order, reduced modulo SIZE)."""
v = int.from_bytes(b, 'big')
return cls.from_int_wrapping(v)
def __str__(self):
"""Convert this field element to a 64 character hex string."""
return f"{int(self):064x}"
def __repr__(self):
"""Get a string representation of this field element."""
return f"{type(self).__qualname__}(0x{int(self):x})"
class FE(APrimeFE):
SIZE = 2**256 - 2**32 - 977
def sqrt(self):
# Due to the fact that our modulus p is of the form (p % 4) == 3, the Tonelli-Shanks
# algorithm (https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm) is simply
# raising the argument to the power (p + 1) / 4.
# To see why: (p-1) % 2 = 0, so 2 divides the order of the multiplicative group,
# and thus only half of the non-zero field elements are squares. An element a is
# a (nonzero) square when Euler's criterion, a^((p-1)/2) = 1 (mod p), holds. We're
# looking for x such that x^2 = a (mod p). Given a^((p-1)/2) = 1, that is equivalent
# to x^2 = a^(1 + (p-1)/2) mod p. As (1 + (p-1)/2) is even, this is equivalent to
# x = a^((1 + (p-1)/2)/2) mod p, or x = a^((p+1)/4) mod p.
v = int(self)
s = pow(v, (self.SIZE + 1) // 4, self.SIZE)
if s**2 % self.SIZE == v:
return type(self)(s)
return None
class Scalar(APrimeFE):
"""TODO Docstring"""
SIZE = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
class GE:
"""Objects of this class represent secp256k1 group elements (curve points or infinity)
GE objects are immutable.
Normal points on the curve have fields:
* x: the x coordinate (a field element)
* y: the y coordinate (a field element, satisfying y^2 = x^3 + 7)
* infinity: False
The point at infinity has field:
* infinity: True
"""
# TODO The following two class attributes should probably be just getters as
# classmethods to enforce immutability. Unfortunately Python makes it hard
# to create "classproperties". `G` could then also be just a classmethod.
# Order of the group (number of points on the curve, plus 1 for infinity)
ORDER = Scalar.SIZE
# Number of valid distinct x coordinates on the curve.
ORDER_HALF = ORDER // 2
@property
def infinity(self):
"""Whether the group element is the point at infinity."""
return self._infinity
@property
def x(self):
"""The x coordinate (a field element) of a non-infinite group element."""
assert not self.infinity
return self._x
@property
def y(self):
"""The y coordinate (a field element) of a non-infinite group element."""
assert not self.infinity
return self._y
def __init__(self, x=None, y=None):
"""Initialize a group element with specified x and y coordinates, or infinity."""
if x is None:
# Initialize as infinity.
assert y is None
self._infinity = True
else:
# Initialize as point on the curve (and check that it is).
fx = FE(x)
fy = FE(y)
assert fy**2 == fx**3 + 7
self._infinity = False
self._x = fx
self._y = fy
def __add__(self, a):
"""Add two group elements together."""
# Deal with infinity: a + infinity == infinity + a == a.
if self.infinity:
return a
if a.infinity:
return self
if self.x == a.x:
if self.y != a.y:
# A point added to its own negation is infinity.
assert self.y + a.y == 0
return GE()
else:
# For identical inputs, use the tangent (doubling formula).
lam = (3 * self.x**2) / (2 * self.y)
else:
# For distinct inputs, use the line through both points (adding formula).
lam = (self.y - a.y) / (self.x - a.x)
# Determine point opposite to the intersection of that line with the curve.
x = lam**2 - (self.x + a.x)
y = lam * (self.x - x) - self.y
return GE(x, y)
@staticmethod
def sum(*ps):
"""Compute the sum of group elements.
GE.sum(a, b, c, ...) is identical to (GE() + a + b + c + ...)."""
return sum(ps, start=GE())
@staticmethod
def batch_mul(*aps):
"""Compute a (batch) scalar group element multiplication.
GE.batch_mul((a1, p1), (a2, p2), (a3, p3)) is identical to a1*p1 + a2*p2 + a3*p3,
but more efficient."""
# Reduce all the scalars modulo order first (so we can deal with negatives etc).
naps = [(int(a), p) for a, p in aps]
# Start with point at infinity.
r = GE()
# Iterate over all bit positions, from high to low.
for i in range(255, -1, -1):
# Double what we have so far.
r = r + r
# Add then add the points for which the corresponding scalar bit is set.
for (a, p) in naps:
if (a >> i) & 1:
r += p
return r
def __rmul__(self, a):
"""Multiply an integer with a group element."""
if self == G:
return FAST_G.mul(Scalar(a))
return GE.batch_mul((Scalar(a), self))
def __neg__(self):
"""Compute the negation of a group element."""
if self.infinity:
return self
return GE(self.x, -self.y)
def __sub__(self, a):
"""Subtract a group element from another."""
return self + (-a)
def __eq__(self, a):
"""Check if two group elements are equal."""
return (self - a).infinity
def has_even_y(self):
"""Determine whether a non-infinity group element has an even y coordinate."""
assert not self.infinity
return self.y.is_even()
def to_bytes_compressed(self):
"""Convert a non-infinite group element to 33-byte compressed encoding."""
assert not self.infinity
return bytes([3 - self.y.is_even()]) + self.x.to_bytes()
def to_bytes_compressed_with_infinity(self):
"""Convert a group element to 33-byte compressed encoding, mapping infinity to zeros."""
if self.infinity:
return 33 * b"\x00"
return self.to_bytes_compressed()
def to_bytes_uncompressed(self):
"""Convert a non-infinite group element to 65-byte uncompressed encoding."""
assert not self.infinity
return b'\x04' + self.x.to_bytes() + self.y.to_bytes()
def to_bytes_xonly(self):
"""Convert (the x coordinate of) a non-infinite group element to 32-byte xonly encoding."""
assert not self.infinity
return self.x.to_bytes()
@staticmethod
def lift_x(x):
"""Return group element with specified field element as x coordinate (and even y)."""
y = (FE(x)**3 + 7).sqrt()
if y is None:
raise ValueError
if not y.is_even():
y = -y
return GE(x, y)
@staticmethod
def from_bytes_compressed(b):
"""Convert a compressed to a group element."""
assert len(b) == 33
if b[0] != 2 and b[0] != 3:
raise ValueError
x = FE.from_bytes_checked(b[1:])
r = GE.lift_x(x)
if b[0] == 3:
r = -r
return r
@staticmethod
def from_bytes_uncompressed(b):
"""Convert an uncompressed to a group element."""
assert len(b) == 65
if b[0] != 4:
raise ValueError
x = FE.from_bytes_checked(b[1:33])
y = FE.from_bytes_checked(b[33:])
if y**2 != x**3 + 7:
raise ValueError
return GE(x, y)
@staticmethod
def from_bytes(b):
"""Convert a compressed or uncompressed encoding to a group element."""
assert len(b) in (33, 65)
if len(b) == 33:
return GE.from_bytes_compressed(b)
else:
return GE.from_bytes_uncompressed(b)
@staticmethod
def from_bytes_xonly(b):
"""Convert a point given in xonly encoding to a group element."""
assert len(b) == 32
x = FE.from_bytes_checked(b)
r = GE.lift_x(x)
return r
@staticmethod
def is_valid_x(x):
"""Determine whether the provided field element is a valid X coordinate."""
return (FE(x)**3 + 7).is_square()
def __str__(self):
"""Convert this group element to a string."""
if self.infinity:
return "(inf)"
return f"({self.x},{self.y})"
def __repr__(self):
"""Get a string representation for this group element."""
if self.infinity:
return "GE()"
return f"GE(0x{int(self.x):x},0x{int(self.y):x})"
def __hash__(self):
"""Compute a non-cryptographic hash of the group element."""
if self.infinity:
return 0 # 0 is not a valid x coordinate
return int(self.x)
# The secp256k1 generator point
G = GE.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
class FastGEMul:
"""Table for fast multiplication with a constant group element.
Speed up scalar multiplication with a fixed point P by using a precomputed lookup table with
its powers of 2:
table = [P, 2*P, 4*P, (2^3)*P, (2^4)*P, ..., (2^255)*P]
During multiplication, the points corresponding to each bit set in the scalar are added up,
i.e. on average ~128 point additions take place.
"""
def __init__(self, p):
self.table = [p] # table[i] = (2^i) * p
for _ in range(255):
p = p + p
self.table.append(p)
def mul(self, a):
result = GE()
a = int(a)
for bit in range(a.bit_length()):
if a & (1 << bit):
result += self.table[bit]
return result
# Precomputed table with multiples of G for fast multiplication
FAST_G = FastGEMul(G)
================================================
FILE: bip-0352/secp256k1lab/src/secp256k1lab/util.py
================================================
import hashlib
# This implementation can be sped up by storing the midstate after hashing
# tag_hash instead of rehashing it all the time.
def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
def bytes_from_int(x: int) -> bytes:
return x.to_bytes(32, byteorder="big")
def xor_bytes(b0: bytes, b1: bytes) -> bytes:
return bytes(x ^ y for (x, y) in zip(b0, b1))
def int_from_bytes(b: bytes) -> int:
return int.from_bytes(b, byteorder="big")
def hash_sha256(b: bytes) -> bytes:
return hashlib.sha256(b).digest()
================================================
FILE: bip-0352/send_and_receive_test_vectors.json
================================================
[
{
"comment": "Simple send: two inputs",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
},
"private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1"
]
],
"shared_secrets": [
"028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d"
],
"input_private_key_sum": "7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
}
}
],
"outputs": [
"3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6",
"pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1",
"signature": "74f85b856337fbe837643b86f462118159f93ac4acc2671522f27e8f67b079959195ccc7a5dbee396d2909f5d680d6e30cda7359aa2755822509b70d6b0687a1"
}
],
"tweak": "024ac253c216532e961988e2a8ce266a447c894c781e52ef6cee902361db960004",
"shared_secret": "028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d",
"input_pub_key_sum": "032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee"
}
}
]
},
{
"comment": "Simple send: two inputs, order reversed",
"sending": [
{
"given": {
"vin": [
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
},
"private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1"
]
],
"shared_secrets": [
"028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d"
],
"input_private_key_sum": "7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
}
}
],
"outputs": [
"3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6",
"pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1",
"signature": "74f85b856337fbe837643b86f462118159f93ac4acc2671522f27e8f67b079959195ccc7a5dbee396d2909f5d680d6e30cda7359aa2755822509b70d6b0687a1"
}
],
"tweak": "024ac253c216532e961988e2a8ce266a447c894c781e52ef6cee902361db960004",
"shared_secret": "028158aff7d61ea66b2fa7f555bc3c5937d1debbde16423d630f9aa7943e14d80d",
"input_pub_key_sum": "032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee"
}
}
]
},
{
"comment": "Simple send: two inputs from the same transaction",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 3,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 7,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
},
"private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6"
]
],
"shared_secrets": [
"03aa707f7b5e94b448abd28aa217e3d7a7cc6bb07f1a8d07be4de91bf7b1417469"
],
"input_private_key_sum": "7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 3,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 7,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
}
}
],
"outputs": [
"79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "4851455bfbe1ab4f80156570aa45063201aa5c9e1b1dcd29f0f8c33d10bf77ae",
"pub_key": "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6",
"signature": "10332eea808b6a13f70059a8a73195808db782012907f5ba32b6eae66a2f66b4f65147e2b968a1678c5f73d57d5d195dbaf667b606ff80c8490eac1f3b710657"
}
],
"tweak": "03aeea547819c08413974e2ab2b12212e007166bb2058f88b009e082b9b4914a58",
"shared_secret": "03aa707f7b5e94b448abd28aa217e3d7a7cc6bb07f1a8d07be4de91bf7b1417469",
"input_pub_key_sum": "032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee"
}
}
]
},
{
"comment": "Simple send: two inputs from the same transaction, order reversed",
"sending": [
{
"given": {
"vin": [
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 7,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 3,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
},
"private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38"
]
],
"shared_secrets": [
"03054f5c84b07182ba2a2e10a35e088778f95c04f059f4574b024c372eb8ce5468"
],
"input_private_key_sum": "7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 7,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 3,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
}
}
],
"outputs": [
"f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "ab0c9b87181bf527879f48db9f14a02233619b986f8e8f2d5d408ce68a709f51",
"pub_key": "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38",
"signature": "398a9790865791a9db41a8015afad3a47d60fec5086c50557806a49a1bc038808632b8fe679a7bb65fc6b455be994502eed849f1da3729cd948fc7be73d67295"
}
],
"tweak": "024cad5180a093d3af0f49f586bdf37f890920178e68e80561ed53351d0fa499ad",
"shared_secret": "03054f5c84b07182ba2a2e10a35e088778f95c04f059f4574b024c372eb8ce5468",
"input_pub_key_sum": "032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee"
}
}
]
},
{
"comment": "Outpoint ordering byte-lexicographically vs. vout-integer",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 1,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 256,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
},
"private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"a85ef8701394b517a4b35217c4bd37ac01ebeed4b008f8d0879f9e09ba95319c"
]
],
"shared_secrets": [
"02cb25a6e7c9b7c6d550e0413da63834678465b5e80853a51d0335d318296ac182"
],
"input_private_key_sum": "7ed265a6dac7aba8508a32d6d6b84c7f1dbd0a0941dd01088d69e8d556345f86",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 1,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 256,
"scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac"
}
}
}
],
"outputs": [
"a85ef8701394b517a4b35217c4bd37ac01ebeed4b008f8d0879f9e09ba95319c"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "c8ac0292997b5bca98b3ebd99a57e253071137550f270452cd3df8a3e2266d36",
"pub_key": "a85ef8701394b517a4b35217c4bd37ac01ebeed4b008f8d0879f9e09ba95319c",
"signature": "c036ee38bfe46aba03234339ae7219b31b824b52ef9d5ce05810a0d6f62330dedc2b55652578aa5bdabf930fae941acd839d5a66f8fce7caa9710ccb446bddd1"
}
],
"tweak": "031f9a80d0938cf980b51f7cc4fad713d49037f430646dff129c0570d75a40d8f0",
"shared_secret": "02cb25a6e7c9b7c6d550e0413da63834678465b5e80853a51d0335d318296ac182",
"input_pub_key_sum": "032562c1ab2d6bd45d7ca4d78f569999e5333dffd3ac5263924fd00d00dedc4bee"
}
}
]
},
{
"comment": "Single recipient: multiple UTXOs from the same public key",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566"
]
],
"shared_secrets": [
"02f6b40ff17f4010fe732ac4b0f2f211281aa09c9a5fb41f1c151ec2606fee9ec2"
],
"input_private_key_sum": "d5b8f02cbfe3f1d5295af9fb8a9320e859e9cb07115856486ab1a4e4fb89a621",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
}
],
"outputs": [
"548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "f032695e2636619efa523fffaa9ef93c8802299181fd0461913c1b8daf9784cd",
"pub_key": "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566",
"signature": "f238386c5d5e5444f8d2c75aabbcb28c346f208c76f60823f5de3b67b79e0ec72ea5de2d7caec314e0971d3454f122dda342b3eede01b3857e83654e36b25f76"
}
],
"tweak": "0319949463fc6a2368d999a2a6a2bcb2dbf64a2ac6e00b3ba5659780c860a6d9e0",
"shared_secret": "02f6b40ff17f4010fe732ac4b0f2f211281aa09c9a5fb41f1c151ec2606fee9ec2",
"input_pub_key_sum": "03e40664e222ba71e29b80efc907fa22a3c6c64f45e89dbb8511dc7a3712b0a186"
}
}
]
},
{
"comment": "Single recipient: taproot only inputs with even y-values",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1",
"prevout": {
"scriptPubKey": {
"hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
}
},
"private_key": "fc8716a97a48ba9a05a98ae47b5cd201a25a7fd5d8b73c203c5f7b6b6b3b6ad7"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb"
]
],
"shared_secrets": [
"02de9719785c6d09f71571dadf44bca59edba2af3e689c65cbc3bb5a4a387732ef"
],
"input_private_key_sum": "e7638ebfda3ab3849a5707e240a6627671f7f6e609bf172691cf1e9780e51d47",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"02782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1",
"prevout": {
"scriptPubKey": {
"hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
}
}
}
],
"outputs": [
"de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "3fb9ce5ce1746ced103c8ed254e81f6690764637ddbc876ec1f9b3ddab776b03",
"pub_key": "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb",
"signature": "c5acd25a8f021a4192f93bc34403fd8b76484613466336fb259c72d04c169824f2690ca34e96cee86b69f376c8377003268fda56feeb1b873e5783d7e19bcca5"
}
],
"tweak": "02dc59cc8e8873b65c1dd5c416d4fbeb647372c329bd84a70c05b310e222e2c183",
"shared_secret": "02de9719785c6d09f71571dadf44bca59edba2af3e689c65cbc3bb5a4a387732ef",
"input_pub_key_sum": "038180a2125f9d6dd116e1a6139be4d72fd5057dab6aaabaa5654817c11baeb3ba"
}
}
]
},
{
"comment": "Single recipient: taproot only with mixed even/odd y-values",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "",
"txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5",
"prevout": {
"scriptPubKey": {
"hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4"
}
},
"private_key": "1d37787c2b7116ee983e9f9c13269df29091b391c04db94239e0d2bc2182c3bf"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1"
]
],
"shared_secrets": [
"030e7f5ca4bf109fc35c8c2d878f756c891ac04c456cc5f0b05fcec4d3b2b1beb2"
],
"input_private_key_sum": "cda4ff9a3480e1fbfc6edd61b222f280f9baa0652002c1ffdb612efcc45d2ff2",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"028c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "",
"txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5",
"prevout": {
"scriptPubKey": {
"hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4"
}
}
}
],
"outputs": [
"77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "f5382508609771068ed079b24e1f72e4a17ee6d1c979066bf1d4e2a5676f09d4",
"pub_key": "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1",
"signature": "ff65833b8fd1ed3ef9d0443b4f702b45a3f2dd457ba247687e8207745c3be9d2bdad0ab3f07118f8b2efc6a04b95f7b3e218daf8a64137ec91bd2fc67fc137a5"
}
],
"tweak": "03b990f5b1d90ea8fd4bdd5c856a9dfe17035d196958062e2c6cb4c99e413f3548",
"shared_secret": "030e7f5ca4bf109fc35c8c2d878f756c891ac04c456cc5f0b05fcec4d3b2b1beb2",
"input_pub_key_sum": "020f0ab50f420ab1249bc2a21659c607f2873400853035aad0ca6d0ded04d62623"
}
}
]
},
{
"comment": "Single recipient: taproot input with even y-value and non-taproot input",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac"
}
},
"private_key": "8d4751f6e8a3586880fb66c19ae277969bd5aa06f61c4ee2f1e2486efdf666d3"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0"
]
],
"shared_secrets": [
"021cd92ff153e638d0a97bcd11fafc81c321b111f5ba1efff593371b7b688efdd3"
],
"input_private_key_sum": "7823ca0d4895515315a8e3bf602c080b6b732117272429e94751eb9b13a01943",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac"
}
}
}
],
"outputs": [
"30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "b40017865c79b1fcbed68896791be93186d08f47e416b289b8c063777e14e8df",
"pub_key": "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0",
"signature": "d1edeea28cf1033bcb3d89376cabaaaa2886cbd8fda112b5c61cc90a4e7f1878bdd62180b07d1dfc8ffee1863c525a0c7b5bcd413183282cfda756cb65787266"
}
],
"tweak": "0233c2a447b8b244e4ffcfb59fe365eaa3bb22288b31e2113b9998861f40d4d6da",
"shared_secret": "021cd92ff153e638d0a97bcd11fafc81c321b111f5ba1efff593371b7b688efdd3",
"input_pub_key_sum": "031ecda9c64faaa6cd57c9f3d7c62bcfc0763c2627ed8dc0e2c3018e9ff37a0bf0"
}
}
]
},
{
"comment": "Single recipient: taproot input with odd y-value and non-taproot input",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5",
"prevout": {
"scriptPubKey": {
"hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4"
}
},
"private_key": "1d37787c2b7116ee983e9f9c13269df29091b391c04db94239e0d2bc2182c3bf"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac"
}
},
"private_key": "8d4751f6e8a3586880fb66c19ae277969bd5aa06f61c4ee2f1e2486efdf666d3"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a"
]
],
"shared_secrets": [
"03d9437eb3676cf5cc00feebe68bc44c4567332e4b89788dec9eceb3779054442b"
],
"input_private_key_sum": "700fd97abd324179e8bcc72587bbd9a40b43f67535ce95a0b80175b2dc73a314",
"input_pub_keys": [
"028c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4",
"03e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "01400a4d0dca6293f40499394d7eefe14a1de11e0e3454f51de2e802592abf5ee549042a1b1a8fb2e149ee9dd3f086c1b69b2f182565ab6ecf599b1ec9ebadfda6c5",
"prevout": {
"scriptPubKey": {
"hex": "51208c8d23d4764feffcd5e72e380802540fa0f88e3d62ad5e0b47955f74d7b283c4"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "463044021f24e010c6e475814740ba24c8cf9362c4db1276b7f46a7b1e63473159a80ec30221008198e8ece7b7f88e6c6cc6bb8c86f9f00b7458222a8c91addf6e1577bcf7697e2103e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9148cbc7dfe44f1579bff3340bbef1eddeaeb1fc97788ac"
}
}
}
],
"outputs": [
"359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "a2f9dd05d1d398347c885d9c61a64d18a264de6d49cea4326bafc2791d627fa7",
"pub_key": "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a",
"signature": "96038ad233d8befe342573a6e54828d863471fb2afbad575cc65271a2a649480ea14912b6abbd3fbf92efc1928c036f6e3eef927105af4ec1dd57cb909f360b8"
}
],
"tweak": "02d4e4f2c4cdb71c9c39a700a9ee1a0fc05b98362a441183f5770af7d6e2b3038c",
"shared_secret": "03d9437eb3676cf5cc00feebe68bc44c4567332e4b89788dec9eceb3779054442b",
"input_pub_key_sum": "03bc118b1c8178915b716d6137633722c71adfe721551ec7b3938054691de6a2b9"
}
}
]
},
{
"comment": "Multiple outputs: multiple outputs, same recipient",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
},
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "d97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230",
"pub_key": "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca",
"signature": "29bd25d0f808d7fcd2aa6d5ed206053899198397506c301b218a9e47a3d7070af03e903ff718978d50d1b6b9af8cc0e313d84eda5d5b1e8e85e5516d630bbeb9"
},
{
"priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a",
"pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac",
"signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Multiple outputs: multiple outputs, multiple recipients",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
},
{
"address": "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn",
"scan_pub_key": "02062d49ffc02787d586c608dfbec184aa91a6597d97b463ea5c6babd9d17a95a3",
"spend_pub_key": "0381eb9a9a9ec739d527c1631b31b421566f5c2a47b4ab5b1f6a686dfb68eab716"
},
{
"address": "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn",
"scan_pub_key": "02062d49ffc02787d586c608dfbec184aa91a6597d97b463ea5c6babd9d17a95a3",
"spend_pub_key": "0381eb9a9a9ec739d527c1631b31b421566f5c2a47b4ab5b1f6a686dfb68eab716"
}
]
},
"expected": {
"outputs": [
[
"2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a",
"841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"03dd5fd04d3c8863be750a1bd7474df06161461d38d3ce1397a5c78cee112cdcd2",
"03dd5fd04d3c8863be750a1bd7474df06161461d38d3ce1397a5c78cee112cdcd2"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a",
"841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
"key_material": {
"spend_priv_key": "9902c3c56e84002a7cd410113a9ab21d142be7f53cf5200720bb01314c5eb920",
"scan_priv_key": "060b751d7892149006ed7b98606955a29fe284a1e900070c0971f5fb93dbf422"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn"
],
"outputs": [
{
"priv_key_tweak": "72cd082cccb633bf85240a83494b32dc943a4d05647a6686d23ad4ca59c0ebe4",
"pub_key": "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a",
"signature": "38745f3d9f5eef0b1cfb17ca314efa8c521efab28a23aa20ec5e3abb561d42804d539906dce60c4ee7977966184e6f2cab1faa0e5377ceb7148ec5218b4e7878"
},
{
"priv_key_tweak": "2f17ea873a0047fc01ba8010fef0969e76d0e4283f600d48f735098b1fee6eb9",
"pub_key": "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8",
"signature": "c26f4e3cf371b90b840f48ea0e761b5ec31883ed55719f9ef06a90e282d85f565790ab780a3f491bc2668cc64e944dca849d1022a878cdadb8d168b8da4a6da3"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "03dd5fd04d3c8863be750a1bd7474df06161461d38d3ce1397a5c78cee112cdcd2",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Receiving with labels: label with even parity",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "0259352add837b6686e8d22b87017814a46b3ad308702167c65bd5c8599cd28d1c"
}
]
},
"expected": {
"outputs": [
[
"d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": [
2,
3,
1001337
]
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5"
],
"outputs": [
{
"priv_key_tweak": "51d4e9d0d482b5700109b4b2e16ff508269b03d800192a043d61dca4a0a72a52",
"pub_key": "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a",
"signature": "c30fa63bad6f0a317f39a773a5cbf0b0f8193c71dfebba05ee6ae4ed28e3775e6e04c3ea70a83703bb888122855dc894cab61692e7fd10c9b3494d479a60785e"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Receiving with labels: label with odd parity",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "0208a144a18433a83f633c822c1bf5ee4c8c8e24601d6ca75e20a7dc57a0ff9280"
}
]
},
"expected": {
"outputs": [
[
"67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": [
2,
3,
1001337
]
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5"
],
"outputs": [
{
"priv_key_tweak": "6024ae214876356b8d917716e7707d267ae16a0fdb07de2a786b74a7bbcddead",
"pub_key": "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c",
"signature": "a86d554d0d6b7aa0907155f7e0b47f0182752472fffaeddd68da90e99b9402f166fd9b33039c302c7115098d971c1399e67c19e9e4de180b10ea0b9d6f0db832"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Receiving with labels: large label integer",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "03d85092bbe3468f684ce1d8a2a66ebec96a9e6e09e7110720a5d5faa4aa7880d0"
}
]
},
"expected": {
"outputs": [
[
"7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": [
2,
3,
1001337
]
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5"
],
"outputs": [
{
"priv_key_tweak": "e336b92330c33030285ce42e4115ad92d5197913c88e06b9072b4a9b47c664a2",
"pub_key": "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951",
"signature": "c9e80dd3bdd25ca2d352ce77510f1aed37ba3509dc8cc0677f2d7c2dd04090707950ce9dd6c83d2a428063063aff5c04f1744e334f661f2fc01b4ef80b50f739"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Multiple outputs with labels: un-labeled and labeled address; same recipient",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "03a6739499dc667d308baefea4de0c4a85cc72aece181bc05712d3919662610ff1"
},
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
[
"83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c",
"e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": [
1
]
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj"
],
"outputs": [
{
"priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914",
"pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75"
},
{
"priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a",
"pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac",
"signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Multiple outputs with labels: multiple outputs for labeled address; same recipient",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "03a6739499dc667d308baefea4de0c4a85cc72aece181bc05712d3919662610ff1"
},
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "03a6739499dc667d308baefea4de0c4a85cc72aece181bc05712d3919662610ff1"
}
]
},
"expected": {
"outputs": [
[
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": [
1
]
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj"
],
"outputs": [
{
"priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914",
"pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75"
},
{
"priv_key_tweak": "9d5fd3b91cac9ddfea6fc2e6f9386f680e6cee623cda02f53706306c081de87f",
"pub_key": "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c",
"signature": "db0dfacc98b6a6fcc67cc4631f080b1ca38c60d8c397f2f19843f8f95ec91594b24e47c5bd39480a861c1209f7e3145c440371f9191fb96e324690101eac8e8e"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Multiple outputs with labels: un-labeled, labeled, and multiple outputs for labeled address; same recipients",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
},
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "03a6739499dc667d308baefea4de0c4a85cc72aece181bc05712d3919662610ff1"
},
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "0244baa5cf5db444a9e922832ff2c88716b566a85d62e8235aebd91884d4f64942"
},
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "0244baa5cf5db444a9e922832ff2c88716b566a85d62e8235aebd91884d4f64942"
}
]
},
"expected": {
"outputs": [
[
"006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae",
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa"
],
[
"006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae",
"3edf1ff6657c6e69568811bd726a7a7f480493aa42161acfe8dd4f44521f99ed",
"7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa"
],
[
"006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae",
"7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3",
"83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701"
],
[
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"3c54444944d176437644378c23efb999ab6ab1cacdfe1dc1537b607e3df330e2",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa",
"f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b"
],
[
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac",
"f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b"
],
[
"3c54444944d176437644378c23efb999ab6ab1cacdfe1dc1537b607e3df330e2",
"602e10e6944107c9b48bd885b493676578c935723287e0ab2f8b7f136862568e",
"7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa"
],
[
"3c54444944d176437644378c23efb999ab6ab1cacdfe1dc1537b607e3df330e2",
"7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3",
"83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c",
"f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b"
],
[
"3edf1ff6657c6e69568811bd726a7a7f480493aa42161acfe8dd4f44521f99ed",
"7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac",
"f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b"
],
[
"3edf1ff6657c6e69568811bd726a7a7f480493aa42161acfe8dd4f44521f99ed",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa",
"e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca",
"f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b"
],
[
"602e10e6944107c9b48bd885b493676578c935723287e0ab2f8b7f136862568e",
"7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
[
"602e10e6944107c9b48bd885b493676578c935723287e0ab2f8b7f136862568e",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa",
"e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca"
],
[
"83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca",
"f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae",
"39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": [
1,
1337
]
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj",
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5"
],
"outputs": [
{
"priv_key_tweak": "4e3352fbe0505c25e718d96007c259ef08db34f8c844e4ff742d9855ff03805a",
"pub_key": "006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae",
"signature": "6eeae1ea9eb826e3d0e812f65937100e0836ea188c04f36fabc4981eda29de8d3d3529390a0a8b3d830f7bca4f5eae5994b9788ddaf05ad259ffe26d86144b4b"
},
{
"priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914",
"pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c",
"signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75"
},
{
"priv_key_tweak": "bf709f98d4418f8a67e738154ae48818dad44689cd37fbc070891a396dd1c633",
"pub_key": "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701",
"signature": "42a19fd8a63dde1824966a95d65a28203e631e49bf96ca5dae1b390e7a0ace2cc8709c9b0c5715047032f57f536a3c80273cbecf4c05be0b5456c183fa122c06"
},
{
"priv_key_tweak": "736f05e4e3072c3b8656bedef2e9bf54cbcaa2b6fe5320d3e86f5b96874dda71",
"pub_key": "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa",
"signature": "2e61bb3d79418ecf55f68847cf121bfc12d397b39d1da8643246b2f0a9b96c3daa4bfe9651beb5c9ce20e1f29282c4566400a4b45ee6657ec3b18fdc554da0b4"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Single recipient: use silent payments for sender change",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
},
{
"address": "sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqlv6saelkk5snl4wfutyxrchpzzwm8rjp3z6q7apna59z9huq4x754e5atr",
"scan_pub_key": "03b4cc0b090b6f49a684558852db60ee5eb1c5f74352839c3d18a8fc04ef7354e0",
"spend_pub_key": "03ecd43b9fdad484ff57278b21878b844276ce390622d03dd0cfb4288b7e02a6f5"
}
]
},
"expected": {
"outputs": [
[
"be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
]
],
"shared_secrets": [
"038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"037d12c02c3aed482658a28b8d1be030dac1daf995551491d74c00543af98572fb"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
"key_material": {
"spend_priv_key": "b8f87388cbb41934c50daca018901b00070a5ff6cc25a7e9e716a9d5b9e4d664",
"scan_priv_key": "11b7a82e06ca2648d5fded2366478078ec4fc9dc1d8ff487518226f229d768fd"
},
"labels": [
0
]
},
"expected": {
"addresses": [
"sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqauj52ymtc4xdkmx3tgyhrsemg2g3303xk2gtzfy8h8ejet8fz8jcw23zua",
"sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqlv6saelkk5snl4wfutyxrchpzzwm8rjp3z6q7apna59z9huq4x754e5atr"
],
"outputs": [
{
"priv_key_tweak": "80cd767ed20bd0bb7d8ea5e803f8c381293a62e8a073cf46fb0081da46e64e1f",
"pub_key": "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff",
"signature": "7fbd5074cf1377273155eefafc7c330cb61b31da252f22206ac27530d2b2567040d9af7808342ed4a09598c26d8307446e4ed77079e6a2e61fea736e44da5f5a"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "037d12c02c3aed482658a28b8d1be030dac1daf995551491d74c00543af98572fb",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
},
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff",
"f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a",
"pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac",
"signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912"
}
],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "Single recipient: taproot input with NUMS point",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0440c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b22205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5ac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac00150",
"prevout": {
"scriptPubKey": {
"hex": "5120da6f0595ecb302bbe73e2f221f05ab10f336b06817d36fd28fc6691725ddaa85"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1",
"prevout": {
"scriptPubKey": {
"hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
}
},
"private_key": "fc8716a97a48ba9a05a98ae47b5cd201a25a7fd5d8b73c203c5f7b6b6b3b6ad7"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 1,
"scriptSig": "",
"txinwitness": "0340268d31a9276f6380107d5321cafa6d9e8e5ea39204318fdc8206b31507c891c3bbcea3c99e2208d73bd127a8e8c5f1e45a54f1bd217205414ddb566ab7eda0092220e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85dac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
"prevout": {
"scriptPubKey": {
"hex": "51200a3c9365ceb131f89b0a4feb6896ebd67bb15a98c31eaa3da143bb955a0f3fcb"
}
},
"private_key": "8d4751f6e8a3586880fb66c19ae277969bd5aa06f61c4ee2f1e2486efdf666d3"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d"
]
],
"shared_secrets": [
"036f040608cd1e5ee79c54e78bea85904c895591f547beae080d0c5f6946c2730d"
],
"input_private_key_sum": "fc8716a97a48ba9a05a98ae47b5cd201a25a7fd5d8b73c203c5f7b6b6b3b6ad7",
"input_pub_keys": [
"02782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0440c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b22205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5ac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac00150",
"prevout": {
"scriptPubKey": {
"hex": "5120da6f0595ecb302bbe73e2f221f05ab10f336b06817d36fd28fc6691725ddaa85"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140bd1e708f92dbeaf24a6b8dd22e59c6274355424d62baea976b449e220fd75b13578e262ab11b7aa58e037f0c6b0519b66803b7d9decaa1906dedebfb531c56c1",
"prevout": {
"scriptPubKey": {
"hex": "5120782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 1,
"scriptSig": "",
"txinwitness": "0340268d31a9276f6380107d5321cafa6d9e8e5ea39204318fdc8206b31507c891c3bbcea3c99e2208d73bd127a8e8c5f1e45a54f1bd217205414ddb566ab7eda0092220e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85dac21c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0",
"prevout": {
"scriptPubKey": {
"hex": "51200a3c9365ceb131f89b0a4feb6896ebd67bb15a98c31eaa3da143bb955a0f3fcb"
}
}
}
],
"outputs": [
"79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "3ddec3232609d348d6b8b53123b4f40f6d4f5398ca586f087b0416ec3b851496",
"pub_key": "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d",
"signature": "d7d06e3afb68363031e4eb18035c46ceae41bdbebe7888a4754bc9848c596436869aeaecff0527649a1f458b71c9ceecec10b535c09d01d720229aa228547706"
}
],
"tweak": "02213b872c9a6ee28a0d861384a1b3e3ec7257f4855ed09b4323e3899f3b028989",
"shared_secret": "036f040608cd1e5ee79c54e78bea85904c895591f547beae080d0c5f6946c2730d",
"input_pub_key_sum": "02782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
}
}
]
},
{
"comment": "Pubkey extraction from malleated p2pkh",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 1,
"scriptSig": "0075473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 2,
"scriptSig": "5163473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187372102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d67483046022100c0d3c851d3bd562ae93d56bcefd735ea57c027af46145a4d5e9cac113bfeb0c2022100ee5b2239af199fa9b7aa1d98da83a29d0a2cf1e4f29e2f37134ce386d51c544c2102ad0f26ddc7b3fcc340155963b3051b85289c1869612ecb290184ac952e2864ec68",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914c82c5ec473cbc6c86e5ef410e36f9495adcf979988ac"
}
},
"private_key": "72b8ae09175ca7977f04993e651d88681ed932dfb92c5158cdf0161dd23fda6e"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f"
]
],
"shared_secrets": [
"034773b97ccad9791cb4213964ff9896ccd6581ee69345de5d114786d9d86b03a2"
],
"input_private_key_sum": "610e0f75fd05e5e80e088b57af0a46da06cb0700c0c5907aa6d29c6b4ce46348",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"02e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 1,
"scriptSig": "0075473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 2,
"scriptSig": "5163473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187372102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d67483046022100c0d3c851d3bd562ae93d56bcefd735ea57c027af46145a4d5e9cac113bfeb0c2022100ee5b2239af199fa9b7aa1d98da83a29d0a2cf1e4f29e2f37134ce386d51c544c2102ad0f26ddc7b3fcc340155963b3051b85289c1869612ecb290184ac952e2864ec68",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914c82c5ec473cbc6c86e5ef410e36f9495adcf979988ac"
}
}
}
],
"outputs": [
"4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "10bde9781def20d7701e7603ef1b1e5e71c67bae7154818814e3c81ef5b1a3d3",
"pub_key": "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f",
"signature": "6137969f810e9e8ef6c9755010e808f5dd1aed705882e44d7f0ae64eb0c509ec8b62a0671bee0d5914ac27d2c463443e28e999d82dc3d3a4919f093872d947bb"
}
],
"tweak": "028d6617f9bfe08604beb2188f4eebec923f5f8cc436fa6d14e4256e49bc32e7c8",
"shared_secret": "034773b97ccad9791cb4213964ff9896ccd6581ee69345de5d114786d9d86b03a2",
"input_pub_key_sum": "038b0d201fe111bdc0e6953772bd02a41959d25d5b2f66bcbe348af27bbdd42735"
}
}
]
},
{
"comment": "P2PKH and P2WPKH Uncompressed Keys are skipped",
"sending": [
{
"given": {
"vin": [
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 1,
"scriptSig": "",
"txinwitness": "02473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187374104e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d6fe8190e189be57d0d5bcd17dbcbcd04c9b4a1c5f605b10d5c90abfcc0d12884",
"prevout": {
"scriptPubKey": {
"hex": "00140423f731a07491364e8dce98b7c00bda63336950"
}
},
"private_key": "72b8ae09175ca7977f04993e651d88681ed932dfb92c5158cdf0161dd23fda6e"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6"
]
],
"shared_secrets": [
"0295a54c359da5b2640601ddbedb26e040cb97b6a3432e60b76d1258e85f72fa64"
],
"input_private_key_sum": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 1,
"scriptSig": "",
"txinwitness": "02473045022100e7d26e77290b37128f5215ade25b9b908ce87cc9a4d498908b5bb8fd6daa1b8d022002568c3a8226f4f0436510283052bfb780b76f3fe4aa60c4c5eb118e43b187374104e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d6fe8190e189be57d0d5bcd17dbcbcd04c9b4a1c5f605b10d5c90abfcc0d12884",
"prevout": {
"scriptPubKey": {
"hex": "00140423f731a07491364e8dce98b7c00bda63336950"
}
}
}
],
"outputs": [
"67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf",
"pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6",
"signature": "72e7ad573ac23255d4651d5b0326a200496588acb7a4894b22092236d5eda6a0a9a4d8429b022c2219081fefce5b33795cae488d10f5ea9438849ed8353624f2"
}
],
"tweak": "02b04034f00da0678507d1345b7d56fecef825a1151f9dc7d8ca6946452a9e1f43",
"shared_secret": "0295a54c359da5b2640601ddbedb26e040cb97b6a3432e60b76d1258e85f72fa64",
"input_pub_key_sum": "025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
}
]
},
{
"comment": "Skip invalid P2SH inputs",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "16001419c2f3ae0ca3b642bd3e49598b8da89f50c14161",
"txinwitness": "02483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"prevout": {
"scriptPubKey": {
"hex": "a9148629db5007d5fcfbdbb466637af09daf9125969387"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 1,
"scriptSig": "1600144b92ac4ac6fe6212393894addda332f2e47a3156",
"txinwitness": "02473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab",
"prevout": {
"scriptPubKey": {
"hex": "a9146c9bf136fbb7305fd99d771a95127fcf87dedd0d87"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 2,
"scriptSig": "00493046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d601483045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b97014c695221025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be52103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233382102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d53ae",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "a9141044ddc6cea09e4ac40fbec2ba34ad62de6db25b87"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[
"67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6"
]
],
"shared_secrets": [
"0295a54c359da5b2640601ddbedb26e040cb97b6a3432e60b76d1258e85f72fa64"
],
"input_private_key_sum": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "16001419c2f3ae0ca3b642bd3e49598b8da89f50c14161",
"txinwitness": "02483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"prevout": {
"scriptPubKey": {
"hex": "a9148629db5007d5fcfbdbb466637af09daf9125969387"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 1,
"scriptSig": "1600144b92ac4ac6fe6212393894addda332f2e47a3156",
"txinwitness": "02473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab",
"prevout": {
"scriptPubKey": {
"hex": "a9146c9bf136fbb7305fd99d771a95127fcf87dedd0d87"
}
}
},
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 2,
"scriptSig": "00493046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d601483045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b97014c695221025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be52103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233382102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d53ae",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "a9141044ddc6cea09e4ac40fbec2ba34ad62de6db25b87"
}
}
}
],
"outputs": [
"67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [
{
"priv_key_tweak": "688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf",
"pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6",
"signature": "72e7ad573ac23255d4651d5b0326a200496588acb7a4894b22092236d5eda6a0a9a4d8429b022c2219081fefce5b33795cae488d10f5ea9438849ed8353624f2"
}
],
"tweak": "02b04034f00da0678507d1345b7d56fecef825a1151f9dc7d8ca6946452a9e1f43",
"shared_secret": "0295a54c359da5b2640601ddbedb26e040cb97b6a3432e60b76d1258e85f72fa64",
"input_pub_key_sum": "025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
}
]
},
{
"comment": "Recipient ignores unrelated outputs",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn",
"scan_pub_key": "02062d49ffc02787d586c608dfbec184aa91a6597d97b463ea5c6babd9d17a95a3",
"spend_pub_key": "0381eb9a9a9ec739d527c1631b31b421566f5c2a47b4ab5b1f6a686dfb68eab716"
}
]
},
"expected": {
"outputs": [
[
"841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8"
]
],
"shared_secrets": [
"03dd5fd04d3c8863be750a1bd7474df06161461d38d3ce1397a5c78cee112cdcd2"
],
"input_private_key_sum": "ee55616ce5a93e508f03f21949ecbe70a2a0b107b6e1df5d98b4e4da4adaca1b",
"input_pub_keys": [
"025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5",
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "",
"txinwitness": "0140c459b671370d12cfb5acee76da7e3ba7cc29b0b4653e3af8388591082660137d087fdc8e89a612cd5d15be0febe61fc7cdcf3161a26e599a4514aa5c3e86f47b",
"prevout": {
"scriptPubKey": {
"hex": "51205a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac"
}
}
}
],
"outputs": [
"841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8",
"782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [],
"tweak": "0314bec14463d6c0181083d607fecfba67bb83f95915f6f247975ec566d5642ee8",
"shared_secret": "038efbcbc1b0938fba3bf59fea1219a3c54b6d6f9107560da05001407adc13f413",
"input_pub_key_sum": "03853f51bef283502181e93238c8708ae27235dc51ae45a0c4053987c52fc6428b"
}
}
]
},
{
"comment": "No valid inputs, sender generates no outputs",
"sending": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d641045a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5c61836c9b1688ba431f7ea3039742251f62f0dca3da1bee58a47fa9b456c2d52",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914460e8b41545d2dbe7e0671f0f573e2232814260a88ac"
}
},
"private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1"
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac"
}
},
"private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a"
}
],
"recipients": [
{
"address": "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv",
"scan_pub_key": "0220bcfac5b99e04ad1a06ddfb016ee13582609d60b6291e98d01a9bc9a16c96d4",
"spend_pub_key": "025cc9856d6f8375350e123978daac200c260cb5b5ae83106cab90484dcd8fcf36"
}
]
},
"expected": {
"outputs": [
[]
],
"shared_secrets": [
null
],
"input_pub_keys": []
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
"vout": 0,
"scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d641045a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5c61836c9b1688ba431f7ea3039742251f62f0dca3da1bee58a47fa9b456c2d52",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a914460e8b41545d2dbe7e0671f0f573e2232814260a88ac"
}
}
},
{
"txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d",
"vout": 0,
"scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab",
"txinwitness": "",
"prevout": {
"scriptPubKey": {
"hex": "76a9144b92ac4ac6fe6212393894addda332f2e47a315688ac"
}
}
}
],
"outputs": [
"782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
"e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d"
],
"key_material": {
"spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3",
"scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv"
],
"outputs": [],
"tweak": null,
"shared_secret": null
}
}
]
},
{
"comment": "Input keys sum up to zero / point at infinity: sending fails, receiver skips tx",
"sending": [
{
"given": {
"vin": [
{
"txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e",
"vout": 0,
"scriptSig": "",
"txinwitness": "024730440220085003179ce1a3a88ce0069aa6ea045e140761ab88c22a26ae2a8cfe983a6e4602204a8a39940f0735c8a4424270ac8da65240c261ab3fda9272f6d6efbf9cfea366012102557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975",
"prevout": {
"scriptPubKey": {
"hex": "00149d9e24f9fab4e35bf1a6df4b46cb533296ac0792"
}
},
"private_key": "a6df6a0bb448992a301df4258e06a89fe7cf7146f59ac3bd5ff26083acb22ceb"
},
{
"txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e",
"vout": 1,
"scriptSig": "",
"txinwitness": "0247304402204586a68e1d97dd3c6928e3622799859f8c3b20c3c670cf654cc905c9be29fdb7022043fbcde1689f3f4045e8816caf6163624bd19e62e4565bc99f95c533e599782c012103557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975",
"prevout": {
"scriptPubKey": {
"hex": "00149860538b5575962776ed0814ae222c7d60c72d7b"
}
},
"private_key": "592095f44bb766d5cfe20bda71f9575ed2df6b9fb9addc7e5fdffe0923841456"
}
],
"recipients": [
{
"address": "sp1qqtrqglu5g8kh6mfsg4qxa9wq0nv9cauwfwxw70984wkqnw2uwz0w2qnehen8a7wuhwk9tgrzjh8gwzc8q2dlekedec5djk0js9d3d7qhnq6lqj3s",
"scan_pub_key": "02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
"spend_pub_key": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
}
]
},
"expected": {
"outputs": [
[]
],
"shared_secrets": [
null
],
"input_pub_keys": [
"02557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975",
"03557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e",
"vout": 0,
"scriptSig": "",
"txinwitness": "024730440220085003179ce1a3a88ce0069aa6ea045e140761ab88c22a26ae2a8cfe983a6e4602204a8a39940f0735c8a4424270ac8da65240c261ab3fda9272f6d6efbf9cfea366012102557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975",
"prevout": {
"scriptPubKey": {
"hex": "00149d9e24f9fab4e35bf1a6df4b46cb533296ac0792"
}
}
},
{
"txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e",
"vout": 1,
"scriptSig": "",
"txinwitness": "0247304402204586a68e1d97dd3c6928e3622799859f8c3b20c3c670cf654cc905c9be29fdb7022043fbcde1689f3f4045e8816caf6163624bd19e62e4565bc99f95c533e599782c012103557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975",
"prevout": {
"scriptPubKey": {
"hex": "00149860538b5575962776ed0814ae222c7d60c72d7b"
}
}
}
],
"outputs": [
"0000000000000000000000000000000000000000000000000000000000000000"
],
"key_material": {
"spend_priv_key": "0000000000000000000000000000000000000000000000000000000000000001",
"scan_priv_key": "0000000000000000000000000000000000000000000000000000000000000002"
},
"labels": []
},
"expected": {
"addresses": [
"sp1qqtrqglu5g8kh6mfsg4qxa9wq0nv9cauwfwxw70984wkqnw2uwz0w2qnehen8a7wuhwk9tgrzjh8gwzc8q2dlekedec5djk0js9d3d7qhnq6lqj3s"
],
"outputs": [],
"tweak": null,
"shared_secret": null
}
}
]
},
{
"comment": "Maximum per-group recipient limit K_max is exceeded (2324 matches): sending fails, receiver doesn't scan beyond limit",
"sending": [
{
"given": {
"vin": [
{
"txid": "3cde0e7ad8adf24a4e52fd18efafffb94f73f4c7facf2627a5b588ad1c9db87f",
"vout": 0,
"scriptSig": "",
"txinwitness": "01407ce01bc5ef2e4aae353e7f291fec32623d6a491b5421be6dccc70345f32ebae5baa6654c60c074e72da76fd06b343474370e56d3ec0413156ec6261757125ad4",
"prevout": {
"scriptPubKey": {
"hex": "5120bca87f72e604e8850064552bedf380ca4584227057efe12a6cc238470658aaa3"
}
},
"private_key": "0000000000000000000000000000000000000000000000000000000000001337"
}
],
"recipients": [
{
"address": "sp1qqtnvg7hxjck9ag24naytgd7pjwsmevwh95ydwht58w3uh7uw0ta7kqmk4a3pm24z0yepw6aw27pku56md0hq5ace0l3p3jstkqaajwrsjqc5dde5",
"scan_pub_key": "02e6c47ae6962c5ea1559f48b437c193a1bcb1d72d08d75d743ba3cbfb8e7afbeb",
"spend_pub_key": "0376af621daaa27932176bae57836e535b6bee0a77197fe218ca0bb03bd9387090",
"count": 2324
}
]
},
"expected": {
"outputs": [
[]
],
"shared_secrets": [
null
],
"input_private_key_sum": "0000000000000000000000000000000000000000000000000000000000001337",
"input_pub_keys": [
"02bca87f72e604e8850064552bedf380ca4584227057efe12a6cc238470658aaa3"
]
}
}
],
"receiving": [
{
"given": {
"vin": [
{
"txid": "3cde0e7ad8adf24a4e52fd18efafffb94f73f4c7facf2627a5b588ad1c9db87f",
"vout": 0,
"scriptSig": "",
"txinwitness": "01407ce01bc5ef2e4aae353e7f291fec32623d6a491b5421be6dccc70345f32ebae5baa6654c60c074e72da76fd06b343474370e56d3ec0413156ec6261757125ad4",
"prevout": {
"scriptPubKey": {
"hex": "5120bca87f72e604e8850064552bedf380ca4584227057efe12a6cc238470658aaa3"
}
},
"private_key": "0000000000000000000000000000000000000000000000000000000000001337"
}
],
"outputs": [
"5cfb6fd7a7e5d2af0fee276f2104ce2e5c86cde7955b98f2f1fb32811b448f2f",
"da290e0d79ead5cd2e5d150aac80dcab54dbd0e68f241a6c34dc30906eabd13d",
"d4a2b1458f0c8b20d756bde8e545560d7e7a65f6b4158f01ed34a913ba3a4603",
"24752e555b0edcca123f769113692224bf1e6db137cddeb7d69ae52e51144e9e",
"c911f722ef9a3594d6b85c585d4f3ed8dc437f850591dc627a0154723644114b",
"ef91ddaa83a0b748d638dc9be8c9771b049a04815f03967b7ee993bde6c260ab",
"ee4ed334fb38af95f52c6bbadcf2f491e646b9cc8ed31da67635f36c3cfdaba0",
"a17d61b4772e453b32782744902261e051510cbafc04f086f53480d1ceee1a9c",
"44d89f5e903739072e3aff8a3eb2f351520f77ff288ac8be277be3f28834bdd2",
"3eff02a4a04d66d63f6bc93a693f23db703f351c0a1ff1656b907ed348a9a35f",
"628c23a6e21e6a47b80274fc80e4decb98ff79b8040c7f9ea5972e4920b62b6d",
"e72190c0a5ea167c2663b18d378520b9228da61ebbc99c3fa2af39e01fb9501e",
"24183edbc5b80588e0e5b803e924e77fc1cab1afca54cfd285dad9bfc2a34f6d",
"c45bad25a223f0f617e8167f858037907e4454210a745f3b9798c8913646dfc6",
"9f9cec85011d7f718f96ee1a2940df21920a857cd1a545255579cb615f285a42",
"8c60891f9bc2f772efc51d44f7cc885161412835b6fd5aac3b0cf57c3c2f9154",
"85ac46a6ac9569ed67d1bc5342ed3b591af5e01581d1b09bcb2c71deb9b2c2c9",
"8a6bfe47e616c6854fc797a4af53ef51c942b99eae18f316594fc8eb8869ca05",
"ed5e1aa6a8b4e805273367b8ec3ade16ed6494270fc2169ba920b89770efe8eb",
"2448503c55a1a7035c069e1d5461b81774c43bf6061421fdd0157009bfe96a8a",
"d0dcb3d7b551eac8d31fceccb83df415c554860d5541dd08ff5fa0028ce5704f",
"f11a298b54b650613e0b0183552c9c9e42c3812e03cf713d351ef71106b6ee3f",
"49749206f23791f858c453cb60160d48710075bdbfd33907b0046d10f0b0295e",
"3fbfdb52cbf0ea9e6655a211748bf2ac2dc92ff3cfeeef0f0a26be9987016de0",
"d4a29144511981919cadbe8227fc68379e85d3fe399f177c2ae36c304b6ad6b0",
"c586cc196ff56f42396f426a0200afee3a6c41058d81f19caf6536ec0efd5605",
"c666994f027ceab025256af28d8ea6aec452fb8b0e1f69e7e13a4f3c5119f4ae",
"5c9216cc4529c3f9c62caf70b04f8354ce9ec2cabaef745092bea1b160328fda",
"d9aea54323503d78c026a8cd465c19a6df54b32ee866714d190e8260054361da",
"ba71f87ca1d74eee115d8e8a26293fe2c88d9d66cff185a7a079282f02f931ad",
"b8b930666b2df74c33dc8963221080c115246070e3fcd51f39bee71312db4fc4",
"b7f42d2f18a3ac61f570b64ae6864f7dbff774a370ba27358d76797e841d5304",
"d636d179055241a0f8bb7db193912da513a8999684d9829b266985a8083819a9",
"be9622aec125f9605bcee193a99ca27c16bc591122ff8b44c511a85e6f63ec9d",
"af5beb25776f84fadd6079c3ffd85775a35ad74096a58229e1d5076d836ca25d",
"75fb55ec31e304456f663c9a66321e67f9d9bd8f43749494acc5189ed57b0d4a",
"8dfebff33c514486d06eeb4ab8eb8471496556858c4382f73780620101a77f71",
"93bfd4e75706951de4a59c7f70c5d2ce4c617b4bde0b0b23ae046df096116726",
"b6eeca22f43bd62a4fcb3eee719e07d39ea703fa0707970fc197916f2efebbb5",
"0437c3971f73342e5c41178590e1cb1364cb855b2d20b7b6c1c1ed0e7da5b57b",
"d284c831cd9d52793977925ce3111b68f36d1ea456e46716158fe6947fb6d635",
"d95b8d2789fd06cc764d47cc7e0697404220ae8f938ef47dcc9a1bba299fbb9f",
"33599fb1fe313b5a2680b126bfee93cb097d938915d425a63e307e5834479b95",
"05ba86903fac2f02ef2e152072bc6067008ee8ee34ce55ad460801303373eaab",
"0b757802e56728b6d5b28e671a90de573d7251a47fc1bcd9319b617cac8e1463",
"b4a2451e725e4cbcdf47fc736139cfe29c847e2f75cbb7653d80c8522bd48a6c",
"8dd800c3a7cb1ee60f52db3bb69413c4c4247b0b134576552c675970f9903c9b",
"4de21129c6fdf5568040346bbdda272caaadd58218ec6f1f152518068dac4d4d",
"22f6927eae0c3717395df6483d756028839fbf0814f8cf0391159efa65dd2854",
"192d26fe0bc772c705c2657dd5c5033ac41ba408793e6c721f74c53747be16e8",
"9527b8e19570a16ce2d8dd3620dfd915e461bccc82340fe682f7f811b978814d",
"f84039ff95cd44f842d7cf6982a726957a89d90bb151a368e62770720d3efbee",
"b5b36dd84b352cddf715246d0463984b9d7894f50b566a20042c4d485df41946",
"592e1bd733a1095b9e5b770021769090df0c001260803fce9a9b761ba697a5e7",
"dd2fdbd6932d8b56d6ff91db3ed28f282a6ca01588ee5a552d061da215580411",
"82f95ef71d4d0b32e3f0cef89e6e90a8c271cd5536b38c507fc69b354ab51062",
"1800903b2d5f8483a12f0b98a5b35ed39d6cf8f4a52f495395f1816d6e3c139c",
"121a2c2ea70a6986af8bde71b7f75ac9f9e1189eeb9756395e7281702f01936d",
"8578df7e8ec4b068f64dca679310894afec095dbbedbefef5944c3a319809b8b",
"5cebde1dbb352ff62841d7c50c3c45cd0fd1b7b3ebe884a7cf29cef6686695ab",
"362f7a73f2620ea061586b5edbee01f9c026ae6e0d95131c570c44933fc41f10",
"3a19b5976236d44a3d1d6920b348fcef9ec830aac56aa672353c711471ebc36a",
"842c43c5293b03811165f1ff7e04c189ccd355fe08d37808a843a0995541c075",
"0ab1fdbf7117c88aed3f882d5f7dee8964c9246030086b9ee3e2ebed4eb2c731",
"7cf8ca4463d4bd500cc12623ac9d3984cc48e7fbb98bebb4a498c2fd66d54cde",
"631676f3369eb479686256cef33c4fb061c212cc215ab442d8f7837c039ddacc",
"2fff6de5386b65efe6062cc2242b692a1e811a083612ab79fa7f7517f1488767",
"3c7d8b7f2a56e22ade186a70a3039b4d4e4e3c0be6e661770b0a7b2ef18b178b",
"e030882188281a754c00706f621084f96869bf95bb5d005ccc7b2649fbfc747e",
"072cb899c3eb621240792a39bf727bf59398329748317d5ca1addfd8ee2f7e92",
"37cfa6b7214e99bbec6323802115b9615b10851ac85cdc26f213b9532fdefcb8",
"68b14b71ad6b5e2d41ef47fe1b9229a0b8297ede0812d1b9cb95aac185d1a5b8",
"652ef549580cf412bb217fb15b2a0a1db8feb3c79969b95364a80dd97d565f09",
"dd3504b7563a65115a050505bc88ee23a50e37c354773cac329355c16c43d839",
"6d7f05d6ee71459d2ea982f7a5cd4a251d7466d4892e6c8b6aaf45eec66472d7",
"14c28adbf9008d0cbcc978006b6c1ec7be51a134bd5587e94ee33844b62c1ffb",
"f9c20067f16feaaf3f8daa8456dd9334725ebdc8b49b4f74f5a02c38ef5f2804",
"e2c537948a01054b7a0d630952c2ddd395a3a265d618e22ee9d99d4597f82322",
"70e3a71945fee29350b5b10a8ee8dcbd19c2f734e22407bb6b50ec3acb1035a5",
"effbced848df72cd467b1ada7353b1ddc0b7f3f08190c0f2fc747f18303ed9f8",
"02d6eedc5abc295bcfbd4c30a8fa3406c8256d8e51f4714800b4aecb795a976b",
"92134c6158993a0390af92565e166418561c9b157989d02304b68c2ee1babe14",
"6065e3e3aff3e2b2f33bf4af9256e9368b8a303335b0587c8cc9e31cb9db42bd",
"732fd2ba9efabc6d79bd7404c1c6f1d5c1f14c9bfe02ee1320621824847935c2",
"209f9c958b5f4813b32205a44d05c83aa1009cb7b9c7343f0ca3717ae069defc",
"1d274fcb65b6d4c846e95030c37851a97d161f926ed88f6c4dec4ed7007fc23b",
"1d3787106cf47e1e9d08761a6c6f427ef6c07d4a571f23d340ae2d31d34b1d8e",
"5697a3f56a0a2a6bd6991ba05559df9b526d5c42e19604c398548a7cb0dec0b5",
"8c0f581f38238215f10f8017e3d234cbda9d94ca017bbd6b076ac8666014b3d3",
"78f061b0fc912fbbeb0d207b92528ad78ded55ec145c8f18133991847fb9cbe9",
"1e3555081a869f3aafa3d74d6b5afa942baace60869ecd4cd33635f84602b715",
"4f0e36ac0c4813db3fdf79d85ef0db89150dc1be2c879ba06299c049288ab8be",
"6b048c38924b7a1f970cdff081124b739202b703db5c17bafa4ad23a5bcb97e9",
"a5f5e9238aec20bd706262f64671ca2d05961f55ca383953d489edf857e4b2a4",
"a047b08e2af7ae5bfb9e54f98051ff7cd5e7dc88a25afacdd9a324526cd33c63",
"66ae2b9513a0e0ad125001bcd5f3a36e18b4ec009db4020ea4afc4951cb39a34",
"621d8269c8f93b6336f8b7480516d2191cfb15a1d9501463771d0fb70c1afa33",
"76b94079066bff52a077ba1d1ba8cdec4d6484d1ce2f7454b2b04aa3d9cf52ed",
"33c6a108f9d4fe054c085991d89d2a5c32b8f108c95b0e688c5763424c283e54",
"52575ed2ad84295a070a99e7785ff0e4dd32a93d3830be7f7c2811804f3df2f3",
"158dfe014c271c148b38459ef16b49cc3b5c6bdfe052795a6f6a6aacbb3e47b4",
"d471729cb231deeb2f1a67f91962ecfcb9e8c66f66b6b79fe1117d34ae86a7c0",
"e086b1a09ab5307d953e25366b1acf7c41047a926aa6a4d122c5a34e3e0d93d4",
"d541d825401a1734d9961fdb4f0e9ce7af220c6929648e0aa2e885cd28696343",
"a555af7a52ac07e681c247f1d6597f8240d28e76036bbf3b2be1f7cfab90dfd6",
"8598fe7a4a6c6fa865c0ca8e8e65c96301c80965e19e48f5d4ca29ac073551c7",
"70c9ac61ab3508a7419ead73503d8fe51b4ecba73a55d4b167cd4db6c9b0cb8a",
"e594eb83b38ad916176abff3f0ec16d7a814a461012c8f9bc8286274af3f1856",
"fa4e0df6df82f21050394fc2caaa8a8713b131d0d1f7d21eb92b56796095bf17",
"891711c535579b555105e5ec18ea0f2f610c6fe5126ff0f6a4257e99a24033c5",
"f192c9b2c49dab7515d405052f825abead30ef9a870ba3bdad98c1d6256be461",
"70c22f6ceb81744c83eb8dae69980f4583c75431457dbb14f5ecd6c9fae3e63d",
"7d563f44bdfcb2a10ee053f4c05b8d46fa90d44822775f97ee8cfbdeda7a4ca1",
"c09b3df69eaa232a9119e2fb805cdccacb658b2fb9c7f3a2106c8399aa928033",
"15b4b3d50fef72de80fef6e3351dae0f203902e4c4db8ce8d8737b67aed9104d",
"c9b7718633714b3ce1b489f13e53fc647be53cba7703f07a35a8815245b23ff3",
"2d344af9852fc2451ca5d2ed7155e074efd2c53ca9cbed7f48c74658967aeca6",
"c8b778b5c1fc378365d8b342915215117c3d365e12f61f3ccefbe4091879e373",
"1deb076e44c029027c1aa10000305c3eded5d401a036c21a4dd3d3455c0c33a1",
"d2d2dfe410cefbae2309e746690818e8d52dcd80ebd192cddaa00204b6833d05",
"d18a0a0bcc678908ff00b236296f0a955a9aa52a802ee4175849d0bcb3d6738a",
"7af51e08357e455e4dda86d60da75899b5ffce4bebc7f96037d1e404b1260ebe",
"65b930580f9738e1a7af2ac56faad5bdc6a417e75cb872b7f62513f4e8e36b33",
"71c8e88c7c478a4d919d0c80d351331102584d032d82aa25510801e18bb5d6b9",
"2166bad16a6e4a1f77a22b0fb13f7f11d618a123c3c077dbf1ed1504ed68cbb4",
"717a3a5903c2b12aea8be15599ea9864259a964c0139125e649fefbec763890e",
"0d042f5767f6cb2f94526b5b6da8ef986e4a5927eb5f734bdeb6c6ec3bb8211a",
"bb67d586774ae9f3653c609dbdd98f216315b54c0ce24ad9e359d0c2c21614a3",
"945b2962ec44c54ea25e3e35e32a2362c130fc3a9495b16871e8a2eadbe457e7",
"7d5324e5e158c82388cba0d497530c6de0c1ba97131688931c03dbfc60ca7541",
"21805a8f8d43aede3e927b80ef04924d388e96f3cc3947a0dbc1bd1b812539f0",
"27ec492fde5fc3d3784359d9a270b735c1820bc4a6f15ac87797d97de047a6b5",
"4fda2f855ab08a8d4dcba1874402e1662315c872e3ad55681fc4d6c5a89665a3",
"b0dc69204deaa17ac4e0f197f8b23211418b5d54f5bac55414445a66c57fd6f2",
"209262521ab45331639a57523f2e3bbf8250052b84fba81c50c990166a6f58b6",
"b02857949ebddecc58aaba80b9d635ae95cf71f4bfc5ea8fbe05fc55d4c73e96",
"5194133163b28182a261ce0473b1f3ab991a53a08d0e813d3bfb533cfaf1255b",
"c56fe98848fe79124ae1ee09d1b214ee87da51c1440134210c67fe15bf6d1bb0",
"851d949ac91f439ec84f07c481598728ca93acf79cb6505bd77ef776559275f1",
"eeccaf0cd29cb002e2140cffa9fe2c08c53ffd73b99167f4b5e6ab5c94481066",
"821f1058ae54732723937c5ae535cdc0a9ce673eec7fc02bd03c240c93aff24c",
"de836fd21ce91d4a6add661f5d259d0ade4e0ff927d03f67ab5d0b24bff37242",
"fdac0470c61d81d1498e4e0c6fc4ca5ccd02f727413e33c84478ebe844feba13",
"469b4f5af2b2377dc09e5824af17c57f1dd8fbe02294059e16641c1307eff125",
"b77348b40d52d531378dead61cf2eb6fafb4c89f85285a98cd4b6032c0e30a16",
"2cf9616aefee83eddb2df0dda1a3331185f0b772c3a8a62ea3ffbb325290f32b",
"2d23a9035ec627187108b9d13b24134d69ad7cb6f77d2c3ab939db17cc6f129c",
"4925a7008584e04fa769661dd9eb766fe2ea3b66622691249142ca155423f368",
"69090019b3c1635da9d9e4661f55863cb3ab561bcedf2632360745e62b06afc5",
"5cecb744c3e65889c22e14a58e42bb69d068c721f1c547c8c704fbc688c6c6e2",
"2f7371ba97f17c64c4c487742f83755ab61aeb1ee537bcd5f16beb4440d0233a",
"9d1e3dcad79b153296a67238771b91a92c430432a9cc9f7b2ad7667fd67b4de3",
"e9a34ca0067dbb6dbba48e736e1d32337cca5e93f2b76229fafef501979d84ae",
"4d5d36724a2baa0d73657a140493a9ba95e1de95cad74c9753eaad785ac18cbd",
"d135fe3d44b6b0875c1662ecfe33556be0f1b39bc8279dc8730d5e9e351f36ae",
"1fb8439b54ead68f72b7ba4fcaa5041f38d313d92826b57dbda299dab06ab716",
"b96e8d59a7c1006f15b0ac10cd35c08a8008e0c2ecba26d87db3f08c0f6fc991",
"73300dd04c53d270420023957c50410147ea4a2814085d3b98ef25d8d44afeed",
"6941323a74081c1ee28846c4ffe3b4023b29eb3a3b64d0d2dea0f47349fc2138",
"f7cebcfc608a982a3e11b3941abf482d8108a7d59c3719279563788173a2cc6c",
"b76c687ff464c50b58e4231379c5105470264de2826574e8d7fc58d6889d0753",
"f0148c800120bd34159684196bdfb34f08d1af93c74232dd9f59e2ca0a66aed4",
"51e0334c027b5e43e7cd557e301bceb0189903a189dadec2a11c1e2d675e3e9c",
"32a3f110862c9340106f2dbba85c8af5d7ed575635d55cf2af7637a59c83103d",
"b35bc38a430ebd8c7584d0c90bdaaa15aa252b3977fcac456646e839746f9c0a",
"87ea74b899c0b929e83bf31a8d146faea3d26140ea99a3d0d3e0be93a4d6eeb4",
"e222ed1dfcf6505fad77b9cf2e3e38d0ea86fe89a969b88e729ebdf2e6c63f0e",
"d5e92da54ae3432603ea96cd770f4da442f7dcbd0a4f2d82774a33675690297e",
"01e372d5dee08beefd03317d0897d5ef1c5126bbfe00c8967ec9aa05523c5e25",
"369df1d577f66ea1c93b58b770783a74606907713b14ad86b316319d94f84ac7",
"ef7e648860a8b3490440f2a8d541a268b4613f4a94c0dbf685df5973b55f0e88",
"f19f4b29d4d7b70abc4624c01a4ef7ab772bd4feae8cb33bb502f30a11dab29f",
"8ccbea64791275ea047a3648b092ed281acfa21f62a4b50ed111b954e534a697",
"d60a6b4846f218a8369db8deb45972760a1df33c7532d0ef1ae679ba0294216e",
"7aa4638be336fb77bc1ac5dfcd3f5ae002aeed8c42bb46475f718e3c278f0097",
"06a82a57d7951a5629a1153240f6b1f09c150f0b9b777d7c64a0a628e24a0bdc",
"d23d2ce73e24b434f2fe5a6eef2b88eaed4e57848cf357055da6914bb234851d",
"0dfbe791dfc86570004538c64195a7702e33ed121490fee5819537676a021932",
"8e2a510bc84d4600f25812994dfd5b4566c281a153e459cc9460c006ababd093",
"cf73a8cdabecf4323a194f3249cb5b1674037f779c747690eb0d9c9f703f7c8c",
"a8999928014db24e80a27cfb572eacf902b50cdac259b5be80229fe73260ce08",
"f2a13b90ffda09f999ca5d7f9a2cd171ac33ee2a9a889c70a2e2d454dee0ddeb",
"a5fa0377e644e743a38f0b427adefab90d218ba8e9e2894fc1f1f71cd815a92d",
"1a27dc6f452362eca3745218915d24726b72f5d6963a9c41a34b9b7a12aeedda",
"74657a8b361a7d235d94878cf2ac2cf3e18dbd76fa1a88440e3be7ac7a8dc54a",
"15059499248e579d66827fb6700d3c31ab3c1e824fd0b0de583668631f31abe1",
"21dab269f60f67bbce69447b7fec674662bbfe2bf1fb998e164d44e92086a89a",
"a266bfdd44a5969f46985337359fe5ebb6083b8a21cf310ebdf4a62aa16dcb89",
"612ebf41822f25ab638867c1232596a83de60c5bc1a62aea81464cd87c50a53e",
"7c7e8506946118e3af1f5c36f94fc5cddb945e6346a009d21934ea0a384778ac",
"82cc3dcfa10188e9cee8d84a60ab86cef7b564208734ebe8d1c6f4fd583e5466",
"7ec2dce8c901de5c5b5da218d4ca6c304c4a8691568631b1d9d625deab025e8a",
"baf8884aec756bba04cafe11f82e84d5721bc66689a59418e24dba0471e5ed9c",
"2033109b98dec88046390619d056fba7ab1e207591b049b5ca4e5ca7905a0736",
"04337d0bc9948530c0f6bd541442a14cb8da9342cbaae84ffd21f49a3a4ff9b5",
"95a390c9ff01592aefaab09d6409dd618263bd596d5134e024d2e04fc080f9d2",
"c314b11e8ab0957c8c11770b6dd3bf9ba8a281c312f0c25d0dbdb0dab2bf6176",
"9372c5731f8e38ca30845e277b499e77dd3f5fa442f5496c4bdde0512de1e922",
"84ff2e4e6c23f0953aec51c9d8642b1d71c653731d7585fdf021e045ebaa0c11",
"c4472b40a9ec2b01de30d79bafcff2cd4853edb77724a5ae02f4387597deaf53",
"de59785aaed498deb953dc239d06847baed05797fe3dd2420a5c6f35a4ddaa1b",
"9622558b5b744223868445c32fd92ff2ba0d9c56f5b34bbf9de7f3e26206a277",
"80887a104ef050b442514ff8292132f050bfda9b640a840c3258f01893e75f42",
"cbfb1b0ad1df2f84e6ddfa190362225f9306eb62a9f5541cc5deb5da781fa213",
"b01734822f1598f9edceacfe3d828203c629313c7ea0f51111f6b10474e070f9",
"a12cab7ec7e781e90a49f837e6efab253d896dab615aba3f6327b264df5b91be",
"ff54a2a3cae5ac505347c5577e010f713411b5401bff7491cebc18b34592683c",
"99529fea4b50b9b8bd91aee8f8a25cf88dd3612ede12610acb24e73a1fda35ae",
"679c55a753495d26c5ff8ee7e9dd2f6329fe76bc3bba1324f27ff5f3ecb7f8c5",
"c805e4ae5d2358af561cce2ab0ae13a83b68a80886fd11ce5e8200b0194a0085",
"5fbec47c66e62ecc3c483c440f0e39711f414dcc8c0ad72b17325bedb8bce577",
"c8e43b97b4aae188ac288e16f856f16e839e67ee149d8bc8f8bb6aa05a186704",
"ff4748fce9a654b3876905aef033f19030938880da461ae9e05bfe84698658ff",
"c6e39da9593ab92827ce0e81d29fd85003d110bb2e85d530769eaeb0b3fcb122",
"0a1cd405a53aeeb8c03e69eda64aca2dc6df3d599c41551e0e71067c2c3299d2",
"41a3b0883541b8e28e321b9cf326c99f07fe0bf8354e080539511dc27d382728",
"47f3ee76ee3a53b8b6c84de48dbfe40d4487c0f1e024be7ad735b4cb01b240e3",
"4605541e0a8b64ebfb694d092456455e366312df0fdb6edb975d5df6738d5f64",
"f140f701e73403c39925a8ec3bf6fc033df1de9c5d013a0b866b71808f77c3b2",
"0a9f71c5ea3656600032d72147b1fb795f1ec515eb0c0e9b142a51b63ccdd236",
"773a797fa4bb49ec882c2c972b71e509bcc094b89083340df1ebdd64a68f6045",
"bd004ac4dc73dd5304e33abe88de5b3889f233d1b27327b14814f2941f47131e",
"5c2b636057904e70179efc5366acf56b238780b1bd50d5733f3cfd06e4a894f8",
"30cd462a2b16211e365728808b2dea5591fdae5f8e7f816300440e255839d9aa",
"388cd1a37c37a2e7fc75da6363e894618c7e011f6db275cf64011312f3d377ed",
"f88beb132412107250f73babe32b820fe6b277b2cf21035bb4c36e7b60a9585a",
"c38eb4323358d7ae5f9aa8d459dee525427a9a490650246a2e8104d1346599dd",
"212947c08a738977407b769756f1f4d192eca956b07413bb3f702402aeff1307",
"c6bb090f1ea6e4350d6e71cba3c096adca356ce16d997f48dd081eaeeac50267",
"2da0a61f2510fe2fbafb40b27ba5aa8d0fac8254d7d69e475fdff6f3777b4d6a",
"785fc19dee1f3e84307dc836550f5ace30b672460267751e6fcd5e33ac46c296",
"370020c80d7e1f3f53566b5f51931a1297fa1a4efdc81ccf7c5ab72e2577ae40",
"259bc6129f4c136073173a83e0d5d5954203beb997ce140d8f69d7b950e0187c",
"11cb148948a9c92a2c962f6f2da0bc9a024ce63c12e62aab3f0693847c23ad0e",
"a09df031dc5d362e71b730b91a0e84677353406309aa06fce96f83eb77671b4c",
"046bd72f9bedc26c0ffa2bb7bb9679b7b1afc7c9cc72a0de2da2fd9e9f08837e",
"9ee8b7df8898711a797fd8816a32c181e641ae77f9d04f69fbccdcf5916cb668",
"98813c8870bd227cb607e97a296195e673829e66f6c18434e852f36719fe823e",
"5ff5c13d156c6c20c0018848eb761cc24a1739b1a2964e279e1841d587ce3441",
"11caa777f57c824055e6cfec2281deeccea4cc6a9a0cd971ec1b9ea7de49cbca",
"3a8e126522f84bb01239c8d1c51bada77fb0e3e76d51ca82245cbed04dcb7739",
"860a27fef1b6b537a6be688753599f84f29a2600f462bddb5180f0575cf10bf7",
"0bfb8295a95da4b08f084135ce5b221f4e5ea4cb7e63d96410e1b0161f0eb5ec",
"684b917015396fe12a0b84845c805f3e07534070e1a0410bd6319f40704fe392",
"5809b9f126cc43329050dec45c6ec7215c588ae85a0647a23816a73e2eee7e8b",
"21ce0014bae97d4599230abcf322b031d49fee0f48e578f173b317478f0098a2",
"79192c7dec85ace4a9cbb6daa82e76105d10e988ffabf1050a0b27e1eddc706b",
"9a4545f77055b0320345d7f147adae0552191e0b77ba53fcd82749b5ef45e334",
"e154afdc575fcfec7acc74e634eb767a87354b7e4c9277d6218174919f21fd7e",
"12c94ad4e5fccd6a8a24229298b1aee2efa0f231fb209aaa4581a5ae970e4636",
"cd089347c67b34ab0d80db569233b6f42792d9fbb08eddb769c5d2c06c03b78f",
"c95de3ac861cb2435096b17b6a6e96880331ccfe730b15fb14771ce6414fbf36",
"b355cc801fd8712315d0247517eb2ff1ffcf90ce66e786f66c0b70b05c3aac13",
"ead6b1e3c8ce5380567394714a8d3e71b739a128872a4310fd52ccc0cd015bca",
"b2aa10099a3d806f3b5fefc4cf5aade2c91e518a93a03eff4b4bfed37aa98bc1",
"ba727d2be80bdb3b47b860b7588a46ac93984db5de47ee999ad946aedc411a3b",
"5de5016468e7f8b981bd5f1b04b270eb7c5ba3665481b9f2215607137c5d6ecb",
"44a38331d4f01c48fd89cb306be7d40910f61e85c01efa64be56007e168eb704",
"876407f1f2289e2212c3f09fbdddd40e4d99331e618fe1fe76e54c0007146cca",
"3c12bc0d8d061735b0b03371c4869f9ebb423eb84ba6a80bdddf863601287190",
"35426258f74c650aac3cacfe5294871a989306eec1f93c85f34648d3e1e64b57",
"24b0f6118578f557278af2deaea6bcff73b7c1fc2c034f0529b804b5a3667f7c",
"a853095e6abb3da36dab40eba98107044c9bd706a59569c27df4956af6a2867a",
"7bc75c278a522c3f2fe32b83c4e5ac1f002b970424ea9534ecb70519e2ffe1f5",
"968a9fabed55c4ffe4df25e7aa61da56e67bb39f407d6c138d8949f0ebd2d654",
"c01b876bfce242254ed98ebe8999d5bce9d6aa8a0afcd643f192c9c58ba05697",
"0f25ddf33af868397a40586b9b29c759b5f48c5d5ecffd65c8025eae40cd455c",
"9b2aa176b8978b1a6ed7c1a7ea238fa59414085797fcc91a2f0bcd4ba2a56b17",
"454807437182e5bd112654fa4dd079fa0ec3d701f61075d1671c6300e77cc3a2",
"dfb43a5c2c31241a80a316403612fc16007a8bb04652eb3316bbcf1a0f8783ef",
"f0c2b72b9e3f3e0dda04e2c94ad826890cb8fa891b519b63a1646fb00690772b",
"8fc8c2fb737c13eee55751ce1dc798fa291d428858e1cd862eabd89507dd0f65",
"a84481a8966b29dcade6a3e58692ad8868a0b729eeeffa1e25cfc95f7b3912db",
"91c8e0ebbee601828719aa29d7664b5d94e3501f3778999c60a975ea74bb00f8",
"86862070933c5b4cbe7d1b29e15c728766079109dada7f51ab02b03796ffea61",
"2aca32ca5da86a14878e221dd132cf11e9f858a1694eb66c29cd245ed49a81c4",
"621a41b83f8e9299fa89f2f5245ccbe34ddf352e1270c6ef094161708f86edcf",
"23984583b0ab9321f11a5c054ca891c1b5940ca0ee0174a701ed91d8f7c52d33",
"69dc06a85efe0e51884bb0e8215d50ea2d2cd59ff9708079e90434bb2412b217",
"96bd0d2f1ff8360f4846e79d20a31b6eab3705f52fd737741bda0568e629acd0",
"7df4dd373b3fac18a0ec775c111b47f96484f3270a6d5d9b1455d4337c031b62",
"65b585500d0e4f021bf4f625c7f48bfb02d32e9e532ec9cbc0c264247f9c9446",
"28e2b11230c728131c2312f86434b934b1e34e985c1601fa17740b7820775fc1",
"f1eec6722e3a8a3626a3b9cb45ce9c80fd08bb7e71c38d7b637aa986c6206273",
"cd5c00f5aa138760efd51fabfba83c0964c47eaa2e54f95b952b437ed66a5a80",
"16557e57e3b29f120e52c5d9c08f07f93340bc79910a29953df8a4fcda6b745e",
"683fca73c707ae662b516a2c0e2793e6a764b990af2f2ce8c3151ea75e9379af",
"b77d4a94dbc5ce109210288aa0cd3edc83f671ae9a9172495e705ea902ba90e7",
"5506fe1e6126cabdbfdeb4cb59bf30bf21edc868046b263d692345649b3fd6c2",
"e94b83fb44f81d60f82a9844edb2559563ffc876bc584f4fc4e11049237ac60e",
"395cc58f6dc01018cd334bf6ac29b8f5ec3385ec325470b408bc2e8d9af11755",
"3463442e45c1c1df952e9760f91b99ea8a0fb604b203c27f03a955fea0381ceb",
"41f4c041586f3e7468fa44de1ea745e3d41b9942dc19cf35b5565978449a78dd",
"31b31a285469f516015a5045dd8434642b2f55f19373b9e0d5530e843deeccf7",
"943b282f0be57bc8c9b5ad4f47aadfc0a439af58522a4495b7cb36e0ad43a6ca",
"f1d7d6d9dc97dd43e3b76bc13c6973e31572fa1792335ce0387ca171236838b5",
"01cc0fadd0cbb9e8aaa0dd49291e39f3f325030943c8041178738bfb662a716a",
"d96ec821e29cbeeb8b9f25f7123c8d5d708159daf8acd12e7a800c72521a4efa",
"b5395de909f1cade846176880210f4a560ccd3180f8b70d2d4bf15325f196ddb",
"e447d8ecd54443d4674c84cc84763a18b9161c76399eadaa82dd74cf31535064",
"8f47c23e998213388a6abc7d3b5754336bd0eacf4eb545b0825abade1ae48feb",
"b2b553a0af737c3912207071469517222d3d3704c7c45bed01f3cae1b50c54d4",
"ebd2711b2330377b5d7fd2f39a720b896a7eef7d7f0ac2a1d0739002a1511a00",
"d62a3142e4c4a2c87e8014012b804805dfa6f7d5da1a270f7c3401479a3b2f51",
"0142c36fee839b588918bdadaf8c737f91d61b920dfc581e05335f6f2cbc3310",
"e729c42028460ee33d01a15c2e369048bb79f8ddfd70a22dccd43b1c58d41933",
"6fd227ca8a63cd5aae1cb590c6d3baccc3518306e22db68095de25f0ccb4b49f",
"80ece14b164adb418170ba9feaa4d352cfc6cb1e31e47b3239163d2cdb54eaf8",
"04205ac29beea2aad32008fe47c9acc02e3ebc9f66c16db685c8f0976f3562aa",
"071d3e6a4659c37fec52601fe99ccb4d2a2480f3a4a7bcd16f12ff21fe84a666",
"57f2fce9dc52bccdec3de4763a02e3700d13953003190d560a8ab306b81c1221",
"076c6ea3b84d7f2535d034e5371378e9345dee62947ffe4de3185d02a2152340",
"0e386ca6f2161a1c64a4072ce7a507e1131edbd90446723d84a41dcddaed4324",
"48042f945a825bc8cea4e8fef1da5c85b252054137adb5e123dbefbcc189db93",
"410d27dddbea610ff9c4e6354b187fe8a2f7c5b19c5563e2a1bca1a4b4b8c6f1",
"453ce5c10b3de7a4fd1b0bd5f96512d05fba41117299d588a4740585fc295590",
"677e34874e3dde27ba4a987778de7b1a64b6c63051f3cfc774ebd4c3fc605b7a",
"c9bfc40e1be4befc1b44e38b471167667f6b12457d5c82662ef3a0a0e9f66e2e",
"4cd169e13f4aca41b158924d9f1b972aa4d167d6d9c116e7094a7a06d96e6387",
"aad5a84ac08dcbcd06b4fd5a0c5d2c1af8eb0d6568f17b3d8cc47d064b72a3de",
"4d495f70907d93c7c1142990927f1a3d59e3218a34db881714250ea6e9aea84b",
"8c43d66f0d23b88c17d19aa01c64ab1d2af7c43704952326129b0dab4453cfcc",
"c12581dc707a3a6da47886aca1c2aabb5babcc0e0fb21808c27c6d5a939841db",
"2c63aef84a0c812b53e37656cc6d5e8f64f8e4f8552e4e502dbb1aa0319e13c1",
"86886a41f2639a791085b6a2be4f2ac4f76d951880eff5cafc722785ab4d64f7",
"73bb646c6363f96e1ecc19f5ddf7df417327b9089c1b70a867f799af03cb3d66",
"ebe518fccbdf53bfed56fd1f8f3b114b5849a8fb6e14ad7bf3f2a2baf29775c2",
"db82684a4b314c554fa6139c4c7ede0245f68b32a885c819efee12ab0c027414",
"5a985ff0be58aa5a46a0f4122cb70c7ebb937f7802a33a32d8262e63b3771796",
"938ffa6e22fccdc71d6ca1544cece54518b9fb75cac5736a0468420cb9f504b3",
"4726ef072888e9d5ad65342790b285c7ff024d60b084c32377eae6faf67db536",
"57292f406904048855148e3dc04cdb08ce05a58f174867de688b252e448096f0",
"ef8e25e005dda6d6cac7947006e1f688c743efacb7633c34ebbed7f87707a3d7",
"b90e5ada245515dc90c2fec028ce8359708a610927c3f9cb92bd93eff2fb59de",
"32ded7b174c9528307b8042692bd00480d31db9683c9476a4f50085aa6810893",
"532a40b49048d2695ab6ce15572377ea0befb57bf6311e5bc89a3b579561837f",
"587782fd3913fdd01f9f475f25e0704ab834d89fac46a0be1d88e54de6b50701",
"b91389a5cf8a1c10e890ee4c740fe9994d48e999b59a2c6320397a389ec7a316",
"6e737036b6c0c9d72a72c8545cc835d4cf7da70c5ea33f6c6003fb844565354f",
"2f239f75caba3909f2b6f059a782c2624a71b591a7e132ef72b4add3c9c2d738",
"95d4dd64bcc89d80efe84c9fb5d4a17ac7115d1b38a0ac0262e7687905eb1c4f",
"4487d612260e1a6c676d2967cedd84cc5adee2ac845ab2900aa193a1b86fade2",
"97edff35d1872b6a95f43606f084de35aef0292cd411541243bf7336a905a938",
"9001c5d627af968d68f12200662585921aab14619935c8be4775c457e2a40867",
"ba959223c1636c7b0d10b43b78c1821e7af6f6aee1f80337c555a470867c5ad8",
"9f8b4937db8172a5e01b31310cb3b74824910f9c52c356c17035d70173794089",
"1750c07b09dfc52f0cb0f09f4560095db135127cab4c511c525f560c42025abd",
"a51ee98093bf11eb0455cf106b3a4e027135e870e3e5fb212c42d62e190f153f",
"35501a82a47804cf7718d6bd2e4bb6fd67d7639984eade0c1232bc2c74588343",
"9c3192c2435a9cf815b717ecbc6c539cac03c7f582dbda889b39485895f3e174",
"ddf04cdfd5366d08b5886ef736dbf547a403f583cdd7c089f9f3c4239e554210",
"2675b30bcda3da6a2cb6837e614ada858c1bddbd42e6c3963eb220c290fbf967",
"dbd9134ad3f09406a76eba91323ab3ad2a4fc0bff4975b2cc480bd4403ac7560",
"2929520c43b14ce24a94bf56870520ddfe4d29bbcba0d0e1c4624292d8719832",
"f71513cd36ec057435881587013b2fea181cb57df1cd9798e9b4bc2b0457e778",
"b83971a9cbba7903239a1d2a5907351c61028b952d4dd207dd49f6fcc9abc13c",
"c3b7e679bd4d0dab1a2e7938b0d5cd8c28200c5da9534bda97ea0f1ea81c4aaf",
"77ccaeb09a35c5a1df5bece681062f6ce9fea08bbc2c2075ae235946e8e1d9d4",
"51001f07d1462cd9312b077be915dfd5225b85c3ba760e2a414275aba5fee655",
"ab0f6f8f5e58803093fff168c38de2710c2aff8b47661eaa3ae2a337c0e71ecf",
"96e9ce518bea74432b7aa4c857b2e2423a4b3f48275fc4b48f87caec87800b87",
"60c0b7a0ccbe7792b9332ad6072636d9790ff736e2d83a12f50e7dfec65a2680",
"38175abae6191a78d957e3c63121036688cb6b8c46d42d026551ad37a6aeccb1",
"48d82a8ce43a65f567584bfe7fb28cf8c84bc725c73413b8768d2e6688ae77f9",
"18621d94f2733bf9289e0353f066c53d95ef8dde449b2e160e28232caf17df74",
"e86c65449e6b871ac6886526107b8d7bfaca468ef270172576bd9f39fd208aad",
"c32bde208f9087259fab6b053db25b1b136b38276942e2420482855a5d7ad17a",
"dfb55a5293f934d40ff7c0a6749aad57806e571df185f592044e69e680e995a2",
"8c2a1c5eea4c8dad313bbc6beae0c4d94828fcb2a4877b19761e75c74fc10164",
"eed8a70bc0d94fdd32629373b50eb9ef830282b42dcb1d8b96fdb9b8a1797df9",
"2c4735a60cfae0273c4f309be579a51c6ebbed0200715a826048b1ee568d4934",
"f7e56418539529401d0780879ad1266aee0f0354da07486ceab82011a069deef",
"aca86fb3d7d9fb64e920ee5ddccfa78227a0a3a3e40bb3b275f114186e488c78",
"bd4b2c02f07305164010353383415b08f570fbf3fb297df74a38d6f6e3ae99ab",
"589908e264b0c91b1358f1a51f020daf473b7e4d5faf493b3625782866b476ff",
"70360b520b95938174c5b0c2400da3b047743e60d837bf567767732d748e991a",
"a54ed87456ed361b714da5c56fae7c4cfd92f8ac4a6e8e901a565241a39569dc",
"9df7afdf237605066f98cf95611f49f5c5f383a080c86dc3753390c5627efca1",
"6281424793e144590ddb68a85972c45272a5ca39227f9d24d0bfe78e2bb82580",
"13657e27b82c768942fab407deeb645ecfd958f506a6e02c95d119620cac86ec",
"cc67906e35cda000740c83f50b24b92bd04c58f2a0c45580e9a134c284580804",
"44e92cefa2c869560d185d18baafa780bf16f148d1a7ea186f05597b18783606",
"8ae261dd18679d8e203e7b4c8dd241a51634a84f83855b559f7ba55728d9c9de",
"0269bb4c3079709fb80f3aa451a895b639e3b7db83360a14f078f26816979dae",
"2faf079e75b3e9e0298fb15ef8c6d53715cba427c8c551e98d44a3c46a67414e",
"745a15e40bf06483cf58188b9c7df99e796754dc4bf3eb0547b11fd8016c5c66",
"70dbd06038f269ead55d560b7f960d24c7cb3a9c8864fe68c0daebf315cfcc9e",
"1dda0994af0142dc5f71646735ed3bbdb4f6eb40955836db16fc7524eff22ed7",
"492af127ff75fa55f94ed919386917778ed9c51e4cd193b75d82524c186a1b5d",
"5031aec77ba13f73b21e5cf92708f44c0edfd1081c89b4630a0ee3a50b91794b",
"859b7197bd1a5d6b8dbca9d6c96321e706708cba23866d44bf3f014deba6a4bf",
"3108f998d14696b3e945569ca9b47346b26f8a3700cdd444f545fd0a03968891",
"b7cde7af47f0df23419ccba57da19a5ff7645fa160e136d43c827f41b460decc",
"18cb7236904f9784d611eb67b53daa31efac1a8a9a7d2ff47dc34255ba276a57",
"1670703aaef6d8c722bdacacc31a80dcbac0326dcee64becba1339bcf630e330",
"6ae67bdc91167c7efd005be6881b58d24abde9f8c3a71e6aecdb8e6738f3d169",
"3efdadf9ad79dd00eeee1d80e40a8297254f249a9dde4b4d94b656d58338fc5f",
"d14ad9887a66067658afeb25a64866bf90debccb49cb8213184b807e9f1284aa",
"7f2bb055f5dd834bedc5ba9d63b3c83322e4325de7866b2af7ff8692bb2b52ec",
"729e0ab27d04bf1c14dc28c42ea56cd7fc1a8207ef207ac34e676577fc32006e",
"3aea585e172df036a10a0a3c26ebf4705972eb3efb5b61602231b8a2b2942b19",
"a3b01753e934a16eea44aed4a756b7582aa1b469ac462ccfe4c92268705591b4",
"d5af668caeda6f6af27a778359ce9196ba091cc04d9f9b3928f8f5203fc3fc88",
"a6319eb545257cd4c849e2cca4c6faabea9490eafa3723434800331f222b86fb",
"a4f001d05640267e07caac4cad7122771451f3f997caee435965cbd19e64a621",
"f852577eacf926a5db6921da93b4a78f00f57e06fc064ac02633976e35d9e00a",
"c48da9db46193fcda552476b8c08fe35a73ff1bc1950a41f3b1ec098d2f75a47",
"7b26f8d832edc5d6c025be9189216766b58ab27f59e7b253d0ece4d28f51e2d8",
"cc5b9121f74988f1bafbe4ebdb7296d2255a4af6f01f6967c7391568c32377ce",
"29fe88933391cedc886475d8aa7b68415a7f3e80e153d8837cacbaec3f47d8c1",
"392cf2ab942625fad754d738f33732d3172f4213a8606368330f72373ec99c64",
"b9ca5c8d1d64334e586ba1f0303d3fe802a03eca9c2aa12d2f57e79836d0b64a",
"c47d0f78a14f36ea4a9d1fdca74596a88f93dd9a0e746d97c91a79762420390e",
"74a1f274dda992663e03a2a10f29c84d41e2e202bf56e658c1a42ebed46db202",
"dfa9dcc132701d8b1f4332e2a6bc7faae3c7cf11ac0909a83c4c7e30fcbe7dcb",
"35d4395190d570f8288d255533eca2fd7bb13e720d6e8f5a7113094f97538c5f",
"70a16244e7480d092b617242786deee67056d07cb15365fe51d0e8ab1e8932a1",
"a26843f48f4f2a218b8f5b219147641ca236a1abd96905d8534350e570b164e2",
"5d9eed350175b4d1217b25e671c2f3c9868c8732b6dfa80e62e4a9bc7010dcf6",
"72db3913aa066e04662cc170f3363578fa47799b64561d3b9e84598b43ee8c26",
"e406db4deb9cc79c8eb7d658c382c2291668d7917d73c652c415f37a3f713b0f",
"a0faece933213756d22239d1a066c1730fe58b3e815df52c2de1fca102b03caf",
"9d6bc10478d9345260c53c40de93ccd7b1f344dc25e6e4cc8199e1ed9c6dc824",
"ff1a79b9d954943147a0b29d67ce6fcae1f9f8d5476c2b8eaf78ac575f95247c",
"ba31c30e4a28d5ad22a364042b7155e5f4ee008929f22eceb3fb7371d0c1c2a0",
"797bb553ef79e09eb1aa5400a889bcaa513583662c3708614e29b202cfc3b80d",
"3df07ae6890b2c332556c247ee91abf341c5dce226e38df09f7010b1c21615f6",
"30de2051725d9f0fc371cfa55aaded73b12e0668b1624775b657ae0f41ed8daf",
"035e448afdafd5069a783abcd6e268a82f43a52d9ea805c1141d329557d2029f",
"1cd59a8ac8c61f8f97cfcd1e43d633f41f0b3b3782e3deb3d0a9d80942b52077",
"b1bd938d8288167f4a985abf342f977cfd1c2f1da70c6037c9bdc4295a705726",
"418297a2f0c0e5c3d6b2c4d80824e1a909a61fce6c18bc937720eecb1ce3682f",
"06031df90b06aa84d58da9de78808f7b2cd7d563f41dbed683e74bcd7884720d",
"28961517d508b8e963f98272dcbe636af5f99e6fbf436d14b9b64273b17857a0",
"bac113e3e3572e90dad38b0c2b32deb78f9027e59b75db03d0fb86c49c2d6d9d",
"26a5e2f817b0596d95c8a82cbbfeec6971da2247ce1cfa52bc5098ebdfd3c084",
"ba7bae49a577e15e14568cec5f779c4700c8ecbd21bc8cfbd3aa56eb0948dd27",
"90bdd504836627c40d4c14d54da1b3dc5cf5b6b1cacfe2e220d1aa44850f6fba",
"02f1553ab9b4f4486fbee6f5735ffe0d9b305feae9a120df2ea311fde4cc6076",
"2a9ec46cca5184106d4df225de39422136c6cc995fb9d124bdd640ea45667a13",
"28a25bb686696fcfcdeed1a996ff4f8956dd4c41587d599eb78a83ab6b1358c8",
"422bb78c5107f8f0a5e1a253347a72894704cc4d8d1f60a49a49f8c5dbaaf298",
"74f3c43fcc95c26354129e18241a1e747c78975c4bfbb0b90a2b67c117dd85b5",
"8c0f5a2aeb81ef4e5805c1070bfb8667ae185b59705c3cab2aac50363327daed",
"87deb9c6b62b237a5f83b7333776baeebb4eaf804ef78b9ca2c62ab92388a697",
"42897cf080c2e405a77fd501360a7a86d0a1cb7d573f5fb07e094bb13a942f03",
"0d3b80df67851ee640b906d761fd95ad7e47d0186cdcddc59a10a22e011816ed",
"dd222577e63a176e688a09834ba7dfbc7d25af9cecda7b130e48a25fec558e2c",
"f6f7bd7315404bee4a9611e69fe5d3387de5e4577ac28267d04d69946f42f18c",
"03cce690c88d34689a3fa66b6f8c9da75747ed568e63fb20715def88e7228b38",
"d9a4eced4646f53c7840f817b4296b5bf16e7b3d5e906953b6302d7b8a848dd9",
"319741447aa9b6c819cab13368125a52f3c35d264249d5b4068d2f379010f4d6",
"0a0f3eab30a538a23ac52e4f251d383d418bccc96d5975446e093cb424e8c247",
"550942f02799dc998561d8695fdafc4554c5a89f12333403cfd7c4c9cb15bbec",
"1b0d7536d6774149b4ed8db577268f176e4c1f76e88c9f956d51577d7349cfa6",
"5d27bef5a988fb678c4e178b4b1063c4151c5d3780c1dff1ec2ca898f8f8cb5a",
"6bb4b71ce2a72c465e83586c39a2c1d2f77a47ecfca14b45af365a4ec29448ca",
"938e0c409a837260a9fc27ad5878f3b8936ca0e6219ecd3f9bd4bef6c402acd2",
"d8aea1404c3d5fca7289e2512982bda873437b43e7b8b2a912f383340f821c8f",
"1f4cd386950035ca3cec81cba5d6a506620863056da90c7dc9a5afe47d0d9dd1",
"dac066c881d458341c7db30fde7d9197e498ee577bb4f0e0e48fb859f3790143",
"09381cdc27896ab6c73c341673a61927099eaf2d300d3e00ea37ea6cecb262b8",
"65f65598a48e7b2e38efa51d454ef1f26be016c6a70181e26bf35921998671ea",
"98d991cab4e708f9281d1f56b1a507026a114ab0733ec2dd572bbeaa22fa4887",
"1c2a4e2bf0dc9a09e511baff42c297b321cb8da45c18ec50e4c39ca2465d7cd5",
"327c7a6d05d522536e61aa1fbe8fa19f781f915e20a66a647ea90abed8879fb4",
"cb46cc08d32b5bc7ae9480f30884c7670b8e8694d66d5438e5f8fe81785dcd1c",
"537fa4c41690903a48b7a632249144f154c5dc4686f51868df0159a0350a4ea5",
"75a5e4322582d7e240de8e8b0ab9ad73b7e283428537338b41b35107dd63ea2c",
"1f87054001c06863b66f55b3a897ac0d76f361908900b30e1d8ffa46742bfd16",
"22197f4735d51aa39ef48c88c4d60818245fca73b98df8b9669dc434c6ac8796",
"a2e14dc37362b89a5b85c57b3b48169adb2e6dd5360b8030de7a0e028a6db3b2",
"676f7706eb7a57397f6c9f69de04cb037d3a1045281b8ad8390244b9afc7a2d1",
"8defc187fb1f0d7bfea657619f9a020f303f0cede255b473d18817b500b94b75",
"be1166434669922a764541789705f9d86af0587241cf3da9e33a7983d048177b",
"c5adb9840c2cba41c6e49f9e97c3b78d8d0a1c4af88929e89af205f75f61cebe",
"a83b4a5b3282ab0a2dfa4b1620dd0e3ecefd89cd43fcee45a1a6e4760453e9a8",
"ae2117b3fadabe7e3d94153da7e68c6d7b371efc20373aa8e1d9326ed9a3b369",
"a0b5970a81570a1b2b4d058b32ba5f207273765be398986490ed5e9109d07863",
"9ea221fe02ecd3c974957ec24796afb677672fd1ca770a13ec9c3a94135ef06c",
"a8316aa74116d533973b74f528dac5bc257a3e9cfdeae39db7d8d32f38085f4e",
"efc5250bdfe42346a1d032ef4c7189cfeaf303af28a12b3be074daeea810b171",
"9aa7194fdc5f39e9ea59a13d04158913df4c87ed385b32a37f216c17abfc69c1",
"a17f4cce7a3aa86d9bd5d51f3c38f235fcc4b086a746030af939997d05e54fe5",
"98b049494b468b0c6cdb3cf382283110668d919005678e4e8a5550a892ce133b",
"1ff264905c3f040c3fcaa107b7df3c38ec0dc7d59ddf9ff8780d6aff0381da57",
"ef6077b9e143f01f8b500e2eb6b6ff02043ec00befeb78ee44db5f00d037bbf9",
"ca1af382997fd751c70fa1fea1cdee6ee1d2a22246463ed7867d56e57619aaa5",
"be8045324dcbd46d31a1b24be314d5f0ed7bd1d1ca67bf71ba5cc43043d5c9e3",
"70455e4b87d4b01585564a77a6a414a53338c05a984de6dcd14d7126306e22af",
"5bb2bfe0be18cf76e3f70ab3c6ef2816dd988074d43389a3c4479703d1a61041",
"3c95b917d6409a12360186d7c8839b33d6fb9a7f66f2e0e3a887601927d14043",
"0259cb83d1129316ee620361341d083c43690ae542e5fec01f887acaf2fb04b9",
"9aa9b67c720b3b2fe3eff8732fdc359ab15ed4fe1092e289fc27b7e55a9c5b50",
"1151155d7be1017544c0c2b7432ea1f67cf3191baee64771e9364f3bd1da3708",
"9c45b3560ce8419825ae84affed5223683fcccfd6e35247d1c03f4b988e8f48d",
"a3242aa0a01b82c6d5faf748c22a616b950ecd30ef0f72685aa5860f9320761c",
"0f07485d78018a506a69021080b41861f801ddad09666090e53fff3bff0cfa92",
"e819c861150099438a5ef2613bbc8e4c854cb8410521e9699fe90500a9127443",
"4e78cd42978462aaedb993b6a49a5ba1315519db360522a26add6a17c8adac8e",
"b21ef6dd5976ca60b6e335e78e479a655409da184e68c10e0b4010ff9d208c64",
"e8bd4c3f3e0a8345ae5b2b5748060b15ef0c7529fc3eff080bec1a9a77584592",
"3c8d2c54c7d5d826498d730a289d36f903720b7e2ce1f699ccfa152999b5a0fe",
"fb6e025eec367e2bf4b44af67ea674d767b77397d0568528e7fe3aa7574ae730",
"9236e92010421a2c1674eb0a8044ac2b215b605c0b94b903f3a2872d0fabd344",
"9ea25f2f9472292aba590e298fc5ff15c4cb22608b2f0f2ce1bf26e148920007",
"d4d18a3b2db8540a7bf72e0cb14b176919f995e70f0df607489d5adeedb0a932",
"e6f6e272b36731484782bcd4844087cf45678a05d8b84819f9d41f5376f0f8ca",
"5088a2b878336dd33c3a7c55c09aa70bfb1d34815f031d4b3e92402c7633b400",
"3d12743c540c798ec2587301a3fb2b4f0f6e1278e4bb15280c247272ffed0651",
"52c17f712792472ca80df50f7b9f96f51a6eb155c872ba9ef460aa6d4e10fe39",
"b97f17e90b9fc70044f8789379639e52f97707eac2863a35e9a19376555f52dc",
"19701f39368b26bd3c71a2f0630b5e89586f7249431843eb6c890045f7789280",
"49ea123cea990f6fb2029e8cbc9ff7ba7e049c32db1f6519306ab980d74d0d38",
"fd574068f0c0df88faf7b54341a310446c0ec94931bc459748e11c58435d6ea4",
"fdd6cc2c790b22471f03a32b906635b4028debfd691a0a57f847e15061a2904c",
"b7a173017905bf55dfe03c1640a4e808dd6a1d6bdaeb27722a7c839766b8465e",
"74b799aae53dafe2131b183068d8cf5fa8f2a3006c9bb9944aa493c7491b94cc",
"cef9c06a87ada326bb03e6a301f53fe5fe6d68df015b4d72f1965581545c7fd8",
"db390feffd9cdd7f8a34acafa77d80889a820c9275095e84b439ff5f05781ceb",
"57e17c1b71a226c7bf02687565e92689e5c966f5c864e64d9a621bb6757f4f2f",
"b8c8dc2624b8aa73874647bb89be2765fda8223fa7055796a59c7f4d1918e8ff",
"08a2553e3004a255c9a4135930bd9f8724423747135c0dfe45747285549e4ea2",
"4d4966d172bd8c367d828eb8a14f853999df1394fda96fdcdf5e41d70725ba21",
"23888052d915017c4b47b5307d25158fd13daa02bef1d4a2c11bfef79a851470",
"52a97f2b532139784f4a6a6250b2e61a3989a2c94534c2434041aefa13af2871",
"73c82b469fce6ce8b6b2828441bd31b66784b0994e57b82d331be9e03cdccca8",
"cdbb2bec43b864ec0d7caf5def1222c3cbe20c79d97c7642350dab42b5d1af3e",
"e047c075c048467400806f61489cc503dfcdffc73d4b9b6bfa470427f95127f2",
"82de0f386c63555542e8a34ece6dd42f2a4671d437e00aca7da175e7d18bbc85",
"fee469874ca3fb72f0871a24f410284c04311446f4c5f04480d7b3ceb4e78efa",
"830d8aa08ae29fa0941efc576cb59975d035139cc27213d0a04a0153e45207d4",
"f444da313f6e7bd9e27396f9a95129c83977e1462f86e7a9b5addb1a7ff30580",
"fa601478a412743bdf29bcf44ecd5fdedc09792c8e469a7399bc17c64e134585",
"cec5ef97aa6a39f3c146c5e3f955bc9028798591d4e38094f38f70e981566d58",
"6bbf46cb35bc96854a8fae0e20935f2ed32ab5a940e7891fa7f268d28ce5d549",
"955d9741503c2e5244f513e2c2430bf814201a2d7dc74e2e5c9c9aeed401ebc5",
"9f2e6590991e25b4fbcacbee5bf7381092cfcd7d4f3e258bf4b41b84102fc179",
"647c657c3c930537bc13047cf886869f5a0699fc52496ab30c997e5fea1b3dbd",
"9802afd3ddb4d5067fd0db7ead8c66ffb3ad1c29391ce56321c4b8f34174eeb5",
"60f782f178f30f3d9321017b2c6591f25a82f957ef1c704c6901fe2fc92ed76f",
"109992589b06b8eeba15fc2f6104140fec043b2031c8df3e9025fb094978ddaf",
"091adb2a123d0cbeae7dd399a39f4ca4a3b68086410e6c7aef0526bb2ad2fb82",
"64143c36d10d8d0659f9431dcf30cec804f4487452d5376639157354bb7ee637",
"9602ec038d85b2cc617dbdbbff0a3293ec62048f70b16a6b38702e26b99074a6",
"1c6b6508f0f0c772137ed1a53cb559fb1aa4b3690f6e1f6fd3ddbe5b74da7676",
"a4df5d4c393b255674bfd64aea4ae82da5175732d39591fa671a233004d2d0bf",
"928a67d956422b29189df8c6e88e345ed2cfc8ac941d06f15a7c24cf30bc5296",
"79abadbacc8e8bcf8930e8295dbf6626e3c2c71b8c4c6883318dd1c72e03ecba",
"ddfc0d445cc013734947279fdf7c6f0d474a622da65db4ab1c0c9cea7f60d0fd",
"61ce62f67c3526d4183f74ef0d457216c7ba9913c9a0243944c972cac6dbf42c",
"9cbe363f9bc69639efc73b9bc02264e29f7d0f8ea3b1f35ba16640a5767c5db2",
"d7a25bfdc1e8bfba013bbcdc8afe41d81511e15cece155e9be7bf1ce81af27c3",
"93f9632756d3b0d8bc72c4718dffaac5ef81630d6bd79364b7bbcc9ffbc302d5",
"2311829f9842404d9cc2243dd149bdb26d210031ea78dfb066e90381a392e641",
"cd08a8a153ded8be5d705390e3bf53cb56d7b8c20e0e08c39adb3689a68b9602",
"8d310a900176ade581ad42108605cc6bf867f21cc115e6abbf2a5e083c2bbae5",
"43c5cb40e94874eb80ec26b7df732cea255453f511992fd61ddbf4de739f3b35",
"a2a9abf1c835b824a9d311105a4c92b3d6ca8eb2761b45da7241f5879d05bcab",
"ec48aab645d64498938781156b6daffadc0ec9f3556b7e995c8dbd63299c3121",
"05f6c84dd8ff3468d8992d9dfcb4e31597f7a378828cc0108320c009ef16ceaf",
"d4d39f9d3724cad98bf1466577b79c4dcdca104ecb489e877fa8f44adb1b2ba2",
"b23a123b0bb6c11060658fd14786dd345ad2a2c699e4fdc7c8de79b1eba41fc1",
"f27d04707f4b1110ffd978f8610b2f094ac0f24c1dc819b59b70e1f64cd86a99",
"42895aa8dc4c0ca50b98c7157fbaafa53fc3d8a5221b660dc86837eed7e6d319",
"ea9f13a6e1cbe9c308bf85b50ddc729abe112c46d74b50ef53d0bd7ece84121d",
"e8d250858b5de70d138213342a6765948419b81b8e8ed65b3763b20ddf009fdf",
"827b1279e3ea50b1b7aeda4a7969cdf18bed45fa018e552190e8341d2b8be2a1",
"3584a32e4fa98cc72c35e0050fc00f46462b7286e9d6ad675c340a8d1e56fed2",
"196435304b5e92922c3453ad9f31a8d1b2821634ee6a29c07543b05eafd7b061",
"a86b7271d28b011a2749b302fcdbbf712f89d9f3efa24b9a169e97e67a57e594",
"d40ed1342bca6c536e736f1fa15aa5f5a01274b4208ac4690a4f8c293dd40b0c",
"513256a2ae5c50af825420724fadd88aa0a77d93f64e1425f768f33bc56bf862",
"83381a3fb9ec95f2fccc410ae48e0581ee4f492881cd0c20c90cf19823ffca7e",
"0d51b0210f527afde630887455f5d231425f8a8aab5d8567e5ccd49441f5effb",
"c584a68f8f6a5d8841d9b51fa9cff1a3aee73b1b4f8c8f378843c79ba5ce5902",
"b5396ef2974c2a1040b8e8ff023a82ed4ddbff2b69e5569249d139ec01dafaef",
"e52c0b2f5da5c4c5f68f4c1b7e3dc81e9572bcb6299d3386d54bf881c43dcec4",
"ba60878ab1ffd5e5b85d843ba049d669ec4d0094330147c3942a62f0394c32e5",
"e412b797b242a5619823b6b33008f45bb0b11bac0ff365b4f8c73c9f3fe6e590",
"50933f5388c97812aff9aa52db014d71556383c63c6b1b7ce294195c8efcb540",
"643ee4638b7d9c626522f9178bce2a53a875453252c46ee3ed4d524ad2710a4e",
"e72b8739dbff60185cfe3da8783fd9af56b7da9974610428a11adaf5c433b2c7",
"48c3cb8b5c7a90728fbc104f8b191a98119f8a2777c00f8c1000244013745527",
"34845f23b0bcf4e5e7fac5f82c059cd08d9bd7cabb11edbd62fdf1b40df95758",
"33bcac68cb4ae201b3d3fd356c62feac888ea3f7e0f59ff0dfa2fef97f1eb558",
"778d833969b28ccda7711e0f6e37345fa598ac1a9fd1c6a497dcfbb0d2a9d590",
"5fca36d19c656d347e71c9ca43df0d701852d9811b758d63b3ae6522dd4c0b68",
"74f0e0b61425240202486eb26a74e53bdf8460203352f1c1adf698be9c01dda5",
"d2b4e304a065b74641f42966a43398a96e85c14cb209ff06d18e6fdd8a30e1bd",
"df6401c07b51c72f6ea2654aa3069fb6bf0d8a3adbf00d926d534400d88733b0",
"3850acc410d21b19110d9f229c63d67e36e2484915693f21569b627b0f3395bb",
"6143ef6a8f8edfb6b40ad2314c0f9595fbed1f55fac3b8abbacd72f691da7780",
"b14ae396d6da8ee43a3eaf5e9a06333ce6515cbf1819bb5283d73a68cd39d2c2",
"2ccb1721e1ed7add382cf8838f7cd82106232c7b0bb7fbbc5f36291936fc8f52",
"cbde7da6d0dbf518da6923c7d82749def1260eb6632f03a7e3eaa62cb3a4eecf",
"9a9df0550f1629c3cc3c539ec83ca7e815ab8c9319ceb91f42b6b9dfc3384ede",
"f48737960c6bfd1b4631cd39048b55cad33bd0fa925a8ae094456466e16b7791",
"2514869fcc6ff50736da7f509dcc55cfe8372f82beb46529d757c0ad98fca10e",
"b21124fa2ab9868f3e7375cebd5cf95a48d0d62ed6fb62ef0e0f08f7337bb212",
"84835fd51e9bd4624f4b6feaf2387bf3652f0b03efd56cde086079f86bcf9cc2",
"868492cf4941bc0fd0ca8c37a30008fabf58e56bb3b41f7bd91e09b43914618d",
"00a8ba1a607be27447cfd6f60447a22ff6e603e347eaad21604bf56cfd3b1434",
"e50a1c9ab7655b55cda75ff82bc1d28ea48cc7fd292e5f7c72e0f48acee712de",
"249df64d683697b530c6013692fba966655c6d4e38ba40fd05a282f60570ee67",
"1e66d4f9bf24724b6ebeeba7f2ccce22cc039cba53b7e7fa76723f1dbb934e34",
"db6767231847109ee8ae86b459f0303e08e2fcf5b4165faf7edc33c66909735a",
"406ee377180093d25cc204105aaa3030473ab112f209ae1dd608ebe115a3f95b",
"0763bf2c13cdd4525a95f123d5a42ddcc9b3aad27c90dfac1f19fe2cc643f636",
"3cb4c58f6597a2e937c8bcc870bbef98fe4a2ef16089c94a0afcd0ecbbca140b",
"1a448036689115f5ad50e0587d114cd77901f23a07070b4d18ae816256d8811e",
"4bc718cc25242feeced0c3f07c5459d30e5ecd91011237dd869a2b1d32c390b9",
"127d4282b45be11fe780f20db6c1737192912449c0ba6b44ac499d9fcf546a48",
"2882d864f8aadec1babadf7ea312ca3774fd0202a4702779415a7296501e5828",
"2c1a8fb6d739f4ebfd01044c2ca11b484de6933d33c6d120c5bf36475ab7b457",
"d4224f53e199e315ffba0bb317dcf7743d764642d93770e8f6eff12506df888a",
"b8d8b26045f477d58aa21e5bd835883ae1a7bf47e416032080750e80ea7b008a",
"fad3f5f3c9d29a2165efdd3e33f0aae9e58365b379f0ac61f41ff8912f7e9281",
"c05aa5280e7bb5dc66265a8862932aeb268162c25ac2be8fca44949f94ec1ee7",
"af2c85d7085cbd5ff2760f744d22e1e5be0bb8db8817deaa14c06ba9e4cdf516",
"00305a938c19feb580e7945aaf55f217d5089185176561c5896d3643551c1aa9",
"8ac01d950862d0598424e3488ede8e9a285dd068c1d401759ecfa3c97f9bdc85",
"33f3b9159541a44f2198e6e7bff59160bb52f81c35c9f80433992edb5ed0a340",
"31244c0e5b1f7c934f92aefaab2e06b0c2b88c98576777d3e5c514a6b8ba97ad",
"72ed3556b3a25c229bb436b6bf809173540368bcc434c74548373c043f4f8602",
"00947670a458adcae6c83f223cc0b2b05cc1debeed514ea4011044ce375c8eab",
"123376bfe0702b06b98915e38ad3c8d3d8d270f2c81db595922c298d980a7991",
"b9ea637bee6f3f3bee40fb76dd375b6419fcce5fbab8523785d04b1c4956570f",
"601b25e3e686fcc9c3470bdbf4fd2af9d008ea1858cef028180e3f62df0fca7b",
"6d5a1265a95ee04afd7df5c9aee4341f31de35b9e87f2fc9e02d2fd7e0d5fa2d",
"77bef4f6fde9b94b5397e63d1690c6bcd553ca53b58c2bfcdf92726590246317",
"27f110882479c6cf64c0bb38d121e389d5ff17db4b216597c75151b78b24b2be",
"3d1d9cc9b494b22ab1df806d7b1e9745d132dd6d72ba4726f55af9210f3df4b7",
"84d60c1d787bc5d15a952183acad447856c0501c2bd5809145f8d8582c97decf",
"b79fa13459e7f875488cf30ccd2f0431cbe8dffc671880c10cd72d7e2be7e8cd",
"061c36fb310210ab07b22f39178b7f451d5142a395ececa1ec783af9c52b730b",
"fa16976c19becae31248c8477ff0e746c4e28ddcea5ee36408c05be86a142471",
"82235891577986898debf0cc0bab31fa765e925d01a27c27ec694103320d82a3",
"39989431d3ac81a61b0311181d499018fb4cddfb74b1afe4a9260b5841135989",
"a846acdc0cf349a8d2b352d3dfa8784893f5038c05277d327341d3ef7de41bce",
"f3cd88ff101e9dcaa9e05998db425b590dc45dadfcd8b8a6bc0ac7e932372055",
"a159443648d0796956f92ec4efc5aa44af0cc2fb7ba97de7e6a8e0dd16638530",
"9e381ca3bd9488a656e965de17a44487f8c0da8896ebf9c0af4c0146ce034951",
"4cfafb85f2faa88a88034c4e04b7a37be20eff7e02d3e21bdb79d5aa7de833df",
"eeae101eeff05cb6a0dee3bd70b7999858b898b8c0cc7fa96a5e9235d1377381",
"786ad41ea86eda551d0bfd3e702622e118b21e619c604772befe546e55d4cedc",
"2c2f151ad2b9d7bb8f52dc4b060d194bcc63848754d0d2983def1eb992f194dc",
"530b5035473e95e2bf117e3ba2d88d6de1e648f8672baa0c9dcb83e80ef47580",
"b34801289f8a80277b7d5fdb602ed3df305d9e915138761eb20cdd42b338509f",
"eff8301ccf9032fb1398c62896f8502a564889242c9cce7cfddf1b9b87dc9189",
"1babe594d5c84b3e67237b6abcf14b9a091368c587958eccedd4ab0367601a6f",
"b2e8b56a474d41acb1a53646d825bec845cb12c7b96dff588d6d1051136dae11",
"7b400ad7fa14af9182259b51e810e16029c947f2509fb129ebe111fdd977af3a",
"842d63a701a80a9799357ac704f2288ab62af3a62d476fd740c0f8f5c35a46b6",
"dd146653c3aabc3747df891c3a6685d24e9cfe4d61e52f5c7fc7df6f079d59ee",
"2564c5ffb78c4c132cf8c6dc06591661f2d7ee12004af6ec078af8aca04b42aa",
"8c01eb1dcc1e13892a782e9826288711f28ca7c716bb9756e49b41c8d9946694",
"f68743f290c5002b746d912702c1084cee82bdd3c323200dc0710381d98a41c1",
"292a6383fd16ec5afa4cffbf7a6fcc8c6553d4cbd2574886f623b00bf12b1e4b",
"4980e074baa3623551a56263d46933f5fca5465615467ea914fcf6e389e5eb6b",
"4cf461bc4b7f8e1104cb225bae1f3be5dc70ea47a3879257d6652b42ee302a6c",
"79f626c481d62c454a9a8e5d008141befb190c0f4e78c0f9796cdfd8b490c2d0",
"8b4ab8a45964bdb5ab237c0e014c840e224ab1ef50cf2afe79f8810613de8c9d",
"6daef9ecc84a1d29833c0edbfd38663b0e5b76f6ae1d5a22cb081984be8a1ba1",
"7cf7620117fda4ba2e7e1392a39c2c0467e3b90ef96ab021f90708e46df97e94",
"44f6020ce6f1831ef60cb293f456a5ed770aa92b1837fb571ecbf00963e77249",
"b53bc8f19e29660d7c2c9622fc080eb3839eee4b601df47eb3ac20aff8ef8343",
"114f8884785cb1ea54087bf3d19418129fbac44f8c496677778714743e678c72",
"640e38abc942b35d60027a7ca1671ef96da9dbda8d3aac61917189e0f1613a1f",
"23bc1dfe86d5be148155bcb7aea39b8cb68a887a07c7159a8832d7fa8af8d449",
"8ad3f2e44ac576c4a9c364fe497b840bae3a5673a29e69f0806208499332a001",
"ba11731e009801147b11770a0822e2f1e6cab3923726ed79efb3ed5675289c05",
"409e700d67c2541afa301f2c09a4a98de150ff30662f25dcce0bec82da44a1bb",
"74aebd9823146c25c615aff0cac7a2a7b43a3678fd4acdba428bc874c2de2351",
"1ab29e97945c3ead550846ae8af77e6f02d77d24fa8d6af4a866c45568055be2",
"729944aa7565a697548f162e0ec9f39a634fec17615a4b1b65c7b68d06da8ec7",
"dbff2d93d089c5fc366cb89c702f99022ccc53ceb39418e2a9921b1f9d895c95",
"170f0177e2fd6e2ad5e96bf1c7d5fe8443f824ca80c51cb19fe985020bac4dc6",
"44321c4c2e53ab3faa16443e0dd56d0bb18ad444224c09a686285528c04333fd",
"2af9827f953129f8eec520d1409be4d9747fe2213e877ccb06a82e9bfae761bb",
"65831a1f6d27ecf91d452140be9219d010695af0fcb2ef3f19764a4f6b3e07f9",
"103f4a32f26764273b7ab1abed25b768e7994a6bcfe4c029d2eb5a30c4e506ed",
"545d4fd5dcc11f7c29a6ba552562cf4d23890761c76ff86d6940dc707368a0ad",
"4ff9f091da95e9e8892bbe017a8fe29a05955c5c62992a78e23d3bfa4b3c7d15",
"8e82f5c6062204966bfff0f299b26b5921358e22e0880a5130004280c418827f",
"1a6df2e84c39918881ec151d620cc74007c0d122020f6c501dcaff8822f46891",
"01ff674c4dc5d40f0a53318e4a210f418dd2e504077f80e640360db4d2470be0",
"fb4b597769166e58a3b28a698f18ad0bd4c1e24d6c0e3cf58cb800b131f4fea5",
"dbef3658df7ce530752ca69e5248cbf2832c1c458f0b85918f2a4f3666d7b301",
"9b651ab03463dbfb3e7dff410e758430fe535d409805506018bb3f9ba98d726f",
"0795034bae75b616aa3d94df004f4b80717c593aae42e0eeea2bda508fd091c6",
"52d8998c0c3ea0a42e6271a43660f24f17e6201dcbe28a4e1374dd20758327b9",
"a04159ad9cdb943b39160af9eba203f3aeff9bbfd933843bf6cc32f40bbc1f54",
"cf250507d4d9f066221a2c5ce190da42e2c8e9afce5a539f09305af5074b759f",
"5fca2bf5cbda4284eb2a9aa26b55f54d43e28d0efb97e429482a11b66cbc7f8f",
"a740d86574c321a0d3ffec5124431c9a2e52882f85520f296bdb230778e74201",
"5543633ba06069b459f10a9174dff488575830c86bd32c1da6724847791ea055",
"8cb684f24f0a95ad5f4376aa8f0d9bdda6e413bf04a3c8821a547fdf46dd1938",
"b167590ad1040def2161bb854d08fc62b8e4ff4a2d60376c1692c87cb2008e7b",
"a00f55c70f539a98a23b51888c892f2b5a9b86328ec99cd56a11f0e5d8d4d49c",
"73dc98bc6b3862a513320e0e4cd61f5021b30170a2d054abbb62e87036f4ea08",
"ac0f7cc6fbc94a64b50565a929ed6aebd4c6c36000dd40b4f826052b60e98103",
"e24d3edf80ad414a6e5ffca904a259c6a28f1058c0488a524908d1ca8a2faa26",
"38d020a513200b0a6d7bad5fe1e87e39efc7f80b940698ba23a78bbe2cde0fda",
"ffb2bdb644990f4751b4795b94784b5e3c00a5d40afa2b110822eb7dd0cf2d63",
"40a6543d5faecc7fd797d8aaf091d5e4ddf5f075e7f4798b36b6ff2669afbfca",
"07ee87b5c221a21104881b0a6255c2354abfeca80be635803a387a3ef9032f3b",
"d3fe1eefcaa0d03434e6759f8b48fc50f4223edec547c94bf072d49427e2f418",
"0ce4d7ed2eb07f798588df1df044d9e124604f0178ca8941e189854daf64f26c",
"4e5657ffdeb3b88cee74452cd24a8d78ea33013f600d0a6e97c56eef47c36819",
"8e5a2d6f8b4d0878a438d7b33ed8bb7c32294968f71ebf45ab51ba45bc3836e3",
"0f81dcd7f649bbfdd0db6fc69ae5f5a7d89b99388e7d20312705ba07d16a4ab8",
"1cc3486005fa6151d957d0cb6e2599df2680055949b81d4dab85562622ded07d",
"78c8021936527768d5cd7e1dcc30ce55ab13ceb6a1209996a829e3cff8e7239d",
"ab1747694e6e07051b6739e3df2916e09d7cd8a135753c9136a8dbba0449e83a",
"25d6f0d435679e7d84147da65006a48a5a0f893ed2e956518bbcd6b98f40d368",
"3554c7682f565a20b336c40129b5f7182239f2b0b1169f39f8421f25b9ad52cd",
"51b263e67a4421f6b858eb3cafe303af0b3339e0b0509eb068fe3092d394f530",
"2bdcbc0df01dbdab2c91c4658bb9b160fe3efbb5dfecdd85ab525dc21033d90a",
"aa0105f9628907cdeebaa743c45a458553942c3e089d64a02bdcaef293581337",
"d4636ae50f908fb11cfa1f338314260f587f26c29c86cd682e5003fccb554efa",
"31ae9547640c8ebad28019e8eb66cf608074d5c1a95aefa065db97da4c1e1044",
"a228c94293d05874a00c3aa46ee128a41d10405c28e5bed3f7e7f548243fafd2",
"a7d5f3e4630be48f88cfe45147b94b9010718e55d6eaae6462a41aac52e866c3",
"56d4a383be9efe8694a572a143649be7bf89b1eb12842438162532827f7bf101",
"79f7177cf2655951fe0fe7c98cd1cca252e7eafc0b81066aab0841f7cd7895f5",
"abc1746768383ad59c647846b13dbdf51d50f9a5f2c50fac9f676531ed6d08a6",
"a1ad8a55e14acf37cd4eb5085405b62a53948065dcd3bbf299477d03b1d8cc6f",
"c731487e9086642d4e92ecbada3dc31b72049583d446d65bda3a09b4370cafdb",
"729c914190c753c6ab1f648ed04889baba5adc43e05102587672a7a0051b279d",
"3fcbf09cd64d4070062dd2eaf9ff595d3e1fefaea6996ab134e9f394e0814f56",
"2efc8bdc74b41138f0075e2603ec227f7265d3eb6e7ca16a7e1696aa83cc3635",
"cf05b470683e4090959a5e6222aabb1026d60907f9df98256ed0dc62103eff79",
"cae8a98b1c421ba34af46610134a71153d525636c02cccad8e0362b7109d7410",
"cbf00526ae885899747bad4c395b9f2c02e62bbf39fcee82565fecb1224bc311",
"b6ddac871381353848dbb438f0b7ef14fca4eb39fbda7b4eb1747ea454b3155a",
"375b66c16668308f1e768c09bc2dbb0def9dd04d2f90c42c49453f558220a338",
"a2387da7be7ec4a0ce7ef03cb1bd701330e5e950be120854efac13d903367248",
"21f4efbd857d838626a5b6eb935c1d8dc3a0a6c8defd23928c8018c4956663c1",
"ac96b176999b37719fe3a67231b811a7a435ee7b5e807fd1430803a29cab70ff",
"9c06f32a7f016a0e702b928f7de9a82297498400654109ec3a17a1c2531a36d0",
"fa932de504e54776e5b8fe75a2aa7067cff79865b766882542608eb31de1f3af",
"d994c1c85ab3611ad12fbbd4ee7e7afb30ff9ce3c67ca619d9786553b0383668",
"2e5789ccd625cf20f42a72de7cdc246ab92a1cd85ee619570549a8effa476ff9",
"ec4145c429fecc6b5109d5a4e1434c4418925fc65f53bda6cd06620dbd2d1b69",
"0978239a7a14bb768e1ca71e1d40e37a102091ad01a75f5f92c5da900761c79d",
"3382546aefe321d644bd3626c7b767bbf940df0cebfd3917c05f69c7973136cc",
"227e8c8045928af96e794585a87d6869c3ced7dab3689c5565cec54e168641a9",
"c0a3f1b8c27d0234fc64fd8d1ff9f6d3ca157b03033e505bd443f1b7bba62f7e",
"2e848b33465df0fa0a2b75d23c4df4f02824f431e78e80c0221ff5aa61348a91",
"14656b6da232af334beffd02ffb86992637993ce4aa530acf8bbc2081c5dd2eb",
"1697567eea595c835310638672cc7ff2067a568198731128280bf4167b2e45ee",
"749a784a544085ed3fe56e3ce9643d0e13aab8f3480f2fdfe7c16e15ef08d0b3",
"0b2b27579b615e086959fb35f7741791615e25c611f8ab7851c83bdfeda7d7c9",
"e444de3a6fc90b1d2626987fe98c956c1e0db2008cdbe6d863ad410e9fe0a8a3",
"89a757ea85e9d24b3e584538cded1e5db3a90bb01066af609d3401d1bb5b205f",
"b00b5a1ccbc1ec142c5ef063daa88aaac1d3e52af12256cd892803aa348c3f30",
"0ea22dee4f62ac35e5b45a3beeff82c8c32231193bcc33ba7575916dacbdebde",
"5c428762fa847e9a97fce0f306c7f0d8c4b4abdf9defcb0df0dafec41590ebb8",
"8eacd0d7d08645ad8366807a5cc9f91a4b22fd52ab4d8c74efaeb9fba398f24d",
"648ed141936c9497702be348e260b9a4aa9ff5dadc6b654381c9e54160a07f4b",
"682cc4ae34101c80a98fe4a674ef0b16d11ce70b56b3a7fc5b191b360deeaecd",
"2b82b8fa930e14bcc38f1b9bf6a99f3987b32c7e74363d20acf6bd05057cfb5e",
"1d2c04136aa4ce34040a9756ba9f16af6a3fad26b7a9669a62c3563d66a4d4a5",
"04ab01586e7e4615656127d95cd558e318457ed1641c2229b75ed676f21ae1d5",
"a7a5c84706284a3c98121e35e89e3361c39ab8b5ce26c3e479cdb4c2f30aaea9",
"d12b3299cd334b9899ce855a088577d8d757dc32125921f2ee561daa94814b7b",
"48714a6b92c6e98e3406ee38539721a3ba60254ace52c741925222955a89a8bb",
"27597f719f1a11522733a0db69462fd7d28f0a64d6cb508af5dbfee291b52f81",
"44c2fc25551c204419d798aafacde9e75b4aed663d47c0cca8c5c3482b7660ac",
"9cfc7a76eafe717ecd56501bc16aa644bac189cab58dbb90bbb0cf3a4e3053ef",
"029223d300c7186ab0c823474f67590a86e7d08a9d1ed39588307def876ad59b",
"533054cb85955768daaedd98ccd79495e4726b2e5e7d345a3cc70beb19538a57",
"60e7f410dd3c32e1c88638ca4e758db9a2a8f7e52e2faee358fdbf5dd3fce27e",
"3ed8f47b67c5cc36b0e6745a29251d0470795cb14f0ad9b30170c0e5c8efcbe6",
"1f889c28d68e869bf711e214dbe739acc35780e8b19ef9576dede8e2e91bdb9d",
"dbf00c8bd10f5ae12f38c625c8af8089cd28ff92f34a1d949dbdc20d7a80d797",
"960ef9daa1b246bb656aed819cbe898dc14ca8e558070c9468f840487c05db92",
"fe1b43ac2709550840c682ecc23d2699e9b3fcf55851999d9f09b02370aad502",
"9f58ad99bdc049a7cc29f7bc482629302d56b32ba3b4a703223945c8a61f4254",
"af61383d241fa4cee95f8065527537a237914d9b1494ac8fd3ed476a604882af",
"503e10b0bd880beb400e91fce69c4fc9f36e3c816ae86b7b8d9729d00d08efc7",
"beb9c475c020f4af8659aa27ef0d1dd143479029a8ef2f605adae61bd693c9ce",
"73b93de4843e323d7db0726e0bc301ff0194b9656bb40bd3baae073b9a4df96b",
"3f3a78847d9964cae0df94acbd73ba24eb042f44e5a473b1dc665a4db518dcbd",
"240d37aeb82815e4a61db5729ca10d069d9554e3f209eecd881d12719a47dab6",
"87f8197177364e5b345abc75771b0418890afaa0c109e2f6da58df071868c7de",
"9d0f1a386ab8b2192f4531281d50df5d354a96afca98b9122198982e0120d384",
"0bd411fccce089fbbd2eb04da0cecc3f030d036a44b78f37352816bd2bec9c1d",
"a5587eb1bb907b021e206cf17beaaeeff2c34c22a9857c0ead14d68f62b1818c",
"ed96c8097a4fa7debe2db8b1aff9baea5ebad839b60b7ac878fc93dd704f9633",
"c244897280ea22de3494642c6a8219500b884ccc77802b953f71cf12de445e28",
"e11b64f780d2e2314fe969a74a86129b8cdaf4d223376843b94f4e64e9be7eec",
"1a7771432e6782bf9a5ef436874bb9aa44a5f46d1a5a7aa785dd1fb2311d9d58",
"215be42fb8c3511dbcbccd1634895857d48d2f26de9f9f167ffa86f141819298",
"5635725b8e48404be37a8c9db3274195cd7e36a651c65d09ee8419c571d1d233",
"3bbe9d510574073e795b4f843f272a1900f31510f9ad36a522525845c90075ee",
"1b19a47569f1803ecc66d1d5163c4c6e7ab9f7e99abe3e8bcf55f8cdbb00ef7a",
"c155578db721fb204f9759119f8ff004d78ba068869c938d9ce0a57e650e085c",
"017d7f31830417c7a0ef240d7837ef9cf047ed0a8414eb085da37fe2cddbdf64",
"78ea7551cf28cb954259a28ec1340ee66d715f02c5eb7fec48145298581464f1",
"b89ee6474841186f5afab538f9ca17b4171c303d5dcc89247b79ce38389bc0da",
"f15ceaf2a19e8eb599bac5959aba3518688d4791321e618b5ff4af1700fc969f",
"6c0be8eac8a473b665f89bc3a310c033c093f5b062527a227921b072aa3123be",
"60950a25415add062c9bd5427cf5e0eb75d6fd7363af9d44656831d04cdcf7fe",
"c8ee6f1b5cafc14571642946e8d8e56191c3a9a020e5322ec30a698258c24a17",
"fd5a24fb185292c845fb8759d924a72f24c18758fe9ac5e0df99d1365e0657a4",
"85db138de6940bcd58f37836e431c6d0dda1722d21f7fe2e519d08ec8d990d7b",
"13a18fb4b02a808771e8a5eb2a64829bf27c7e6fb82b2adf8d44a920fa6a5900",
"cf37460c8ad19a604cd4d1475e8258ddbf72e3163d07bad676a0db39248f298d",
"16aaf7854629a4612442c7c7b67836990ce60a78b95bb0221646cb9d27454e2a",
"f3ff2a33d32daff5a2606ad41d8b9fa469fed175ab2d12cba2432d2cec320bcd",
"3f84dcab7582376089e959b42b47ed237ad52f5e633093bf7fcbff6164b74cbd",
"1776d3f2ca165cc20e0736e7ba69ce320b1e19575245e0e78bf628bf8a3b4c90",
"4b815273385785fe9e57dbe6bbab75423b6302f8daef245c12bc4b8572696893",
"f9daf148d2ece99869e00ed44ffc1a740792569a36d6dc21a94388453c31a08b",
"0a7f0cc9bc54b816a21785f84414bdb99f34a49a3e33e5fa1d105ba026540627",
"05ec349ece9f47e92ec0bada62dc00a7896abe818b213914b95d3cc301afa0cf",
"3f652f63459aba4684390a90687e117bfd79e09b42542733acb734adbb0a01cf",
"d7be18e61d11c4e5757f2ad5fb6b8eb70ab1f621f7785d048baec87e3c81ddb7",
"cb4ef5ac7ff2c34808e9398ff7e313cfb5b73e8b3cf9c0c3ab8059983159213c",
"c1f66f86c3dc26b2212cd7536bd40bde14015a19108d997e24d0f5b1532c5201",
"2e8766d4dd56646f8fca1cc12fe66785bd90f42d27074c71e3380732f5616558",
"feb95b15d26976b6b31bd488430da464d87102d5b35cec8bb578cffc91bc7933",
"bef956f6a785e9937e4e3bad0b1468c428534fc06658738d5e02c1a604c77003",
"fb471f8b762add49e6d91eb46cc018a6990ca7bf1fb15d26aec90f6ba968f6cd",
"d4f35e4a4e006546af1bf09f5e49b5dda60ae5dd526b85ba92d871f4f09df77b",
"795fda42bece1d711437fe504f78e940f309c89830bdb5e9dd46afe3fbb1b150",
"abaf0bc879b70ace0a82af4b9d4f32085ddc7c5d920a673c47e83199959b4de6",
"ae69a784b18524bf95e7b2349cd1c36709eb810b0168e7e140a7a411443a02dd",
"7858fa7acf40bbc2168ebf05e3389ae646d1fd4567b17470506596baa5e00ea9",
"d9f1d5f5ba2a228915342e41510bcdaac533e10025531eb9a1960b93ae667332",
"5a0def567978daf9e17209cf27f261256f11d0f8cc946c888ba3bd15e56c786a",
"589c40f1e0e442e1e227c1d45ddbd799c41cc38d025ae871bbbad98e0b65d2c4",
"d25e897ed507bc4dcbbf349cc2de3d2240ad6bede49c89fb07c9b5dcc138363c",
"b480a7829783c502490abec998b2d0253aeeee68e54bc165a5f1e98cb6a9f4c5",
"ae8c6d400c2d517eb69379c486e1ad35497e692292bbe495f0d01b4d4e48e265",
"27fe2f66e35f873b8094d7e2ced46e55811f5a936f9019e5e2db41b7ae5e819b",
"1d767698a7e6a1d6adfb55c1584880350f2c4e80f40e51776bd33a6a2e47ba8a",
"70114481a06394db7de45673ff702a2ca4047d2715d780884f3f841a493790b3",
"404487dd890566585291dbf1a22cbbb7fd70e4870b36f39ee7c710320aa0c270",
"b908e1a132f73bc705594db6e08b82fb277a87456142f6e6145fa4701d7de09c",
"7f0734a0c77fbb88b5a5a4d49f995bad567f0a676cc9326c3267211d06ffffe7",
"204e168e47177bf41e3066b1ffa5f0779d98fdc7a0ff8ac5399f1c3abd6998cd",
"fae75f8b1c0302a15813cdacc724fb9c9d06d6ac7c6a358b1f1c33a9df3da5c3",
"c18e90a57bd273f5d27751fe81ea9302f5604f24c2a2a9d306e2b0b26ed65cdc",
"dc084d1ec5c777f8cb78fa955903adb7bcc68b0d18cd2de66f9c32acfe9e9948",
"4fbad69a041e89833b72a21907459d2a9985bef82d05f70a8740f4d1abbac471",
"f0d752ca1604efdc9102728c70fc2198ed466b21acdafe6a234f7124cdc3c531",
"96a291d08e64c21d74c94982a2d1a146ca25ef24b4c2ffcdb3a8bcd77288072b",
"d84f7a140461dc63b72d66dc97af315127f8260a6176159f7120ad15e0ffbb42",
"e323b02b16317a133f695b892900cbed463c146310f13847cf52f5e8a1556403",
"56f9986c62059e091f741f5febd25cd26400acfd51302e09e853c49815345372",
"4a91c13e08448237509eefdc09ed41470f72309aeb0f3577bfbdaf2f45b359ca",
"3f1214f03f2bb53d779d05f2a3a647d0bc2550b5540ef159c2917cbab8abe006",
"c00d7a898094e86d4659ecd1ebead956c2d74969a9c7ea05b2ef5daf456cbfde",
"c9f7b7bd863e12133688f089abc3846578a8c50f8fe95d33ffae1472cd61d396",
"9c4cb359614595f16ba7a76a3a5f7a78205c32a23653a935400f147206eb4a2e",
"f81f1b1b6ec3af3a09c79607ff09a025162ddfc14cf85ddaf4ed678599031bcb",
"07518a7b6771f27678761c04c584da6475af520f2358b0886ac0f792e5b07e79",
"3d8edf9ff36d26b12f22af02685c72a8f9106295c7cd06cfe74fd59967501ef9",
"957afb2e2abda010d44ee4eda67a2b70b61c56594a31964f860b26a28cb8454f",
"f136ce60520308496e1802b6de253f4911afe61e910358b2ead474a9cf48ee6c",
"7c90e7fd57edfe1fd3504153c5fc31342a7b354e93038b45140b67fb6fd18e65",
"629c3a127f091ebee42b4d487d029bd4c3fa2ec72dbecc715e6c8c9d2671b736",
"41e8646e02f9bb0537b627ae5f269154b03d916fc490d38abbcfc3ebf6d9dda4",
"72d66600ed0cc1faa6d91c2a0da81bd90d4538cee893aae4bb0cc14eeb4dc280",
"81889ef1c6d2c81067e366ab7185eb2199be8789f114ddd6a3b693ef7821bbec",
"8adb60319e326ca0afa70e7f8ce7209bef89e1ec820a5d70f13d606add534ab6",
"ddcebfd51afd77e78f06d5a5dccbfb4d6dc61977c47ac9b1a2f6402940d9a156",
"b4cc18127051cfd93b1a5eb0358153c03f1d44b841a41cf3c2a7a23a14dec4f4",
"a3d44b5e13a0c0e6eb22da6e8811d4995d495d4d780e840ee85c83f2b1656082",
"eb69269adfc48cad8200b8e31807e9454ec615b8d33b67e7191cead52549007a",
"cc6bed8de65dc9b905e2aa95ad5fd57bb82ee21c49968cf30a6cb4b002be5f6d",
"0ee85d0f8f0f5bfb77f957de73fcb2da0ff2691b2971ea681432a67ae5c7c378",
"d8a2af3e7a30804574e74ed97275804fcc22c19607ea30251f7fcecfc86c8cd4",
"be4f45e912a7cc5a174d6cd1c058412042308381f9882d2a74c43cef9a93e51c",
"b2137011b2206e9737392b735787c1861d5df47690b5682cbd432fcac4c05198",
"f4fcc63e7a123783b643adbf0b97580b789def70d8ce5af5955b35b263f4a4fe",
"1cdf85f46a7dd1937cd43c941f1b555d582f36d3091097231f86602c73c84c7d",
"76cd77e06f946eab3f59cdccd3a3e20395f04d5e61ebc5ae6cfebbf72d96214a",
"f080f232fbf74a104a25ff2df6958e0008662596f81cfb84cd72c2a940c9b5fd",
"70a13b34f284353ecae70355403e6297fbab263f207707860ec22dc8a2da4c94",
"2d1bceb4417eabef500af978c975f18ab1b01b12946ff411832af267652f5d49",
"74847cb2b631547a13df246f10f21053e1d412b4bcc83d2a28285033c75a2839",
"0df6e0d42f19ca95d31d9b762fb58b9ee4ef0a2037cab32e49509c575c6ed19b",
"e9b6acc84e087163ed1ea23f7b7aa0fa4ea37f15473a47af6618d7f30e8f56a7",
"3578384eae5e7a10731d6de0972072f1f568a764ee9a2c2c6152eee141fdd3d7",
"69653aa6632c7fb7c69a8129861e9f3226b726a8804471165642481b598dd099",
"a296c05fca5e44afc5c2cd583cbde4a1791bdb7a8461c6676b97ea63c11fe393",
"077900cf366702fe8add4f0265cc52273b343a14218ea59ab26cd628a38240fa",
"a63d694c0e6728166e578d90061d24146d56ccda4ef281c41ce6076ad51727bc",
"1623e53bff3af6346b27b38cfc0d98f6f2ec80830789f88bbccfbecb4ce1162c",
"ce5c3ddd1852bb75590b6d8db16b4e6264a8993a3aad89f1731753565d5e54fb",
"3dc87d48cddba8c9aea71e8307e9d803925c9e4c4f55d7730d3e651dbfc7ba45",
"1cd04f320cca7fe33c2f43dd9e0098cda82edf20162a67320e68ebaf3fd74fe5",
"8d63274c4a44170e5008d2d1b790d5f468269abfa91a54c329152433a30665b9",
"89ff3946f2111436afd2b41932c475a0d09223e23b6b9e9a9ccf164d3cbe0b11",
"db63caf3eda1222a308deb317a0bc8f1deb95a6b3b0108f71d2d16691244927b",
"3d1ba03634ffaeb5d906032273191fe2595bd655a70dd8c22680fa4929012c6f",
"0d355563eac60a85c52b4b2a54c21ee7610819a9a3b30e69a9a37b5655b9b5db",
"373a44ab3936104a3d9d26a246d2365127c1726c34d2f1d7e87d7d7f6058f248",
"16022145fe055769433d4c3cd9639ce0f8f668e157bf9711e2c7bd7907178df4",
"6b34e7d77649a72887fa46cb34618d813a32fbb77e4ebdd6691527eacf5fd84c",
"df915fc7ca49225b34f2d419554d2594c8b2ffd834b2bb92f49397fcff381eac",
"6002c0ef73c781b20d7d4d9e01322f8efa8aa78e5e9792bce29a9169c7032f57",
"3a0debbc0ee42304a9edb10db770d0b8180c403971f42dad8832cc16e395c11c",
"6d76b23d46aae2e574ec2947c490f2ead9acf9592e417069e72050721224fba4",
"593602ee2803bcdd743fce93962f672cb877edc7d009be65c02a562b8604a74c",
"64759e44d4e426d1c147b405330e2fe1ed1afe168b8db60a87c935cf07ea10f6",
"d8f1eea3b2c56c9bdeeea5cc57d5fb38cda7c2dcef9276ed5602d27b9788c194",
"0da1328dfa5efb29034215279a87bf026e70aa7ceb2793e8c0ba9354580d552b",
"8bf631c56ecb7ab31c0d30bf31dd28a62877402cd6825d0ecc9c71e26f4be643",
"ae29941b70abb79f690de45e32c8b55f8114b30cae4376e991b963d4e03d970d",
"0b87ec546259a15a8c8752634c3ef219459c382d383f155f219c04d9d5bd7f01",
"87605721bbed02e5f279a29dbf5fb857a5e1d41ffbc50689ec4e1ad1ed3f2b76",
"64d33c169662adb9ae01cc1a902b8725ea84162226d860b05b22c1cf8b716b88",
"dd3e22b9aaf98f165f20c449618ebf776727386daf5695e68847462a1573f1fa",
"2eed687fa82a0df68fb2a1ccd9c7e0679f5ada28b831b105718dbd0580c0aeb6",
"3748437a03b2e086825a1b26b9a363495cb04ee3b5c6125f16fa7153d388b38d",
"d6f69cb9ff2388175b1e549df23171ea6cf0f181c52902e90740dec0fef941b5",
"81e173033c052c2a8b6c2ce928c7d9e7f7b956e9744156c8b40cf815f093de69",
"627027e95f078f86d70df8b97d509bd556c6397693025367ae4b43edc9b6fdf2",
"9c8bee1ae58091342dac7901e5846df4acbbc409656457b03e1702eeabbfc8f5",
"ee387d8e66f5bf75dfdcdeb97d28b4dbbcb1302bf20d6bf8465b7b41832550ad",
"681f0145ff4dd8a84e42b02ca5bdf4bbe8adfdff11e3ae57673740a4f98f0c67",
"9f7d29a27a80e64603c98125d6f77e23afac3ae85ab0fbbe91e74e498fa69c89",
"f23c72f39810dfa196ddac4a2b30fc97f3e05cfd67d91ef2e6ab063ee29483a9",
"cb02c55cbe1a20d200bd53e718c78f9f2307d0476082bb425d4476a70ef47172",
"2c56d7a46e2e989c71d754a9ed2ed22285adb9bc7ea0ce85e7ad0146798836e0",
"161f8ede4832a65d9d082699e93299189916a9feae06703aabba7aa7100c8078",
"c14f24845530dbca3372c7d7453441113682d76ca7c5ee93a86f8705dfa6754b",
"98e2302a8c27aff16705eac3c9b4861e0d670571ca493dd0077280785d1d32a3",
"1af7252bf32de08559d47dc9273c82a7e6cf89c2ad0d755084116bdc30e2dcb9",
"b662f05da0258a7218659df10926cb716fc6d092654ebdf9d8a0efcab72f311e",
"ad8807bdc9c0db6fff8ba8963af51f14ed809ff5cff5944d27b1923bc5cec68e",
"4502bbe76bba11effb1f91a822732bb4d1c6cbd20a12722cf7cf2276bcb224ef",
"bd100da2cd60b60a2923299e505c6c0fd23cfdeebefbcec8119567fee2b8d5ac",
"2725060e6d944dceab24729b82d3a64275ebd82cb42ab330af43f53cefa27893",
"9cad96ee381a6d63d841569e475eeff6dee67836e2d05113a8f18aee590673b2",
"c22c8e48d846ad43fc8319c4d3ed8c4af31ea7c3e079595cbb557b78e50f0a60",
"24a9bcf359c2345fdc35812a10f9f08229d11f17c5951120cda1264adb2e6d71",
"54658722a2c31e13616e4a38a817927c01d2df37830dab7e76ec16e7ec93e298",
"fdf9d5820ce67e076d78db09766a5827c6d14678d1336c8f936608d80ae83d72",
"f3c55939c47563aecd9a0be2fd16c8d839331c811403ea22d47a8dedb636f389",
"9a62ce2c9a3238370ab983857b27a6ebba407540c6a55b8d3e62fb012b9177d5",
"32ea29fa721d7727b0ad77f534bba0ccd4f08b16b1c809c60da2e83c37cd052f",
"0c8eab2d814623966122a83e079ae8629897d405fc471fe70eb8ecf63d53a6a4",
"b5f81d6be6c5ed881db8e195b850c3ebfa2cb455d0a1d14df79740eebe5d549e",
"ff39acb8667a42faa265d97a90fa7d5802c6a581dfa6bc868fc6e953b4fe3b10",
"cd1a9a932859370e971587fa26255782a1aee9a1efeafd17badd1aca3c822363",
"780034cf738e520971387345b73f42cd13770dc8cf68948ec9e8e1f6a6327f61",
"0d97a70b467fbf4af625a6b539035b19e86d011782bb7a9ce538bb89d81438f5",
"ca8dcf9e3454d6c2a346a01372c798cf2cf8c49c38f9581d705c42e4f1e7c4b4",
"0c21834cdce637a85f931e8d2d961573d1dba0ab7bee93189f74c6331995c914",
"c8aa251601172c9479b4ab2c1382a2d6608b547cf6b7a4a04a75a91fde4c08b3",
"14d36f3db5b2cfac7a99df066016eba59a21ef651e991d631c04acb11d1d2b51",
"89006b74bc61637b0808bf786df16039d0f5a26d1cde1348de0f33718d47e75c",
"098621c303cb1b9dda387a0ee66ecd267172a70defc1b403887ea74c53d5b911",
"f9428c1dc527138be5c9ddbfeed43077d06f2826b75edf9218e7b90df8b5ec29",
"245270fc3442e19475818ca0d5cd32a4728a25b5c4f2231d571eafa281e61e18",
"753e79f5b9edd2e49c30c17d3d5050a2c0265027abdf8e661281d22e6cacb701",
"7ac9b5239a33b2689c63739de793dfbbd0955c044fe062bab28f7b9e72af4755",
"ba6c405725d69b2c74661f3e4259242b054d13f197db5700d1d7728110e56955",
"a7ff3309d156a8d4af88c92e5959c98617e0c1b95a10caa544fd761f93715b80",
"4185a1fd84ac173ac31493ea80b4a6d38d37325e8d82d07ee31bbd7f5c661e17",
"78826fde40d9fed3355c37bcaaf0656a4236d58404a892d1da402955698e2904",
"9f591f6bb853601a315de1edebc0927bde202e6cdacacace8dd32bc824a8a094",
"3ae950afe6ce59737c943cd90dc8f100de10de1ee952b2d295514c4f710aa7d2",
"a75089fa658b1206f03622608239f2de628b4a4693548c864d6096e2cef76490",
"efa7ea258d706b04547b8d4a791b1113fc77a4e5547c8a308a89bcbbf8161e56",
"f0c8cd991b168fa30685d9adb508e9aeb4f2b63dc08a153b814b0cf1f989183b",
"6f1946a94c3138276073dcfe0d0d48d3cff0452993b34965a8fefe90161f0fcd",
"2bc40489956125fa47c9cff896091977b8dd0b7a0e0150f614592b11a2e4d1ff",
"b2f96fc311567ddbef1bf0fc487f973145f717f283883606ee03b4384da74003",
"afb571e0e140ddda917b23d993474493d61a8414b0bd191092b6780bed309756",
"687a64c739ccc3941a0eb74554bcd0135e0063922933ff892c7b90b88e21c7b8",
"5ddc34627e55a68c4fd82c789c10d7fecf3e380b458ecd18eb8c5ae041c0b288",
"ee7584bbd58e279c2667ffc07c1c4977654fc948a63e33633a563c757f0dd9fd",
"3b7fb2e668fbef730803f10eea0e6cd9a2819eee7c1c1418431d1dc683def7f2",
"b4e18431bfedbd98c924a64497c60ca9e4a82f22084fa1ad24c09f79b2ea6a94",
"a5073a937e8b5cbbabb8915cfd2f2fe7307e4e334d5f434077995815475f0df2",
"455b0de46808bf01d625c22f0cea27120780c8c69c0c11cf837e98823faf58ff",
"a2b26681847ad348da10f7b578cae28087a3f5aabc5f84de188ae7ba9dc754f4",
"f03694a80d8dcf0b98d4c4ae69a797218cff7688f80ea97e627e817ad36f3795",
"006670166e382b2bf369907cb2b4834d58ccdc55a4bbd6494e8f9c129f5140e6",
"ba02ab95f8cdf7e40f03a629e47a0f7d5b77096549f17a158c73e2b96c6cf0ed",
"e1180c4ae2e094ff0ef2dd8107e5f2b02bebfad6501b18965b75ce8689efea2a",
"a8114db88256707afdb0f589c4e375a7b165380a0f8c2795c0c0dc0d02f5684c",
"a8ff66f47c414f56d8129e33a45a0bd9b9d1a640a3a3454d3496ba3a800b2d1f",
"f36ca0f95e603f806380dce52d91036d8e3a5545e1dd7620a19196397b91359b",
"1c207b576a1e9e765209ac6756c7948fa3f252a4687696d0f8e831f14ca52b92",
"cc5eb95f7759dfb6cc55027d49a5fe9c52f3006568cd97a0c544638be7a887ee",
"4e15d5885837d4e5e79bff21930dcacba97d2bac39e506896e005fd55aad7e67",
"5e2e62808fbe25793a6917dfbfd06029ea30eee0892116fe6ea4696fcf62ef53",
"334d575dcfb7f6b606866af045d0a378f53447ef51d5b3d1afd83d78c0aee1eb",
"591c6dc98541b9fa044ab89f78856374c3f42ca5f8021bfa0e119d8a04a28646",
"c502d6853c8eb8a2657e069659c1f3b06878498d1b1a15f771fffaf886a1ae52",
"2d4b16c2b6cee606af3c02ae8d6a86560e2393306fed2ac0b72456a8e35e24b6",
"b2ee8ad11dbd4ddbca245b403ada57354b5df94a9de54bdf574bf0eb41645c89",
"a895e7d8adaec8c44b603648f36774980707d30ede4f5dbaf2bd3d2e3d4e90b4",
"1e76fe8a5aa1b516db5d04f3496e69170d3a6910aea79ad7554e2527b81b6b5a",
"1576d0f08a566bc422049efcdd942ba455e61a1bb2d6e1ad470e098899128f75",
"ffc42cbcc82b0b23c5616301e90aa6ed76f485cd63506ba52097a42b5c17420e",
"27fa1edc6938b7d3658c5c9d894136857fc0be8fa743924a86ee4baf583599bf",
"4c8a502fb162a9580502f4f2618be83041782f245c6023e1d6c3ecd7bbf2cbd2",
"5b72391f63f61ba48fbf8fd308ca6afb7d72b9545d1812538f2e4d1414c6fb1d",
"1968aab09560c49509dc7cdac8c5c919629a3da0a39d7628b172d5e7bde99c20",
"97656482e3f4c9dbd01cf1fd91f0deb0b319c15a89b5deec6a57fac647a81753",
"d1392d6f39252c12b76aca6762fd95086785433913e5960b3c14a708401c2897",
"c11244439c754d91aa30a2fcddeef5a0be7e300b94a5c98967785f112cdbcfff",
"21c529765b6a1048c8c946578be14e63750eeae28521fd845bf7a3ae669f203b",
"c2f22169832b5de185aaa5642f125738f164001083438328d2541c15a7f986af",
"293583e0b2b86f041204e4ddc9546ca74431407f88ce36665337a5602dbe3bbd",
"1c270bcff184b5efcdec7f630e707c3e7c90a519302233fdc08aa744d4cc0f9f",
"88a9d5a81d358a14cd92c14d669903032c93371915725d764fb01c7c1673d4e0",
"c733a54fa8d1ef07070c52ce77898eb93f148b13cdd1b6fa69884dae4b62144c",
"acc7546cee77ad0a641bd33253869e0459325db8e6e3a9c7e3812916939e5345",
"edb6a177be83d61f8e67db1b3837db0316d0205cc7303c242c697fb3c2a1af25",
"8e1e002d811734ae8033333794c2bdbe826f1c69f4dd6197e595e75837a3ca64",
"316f26c9d7b2dc523838fd4d8a102e7b817a44d00a4f31dcd30bd6529ca3070b",
"0ae34d23335c3138e2ad4a282b3bdb89542bdc29a4df69d202ac41f140e15aa9",
"6c6d48776be2e5a30e91af97bd6b0bc5a5eb76a5fd713adc399f8664918cee9f",
"dfd7c371eef529314fa853918ed4fac86e473d5bfcd9dbe261e57201d70c082f",
"0046ae85e6230a07ef27a9c7c75dc6f6ccb7742433cf8be17343ea8666512259",
"dd9fe83a560f0897bd19f23474fe744c8eade026cdb1f048e84f3459e0f19303",
"3e6a71ec2a652defe81127e60e22728c5c2b6b7ebd3f8946e347d662ff3a868b",
"a4229eb078f80905f012a474545e0e2786f98bf7fb2073dcead7ec73c65fbe9b",
"7dcad9638f5473ae40af1a5d9334ca763a09c66812806f67e75bb44e457f87c3",
"374ff61877eb866ee324a87077eb71d0a269e9845847e55a5e10fe5f3c77aade",
"ef6f393a0d140250e071d3b82f5086c13bb429266cf944bae8cdaa28834cef8b",
"9651ad41b55c6e8d6abb345d4ea06e4399cf2902d2c1cf13ebbfba0b7140c8bc",
"9d0540e58a6445fd868ea65c40185a7da7858524f419797084a602427ace7477",
"5d812312bfa56dced2d010ddbd98b79ec946a4c13fc545088c80d037e4df3c3b",
"c75d28a33c292a50e293d4e88f25421bc03c83fdbafaba4f526b8c6a7e5c2e2e",
"53cc98e7b41fa8cf94ae5ddb9807fcf8c73c209d910c892f266621fa05782ece",
"f6b589decfffc6c33957cd061404dea6482435abcabbad3485266cf4a8e7fc05",
"e4e03d0c467c2420923815fdef774f530d07c0c415e9975bed75db2ce4227dbf",
"7178a3cf86b9b27023e576a0f112ddbd3e240289bf8c4256ec384962207d749d",
"58c29327189acf5670bf364f2c9023439eab2dff643a4ff36f3d35b43263111e",
"d9b365bae902827f415288ab30e5e75d93038ffc1466356d6f5280863f18dad2",
"ffd371a7a95b47d197bc947e0e1c3cd50a96657ca14116fad6fb7ec96aec3bf1",
"10ab513a9aa33ce2ea4cf293dd0c435b5aad5a1adff65604dd3f07cfa1f340ee",
"40863aa43e50ba80bdafdba66ae053896370421d48f59c2aa962ec5e2914bd96",
"0363498ed651cf53bd469fd0dd8ffdcee6c6b4641a67bf52fd177ee7e9e81324",
"7804a9ccc78fcc0e6b6583e2fe28a32d3b409a08dc48061233f8faf88dbcfa03",
"68ae59987180df7089fe2566c5d2a61d554b267332a24dc44ffba97c1ab1b596",
"f2c29ca8dd0b0429df3fe25fe3e36e6fdef1170dbed8baa30cde80f13cd093f5",
"06d4400c68d16ce0b1b70f8fef726fdf633af85eac4e285694db95c0f8e503cd",
"8db9481d31cd20f8ebf15b2ac559ee46796f0da83b8a94139ab998e2be19f035",
"4c4a93fcff164e070a9eac32c8b7a582a00c6d32f8dd146cc603520d91fb11dd",
"3d70cb493fee1f8575dc7da9c7627d31ebf42c9842275f772ce6f0d42e06db0a",
"9f28537ea916ceebf76f1a42544c43e13e9075929228f32190d9ba4f5bb5c9b0",
"673af69eacb58312c01c9b4e93167bf8e5bec2ccb4450ab833baee81cdbbd95b",
"0d0b61e12e81bed69380c9b8eb23a2384a48bb13a4b7808a21ebdb00960e7e4c",
"284b4b1d0f126cc76b743eed1d255b181a4ea45839ef0c1dd2749ce5ae83270c",
"70cbb1998efc52d6b6aecca67551e42bb44eb6dd6e400241d2e2bab34ef9c1f5",
"a47582681ac364f031f9d19c42e0b68edc0749c5b3da9581009b5187b8b503f4",
"808c8d746109d74eae54b97f45ab7b9ed24f32835cf8a1ec9d7d46c3fae5178b",
"ab0e3e550b11a95ebe15edb506a534d70e4bdfbbc9172b251668cb8eaffa5c7b",
"8d24d23ec2012ff57024b1241dd401eea2ec104645e5dd4088b32546fd8ff904",
"523fc99da5bd881da326c94b303a852c0796792c1f3abfc1fdc7590c9a1ad80a",
"bef023158f2dfff9af92f2aa64e7da3087afe08b2cd5bed4d6a0933e46efd411",
"bdb056bd0ae30d8b926688b56a6e06029905ecb5b25922fe4f6f2004d4adfa11",
"94a65dc8805bbee393a49a95ce8c95574ab280d6cfcc4a1490cec8352754c6a4",
"50410fb63b9759e697bbb5c62d39820ce5d1f76ae9697e064578a15e0621b792",
"90bc57b7055d84741c13f3a7707770de07ac2118015e3f0d08ac9ca3a4a6e177",
"4b703ad6aaf1cbbd6f4fcaeb9745fa82f6fb055611d7164c572892b0fb786114",
"0ab836aa1a9ab4467708652e8dbec2885119358e37b32f51b46d45f33c88046c",
"1a118c7d922133ccd430b9f9857b62f8f2ce4df7d648a197f6edd3fefc07cecd",
"40e846cc774ddf6392d673f69ce95245690f25786770051ba5ad49461310b0df",
"5aadcafbcf0b1b4723d39c5d4048a8d9f3889a3f68aab66cac0ea4f0ef7d549d",
"acdd2f2a548cd325fc06b49c257bfbc9b09c016ab0859cb947aac64c4570f6e9",
"0b3ab537044f2e6142ff425079d25fcd87e0dd8187f03bf0dfc479142d8b9abd",
"497c6521a301865863f7dfcd03316ae0db690e98546116c14df05d98e8cdc893",
"ccdf5949457b2394df193f21d8cacd4971942ea3a1467e2ab13fc0cf38a2aca6",
"b38079f35e81d62e2ec89a5511537abd020e0d49f47cfeacb1fdf0000e3898c3",
"b5477b70b3e6f62fc281e349303e8e160a5cbf6af135bf3c991955b3cb963039",
"64e8bcf3fdb18248ead8b6c5a23b156d76cbc6ab5789815a2b45c365ab20d353",
"86c981eecb0af6e8ada8e68a9ba9a6cb93d0ed527a366121ab0dcf9f44d2a38d",
"93ff8bbd4dced9f09d343b2227099d63a28c121389dda386c8b58acac7e020aa",
"b9b7cc4a4e8b9f5a1ec1116d378e3f90ab3e8e4605d4cdc95b3e4b7df2815a1c",
"f2f37eaae0ce72d792c65a906b6c7334c2377c3c31e454063305e7e63e5329e0",
"cdfcf71c42e3d8d056cab0fbf3625c1b13704870709a4e0850006447f128efc0",
"83566f6ad1536d4aa2543258bdee98989807ffa133d36af3a26672708ead8410",
"68b89c27a8254d5fa39096943bd9bb0074e950fac7e686209c0113df088ae054",
"0e8c8d00c7e71968371f4597da934aeaedc4142586c6454790fff7a4e61af30e",
"0bc7e2ff2af89d45812349f03973406f27a4475c44e71589c4121a9cae9cf37e",
"53738bebafb5a06ce8140b83ef922a31a05521c07c42cb09fbcf6619bf959697",
"809f6e691647916082cde741c82df020254de10148b4b712744f1db345bc2694",
"82238f89893476756a48eaa42cffb4fcf07c8cf4cdbe12a1c43145d2b67aac07",
"ee995fdc7633e803741fffcad712a48aeafef16e5a91aba899e4295bcfa3b577",
"b65b0489ecfa62b9725b7a4c4150caf0f01350de9cfd613c90c60d0fa4875ff2",
"7988a77872e593e831989c6ca5e5e6861b63e1c2a42030d684b51fb88ab73004",
"914ea37de5dc3b2f9035cdb7fb80e6e692a0a5934756beb6d8e2ea8eee7a3895",
"d9c28dc8bc385283650fb2aeb1efe10caf848c39de37a78dbe6f47b8f3bd8b51",
"49a2581f6ebc753d70dc30d3b093882153fef2d0825252354e5beb1b35eb90aa",
"7791d37475e1e15bb9b817b180811d784963d2398c5e736a851af2ef8e622e77",
"3957f179aa7676eadd2c312cd6096f84b7a0424bc99f05c8997bac9fed057ae5",
"9d954ab5224ffd2e0301ff9b33ef834d019596a6c3f56fb634ccc9779b9c694f",
"e6235eda52b721bcc3b997bc8da554f1998b5c7ff43cb86c2d7f1915150c4ded",
"c0684e197ace1cb57ab553203b16fbccce5c993b876b90499e96d94ce308b956",
"70cb7be7ca2d01bb41c09c06fefc04e8d6dbfcdbd9b8df4bd38caa3c7fbb6001",
"96235ac39c397550e28b63f63a4bebf549215c5e72cc78488efeef131b0cdcf8",
"f3bc2994745fcbbc792d905ce1858978814bcec9a5a0a3eea4913bb87939378e",
"caf6345a1bc6013c428933fcf151ee366a11ee41070c3de2a3e5036a65145194",
"ce92dd8170fc721b8bb69c261cd868b82a2d1ccc556bef3999128a3c20bd7c5a",
"45e73df58de1b26bdc1b842b5a951da84381708cd15b40eab87ad44641777c6f",
"1a57c8e01d94f7455719c85c662f76580b9f4f530aabbecee9c5abe00fd7def4",
"c92b4679c9376df3e41d79131f42961fddcdf99afd2c476168daf9657f769373",
"2a2893a114df2630e4b32c47bd60612b4f3d9b04891e944af55fd2767d260314",
"98dfd86f3bb1b56d0e5b3d0a9b3227642b09ee0a2ae78f19eb504edd1bd91ba1",
"2bca879ad4553c1406e38ab072cda33740cf1681f18e7cf548ce040528fa5d05",
"5c3039135e50309be3292559fc0f0d6a5de7ab2803c83f206c8cfcc06683b54e",
"7b46b23f8ca2c45baf6124165030a1ee5fc27f1ae3d1226defb2574177cf728f",
"b37b504ccbcc5ae9f8b787fcc8da194fdda3a25b94fbf217444c13fa4a0863d5",
"36d5d669f4afaf603a54902269087a0f65f89962f87ba03be56b552bf04ce81f",
"f57f94affbe464d876235351bd20660ad5896e5f5bd38978d64346564a089754",
"4637eacec37dc577f7d0c780ce46a57de6da9b5173f4d0626963af480b95213b",
"e22295a0995837f730cf99e9465b0e5c41c1f4a99456f6b27d26d66b8ef2c4bf",
"33d01fca1bb71c53d131b757afe6d97342006694ae752c17747a461717f42f8d",
"ed239b46bcf7f8a66b92c15135488e1249f668625c6fd0a08a0f49c733806de0",
"324c9a8fbc527d9e9357595b1b3509847847f340cd557b9305e78fa2ba963be4",
"2fc5f4089b8b6375a41bb70257be3281cdd32778db05663c55f96cbeb976ef1c",
"691fc9f8e0e0fd9c0a0f42f17f33ea83c3462e35d777dd54734108bf273b5a4f",
"e21e3a565655f1f58ebdb421c94110e19a55030777dbbe455e350868020a574a",
"2c3e5c5791cb68bb2177332f5b79c8f7d1cf4a577a903acf225a0d11e45aa5c5",
"5707100bd5a978ef7fe1def6ba895ad388466a4db13679a899c93bcb802d3a7f",
"fb537a7e26384ea9867ad9ac845067553c1461f5c75a5bd50df1afe40b063b1c",
"afea4fc11996d2552a83a4b7bec586c9dbf3346cf2b3ee7a862b8f6ccf163522",
"67a83eb66b438519cd92e6962566f3d1277395d2edfcecdb06565e33b9b4200e",
"a763a731e9fd04d5ef02aef4e7cdc1726a34c7a048cd78c45ddf9f05c52773be",
"c992b26e5d9f56c3f1615fe30fd5d4a70d639e192583e5792909baad8695e90f",
"5f63a2abf7fde874a260f469f56f7392c715f43581fa0e0ad99522dde7c047da",
"2d92ebb998b264b0c7fe1d9dc94c8f3ac171f31a38867eefd8687216342ad4ac",
"36758fd2cddfa3f6c1658a649508727ede3db00c36b5a619260212b50b3e5da7",
"19237f8184a40216542e1f326527f7e512ada4ff9923380f9a7a7e73a0c4aba1",
"3f2d551638a07d4c6b03265f131adae2639d1600a9f31a337d5561bc22c41af6",
"212a3841885d5890d53c698bfc2ee6114c13ed4636483f65bf9f43e2a23c2dc7",
"30c6c4fede61dd964588586338cacee4e0ef8977b556b4fc104fcb6120d45d3e",
"413981cdcd8428b9e76a34010c95f810ed5f39ee66edfcda92ab0ad94f030871",
"c70a24bad26cd871d82aa4563199ce82ef8d00cebc48a1cd698ee1933ac8b6a1",
"d228077b8f08942f4f5c445f5431f6a388d8dec122471f8c24a56ac158c90742",
"6d25f50ee65fc7f46a86e1742f30afc9b9536b65762f75d9bfd1f9ca30df1d75",
"2a7ac6f4b98849eb4d6962c424e91537967350ccb60c5cad40400d46fb0dc3d6",
"002721d6c430ad953c9125dac7b4235a3f5edf80309b23fe9e197d0ef12ab0e2",
"5464573c76aa26e98ba45180d7783bf83a1ec7939c8fd8a210d635225ea1ef42",
"18395b65b1a46358ec085bafcc873706fb482866f54e02e042522ca09ff0452b",
"f4ff0049dc8e5a4f06c6274a1bcdbf8b5f8b841f921a264ea5bff329378fd620",
"19bdc09f26645d82ea05cd1fa0ffaa68885c66530b3f0eb05caa55b88aee4efa",
"6e749013aca97a5ef3b156da4dc621bfefa7e0186e5e4780c31332f9c62ac7f7",
"83800ecc6922e2a6ec0c34c1736a12f2dfcd94eb9f27c6948a5b28d961bc4ae9",
"86b6fe2935f0206083c952c07ea38c25388955eb8a806c10b69d3e52d6ec26e5",
"c7db870f8b09b9498d39b22d828b60a806f7a1de694c43d6bd29f3d76a11677d",
"b0a5809735c83af8e2a3eeb93da682bce95a699392c0c4abc8d39188563e381f",
"63af21f2f1f82d3120e4d8d98e7fda2d9f39d102c57d9c4111d07079a9ffcd47",
"ad654b3ed5a11b9a2a52fbb8dda47e91a72e4b7bac3a4ad75c074786f14c046f",
"6d9c4a44bf22648c07881e2e92a81ffe002c0177d9c7892416ce01ed1f693872",
"16f279dbb7b3f6c3d4f190b36fe2283efd5fe4669a8f70d209eeed96bf55907c",
"f79a83867614dc4d2e47353f53cb5a833582446329dbe4d5e8df941b0926dcb5",
"0cebcc9ea3729487c1b20adb8eafc6fb1398710ff6179a7fdafb1985e5f4a8e8",
"5a53e473fda88a9fd818defdc2c8e68bcea0c5aeded0c1910d6004b0e77ace89",
"f97965894c4a296fca42905242a27228e5a9a0150d31a55e65d637dcb9e60ac1",
"ec72e9e2fe2f4ab9db10b7075012c9e7cd2a4ec02b4c3b76df17f6eb27348ca2",
"a4e92900f9f5490b66e21fb66c0ae094d106eed5366a85418a86a8a3f8f87a28",
"225f9b50f64a97b9eadb625662b1a3e1b400eb86cee50fec8c62260027b4d390",
"7cd4971b0e5453d210c097904480403bd53c689c19d52e4c6a37925d14e4272d",
"3edaf61be8b6cfa06e1d42d7abd2df32033bf63cd14df8bb3ce337e62a822f16",
"89fd8d0e59d8d757b7b8a2c3a2b826e799c028df166b6897a42f08f2284d3bdd",
"0aa2fcdd4e83a4395cb5f514e1ef61ad4bb517d7c60f81bea030d5191c3c79b7",
"80a275ddf6caa4bef4039860d4c5b0c4bd1009953c19ec2c63294ad2c5c56d1d",
"e85d450859d702a0473363070a6e56d5021ebd1111232f2af28a60963acdac16",
"54d48012bd8af661baae940fb6f0d10348137cbb13c650626f42051ede55ec8f",
"bdb3a9bed24420afc6eb80930694b4afe0992318e49428156acdba5762c69e16",
"cd277985e4b4c30a1999e5bf7bf7d1cc903640a04678a93efaac1f9bb5482dea",
"d1319c6862feb76be11c089c753f62873519ec29a0c83b186efe57f50c4e342b",
"1662d8e6db309700071a801a3d066ce97f942abce241c8085f3c023258927eb9",
"e179e018705eb4a49ffa4e5271ddaa4fe1273029b521aea7a69f8f3b764ae017",
"0e7347cdb154f6d96fc8f9eb8991d4149fbb21aa3270c21fa5df61ca140a4fe1",
"34f182c2f44fab5ac9403543493be5006814b2379e0e6b7603d9e0fe76390367",
"5d710a970ba007bffbecdf12d1c920fbda1f57023719d506825e0895a2affc49",
"b99e0f318386f90df96c1d1cd4dc5bbe4726410f327ecc108108ad898e450eb5",
"7eb9ae1f66a6bdc4482175d031bd6af270fe4ff8ed1138200d6eb49e13c0b8e8",
"c508f259179f67bb6e05f2b9c5c5ea751f3a013eb925c6bfcc2a2624b962e059",
"f3d0dab6f1d30ce74c97b89f551ce0820bebad2bc1cbf4a449b11d5408cbc140",
"c116f6b0a0852a30c8a913f9e0f1680ff1be06165e19eac4d00c4e426ca9b6b3",
"25df122cffe53ab88ecb94abae69e0a1d4323eadb7537c5e4894c0e082d58529",
"a30d97485d4162e910b12effc549374221217c216b0a9487e5a07ff1fca835b8",
"5dffc63818983f6a7db2ab65d621819be9f9edac58df38571887cba22aaaf1cf",
"f042fb4eb01dde4b285f2df328f191d20621b66d7630d7691e7c69d9dcc04aaa",
"d4190e2bf10aa9800a1c2395c0c4a38737c21f8bc42dffb23addf762ff309aa6",
"4745eb0e771c9f2144ffd4abf39e63cf6d0ebe122df5f32ae399cc15fe3f7011",
"806c6fabb4059c51865f723ae619e0c55718f973680ce7eb84c49b935f59ff02",
"3352add492d3a7fa9ee046040a3f7795ec375af875c87edfdb0bc876ba14fb3b",
"27dacac03594cae3db57550410bd0f8d166863992895548f6ab782a8332462c6",
"1708396a0792c2a33b8174dd950c4a59ff06e969db873eaf2a7d82453e233b99",
"5680174e172ddbe6943cede98f8d854dabb66ba65e3349889cd6262cdf462a80",
"4960f0a4c46286d62e5bae021da9236ed0258f6c4c779e1797a9e66a47803f0a",
"06af18499315d7dd1c8d16533f0e13465d606fea2946115f23735f3fe2f6d882",
"73b0ee02de1c3c8a9b2bb8a9c48705c94df76c9c2d68a222c8493848c75327ad",
"42044a69f91d56cf8b993166dc1c724ec7d311eff01c8255987cf563d58fa5a2",
"187382209cf9b45c1df5655801a651463854a6495a7aa303887d65ad0e5b915f",
"3e44b609a8f97ea0b412abf88d7748edfa62b7ceaa174bae008e508b1b133e7e",
"d7b1c0b1bb02a6411eeb888ae26bef44c20364113bcfc1a4a3410396cb52b950",
"5534bafcac199f54a48fa713c6f7ce0568abb11b341e38b4a968bddbffffa507",
"84044786d9f286e241174796073fa47ce25c154616ba27bcca69fee1482942e1",
"45eb4756d3895fffeb913bfe149746f56e184f4c336dad29f6f81fc2a3c0168f",
"b583374fc47629a3f17476f4c9c751e851b7c4881eda50e4bead35afb77808b5",
"4a99c32e81aa36e824bc4be78495458020b1faa47d558e7263f2c0477a16e6d8",
"888b7d3a32f4566f21407c251b753b3890604001db91f88d45773bd8a53b2541",
"53eb65e5b425e7acd56ee6234ebf3d40d8fc45a3dab9968ef4273cee307c38a9",
"4bec2659f865dfae69862e128e710680f6114866b3478de257aa5ac596a66555",
"543cbc31d271c10cabc9417a4d4b6dce2dac73c20ff29bfffbbe55584e5329a1",
"4970e6469f1ace57971103d1cb2324b595ff12e34504ef8249971c76296bf578",
"010810a21205384741812fe98489cd7369d9f6fd9e6818b11dea07c78a9073b1",
"6114e32fefd54c1c2352ddf9327727bb6a34a9d8b3b7d01ce59c6e0d32700c7f",
"ecc7248b7093678e7e0ae58333dcef0eaa18e3af261b2d1722d29acacce2b8f5",
"0dc74b6f19b2bbf2f0e7f511440d4dbbc67952050bd1d962516b683ff6f9ec9b",
"fb8447ff1d5200c3acc768992705d2108c37d61b0451c7474304803e76cc09e2",
"f7f222b44c49d2d927fc2e345d64e2f0ed5f9a602758fc5f5ccc73d3b087f8bc",
"295fcc7e7fcb601b3e79c1fe403f920b622bde0f4975419c3641c4d432de8f50",
"e016f042fea1d93fcd4b2326b3ef6051e293b4abd066b3fa5c430ee7773e443c",
"7c8347faa1ad96169f5650a1d138cb10bfb60dcf861d5e2dfce6a986997d2dab",
"060928467611f28b99eaf284bc6c09d6760904ab5a6f9e072a44915a646e3ec8",
"ba582c64b17221c46d27aaf6ce1e2818562639b321666c9513c1e85727a623e6",
"e73793b5e2f33f60887c6ab428339d40d21fcf75530640977215a18db34fd7b4",
"0ea32380009a639b705fda94d93ff032d88c3126503c0d153bd0f104b039bf60",
"13bc02f7f971910299b8c61d1a16782726f22f63b31b2c0c34faece873f4418e",
"a99b3ff6413262f46cf9a44c3fd5d0424109a6373e2580fe97938c3dc04e60df",
"72b149e7ff672ec6b23352493cbcac166062282911e46d2b7ae5228d5814b720",
"58d67077a2b7c836dbc19457eef1b1e1f734370a800388bdfb1012840fb7a240",
"32beefd48538abe6eed6ae137199e03e05229d124628205cce7deb53f16f8f16",
"3e466fb18e2a437292f00acf9f6e662fdc6e0b7cb9c0606e613f81dea3393e39",
"9e537b504916eb6e9838f13eccf0c753869351778201c0813ee35cc19205409c",
"404c0560dbcd46d1aa9cd76246654bd01f62ecafd40ad2b364c426f849941c5e",
"89e5cbab667b81f08eeee6203be0af9cbe9dc0655af3272b0cb3fa722116c200",
"2fac933a1b980ba75339703bd02f055199d057355a8dbe94eda724b79c2ac534",
"c0200b5442f41779316e0e250b7bd011e12551b2babc96c9228f3187fbd17eb3",
"f3269d2e80bfa7e80397a8d32815f8fb8fc0f8dc01dd1c75cd57028a23e5d462",
"d6be8612904259aa6ff43ff30a2bbeba9d58e02f479f56480a8affc2cc9bee64",
"a67a26fdd90d624fff7e501a2a946681134e32e3afe3094a0c3776229e7db123",
"43234eef33f6bad45358374d23ded2731a35c12f472cce58d05e6d9ee56c9535",
"f0217ee0507b13f56f8417d0c92e3c76026da461c22dbb7fdb653442dcf65ef5",
"d9572135cdc5ba7afbf9871de3ffb68a1ca933e71b80e8766e678bde59ad2b52",
"9d32d8b859188827a48fbbc7660900fa51bdb1bbf3dca2ecac1392a1cbbf4757",
"daedaf79fde7f4e49a736f5b81f8b6f505884a073c5aad83997b93bb9685ee52",
"fe7b3ac50841778d1283fd836996b1865f45392d53b95f3bef90ff657a49c498",
"b89b62e4130fe4d40232744fb0182d477047acd40d32bcd15fb6181ddc890a6a",
"0ae8786dcd5bffb824b81fa038b10c9127b811664e0d9655d537d95377d6d93c",
"8608661859b838a7e8ec16e15db1114aa9db6b141877851e09439c591b46d830",
"f5351c6f978f600be1a71c95abb638bdda6a7f6587e3f66d53bda682c7aa631f",
"b6bcd591af74caa9970d39e0747bf20b56590878cc5b76da411525fd34b71cab",
"bff91200c32ad862bfee68ac1fac4b85a5e6dbba4fd00a7d09e217cd226ce777",
"40e5ebfabd309ba228262431317a2ffa268074cdf83556682d5f5e8c77660c5f",
"c379dedb960b327f684e794ec212b11fd1eb8f20a6847676554be85aa4527dd2",
"e405b5be582345aec0595f1a8a4aac6f938b539426fc7910d1271f3e2d1ba81d",
"e27a84e97deb5450a38bffa685d0461dd90e2fc9c42aa1261da9d3b9fc8fa0b0",
"c8b7e2506c4a067bacda36ed1bba81327b18a08df3fd373be25690754b9d8439",
"5b8d011d0493a5217b74d086f4b8db0bb38cb357c76b1d59441af36806ead1f5",
"4ad67654188a9c920bf0bfe25d22c433035d876e28f79a7c09c5649ae7b970eb",
"2a0abcd054b303b2077ba72f2681a7832712b526b145b62c601741efecb360db",
"bff88f3f33650251f8b9240b1bd94621460baf5d7b224030ff9619a6c708c56a",
"d8846d0b025e2eb7eb528eabb478902ad5990d507837cff5c90b1113addf4c75",
"e57728788dee9191e55c5588236680bec3f0d2cb8791da18064a6cb341b5b7a5",
"f291bfd6644103b66aaa5208ecfb536a28d6209462f98493847ba6454896a369",
"8b0a1b5d290d1069f771d50369e662c5f3c777c2ec3efee722d1a0ea58c6d9f8",
"cdc255d80343d5967d7418ad4edb8dc99ac7138c1621bb8beb0869dafce44cb3",
"cf363923e12340b2e95d7397df7775e3d6d98539001d8262048c67539be6a7c4",
"aa8e17f4657e2aa01025d8c99112d7002fdb1abb086cecb23d428081c87de6dc",
"59faa9c953bfd7f7d5bbfd363c25ed4089fbcce464b2958c9aedcd5729d4883b",
"fd0e1bdf4b5130bfaff244ebd4654e4e0df288abf7673df010bb909286f93ce2",
"f354946364f1449f4cb93847742ad2c2ec82163ccd7fb4e0d5687fccf1a2a018",
"8be151375abca57a5df2d52428068eff6f82dad14d5bfd08a699f8e747ddcf99",
"14a1cb09f11e6401ca5b119808a3176f893db83a0c23fdf9c393ac78139ba429",
"1043a8492b8a8b6a8b9355669a29fc3f2e1e01df59741458bfd3014420df60c8",
"338caae1b0d36e70fb8bbfb3e230a25fc9eab8a1c5b727e1313d61174c878411",
"8e1509bd3f536a9e263d5bbd5cb5d892aa0a860c104f0ac7af74493b9d164bd6",
"de5f3b69cd11a453b41b1595ee919dc2175ef867541c66571e6e71abba2661e4",
"653934f935d080105495891b1889aaf0403223077af687feab1570d03cc08d29",
"0cfc8f472eb4c7e30b17ecf91ba335ac1b479a01154e442d33fd0ef3c0e5dc4d",
"fbc10b32be63288c096a64a70c75dfc76f162707be9f3b09675eeb08d98a4f52",
"d76bf859e647ec2d77a7e5b5f726e8eeef59c6ab7fc1bb01c981b5cde26f3eb3",
"64fe376e3defceb8149411cc4cdffdf3dac15aedb2ae45263a0b94877c8b9ac4",
"3faacaf41e61750af0ac6df1b5a79927dba509d293a7fa2fa9e76bd3a574fd3c",
"a7a80a4cd46db9010cfe1fa8859d658d7b4534832e7b44fddee51c53d6be6408",
"c0268812c0e6cad694d5632f819b5623383fbc3e551122cad33b82536f733791",
"a5a2a39a433131759be0f1f6339c4730de3d401c54c71813066def40e6cfb046",
"61f4ea199859377dd681fd26610068f87e99081866cbf9aeaaaa1163e68fd950",
"65e2e5e77b37be178505f7f40de4e64fd4e86acb9c6236ffec62392e8184692f",
"bc82892fc9c6dc5d7bbf16ba4b2bea2cb9666815bf3f680f72be395384a299e7",
"db5139acccf8dc1294eeb56fae06397f17a040e093d307a9e7b0d62ad6b42ae2",
"43e63ea9672a65432e1b1c21baac7741c9a5f1d6c4e60ae0b4618587415c5a9f",
"75e8ad0712bf9f279d89b252e7fc17ee0add1587df3f355568999fda4dfb0a2a",
"83491196e6dfdec6dc2d09e12380cf55fca8acd4ed8af12012e41f3ac2270978",
"b31d6592a4bedfc5e5d93565a4824f2917326566070ea981e45bdaadaf3022ba",
"ad3b86deac6998141aaaf372f299bc1c39e8bbee4807cb2b6cab7cff32749815",
"e2ea5f557fea88d002756c080dff0350e2ae9c15dbbd423a2be45d660107813b",
"7750f2575cf347fc1b24fdd5b149eba76a438109f7ae02a515e2451179b2c98e",
"c34cafe9369b18ed88c2936cd7cfaa2dad9ff105a9c3a53e49da5e7ad4ae4b4d",
"c7542b4b36dab508ea0de2e1957d451160fb3616c4c81ab967d2aaa97cc0d8c8",
"9da5cd367d3dc450b2c76dfa1ea0ad1e52db56eb7426fa031f2d08d919eb39d6",
"340a3d854262aaf7a8a6bf005c21ae7ef62d58d052c1d108e7e09e708ac3f0d1",
"dc2baad94c21cf7e37a4208a6dddd74bcc84aec852eb308a39ce9f81f6fb883c",
"d21cb6a6f34d9a66c167c4939619a8823be213ceac2bf401721495628d2ea3ff",
"55f3144838496089eb2af67adccd4b27340155cf2b1cc885427f4c7d4e7a8666",
"86ac6e18b9931bd435b38f96d97aed092e1fa8be47089f00bc44b6f7897e64ff",
"b4044a883dfb2eb9f4baa42d259f87d5ab39821470f977548a435cc65897a162",
"d75f0fca387134162a37b5037c5006c3e25c991fd5c0d3eecaed3e75df90b30a",
"4ef8fd941ecc624d1f13ec8c0004744cf907bf91f0a25ea0986294b81d5e45ea",
"015e5322f9f2153091b70b0341912ea37a0da3ed20cfe9b8356c1ce882c00900",
"65f0ffa646fdd7a98f1dde849611f19b2f443703a11ff5a61568b0ba7f85b0ef",
"d9515617ba3fddf4595e395e0e033e9eae484810a478be85bb0eb3851000459b",
"e3858e031fe47a5edc3ec572173de5ea77e9ed292968af2c6ff2fbd98e5d7996",
"4fcaaf279411aa84d92f548b1dfc05458af2afe9ff577221e4b1d82a2e37368b",
"269b84393f62de52b612e2f9922a67d06e523e27d4d2fe6d3aa68caed7a2a190",
"4d179db7af1ec1b6094dd55ce21d26a54e395f23cc3428c0de6ef171d6b015ea",
"1a508533186b12799e418ae46978c8bb8bc88fbd8a478fbea38b86987d197ce1",
"ca4e5990f8a59ddaa61ea319c9ecba88cf321558b8735fc262aaa172185801b1",
"0d48ac9f64fd82bf2e95ffb1eb9f1f73a8dc778417672fbdff374e5093a35f23",
"c2b88c4f59cea3fd60369fc386ac89d22f6998a69b24f4c8ab7fee63247851a9",
"75fa241c04b786f0f2670e0b1e45134aa76445efb26280cf6dfd926f0e77446a",
"b6b80a7ed9aa4d50ec56812cd5a04fa290591976b0adce14e6657815764d1645",
"c29d8b54a265d59ba2e8eb1bed27450e411ee34ccfda853d3a83c1da2fb75b3c",
"180681a90fddc13a6f216b87128055a0947736248d967a5170149a50ec8020f8",
"f65b08dc2c498a0f01adf70e45c5ba21205e259186f928305961718fd086e08b",
"43e8f556219e8e6a7508a2c5ae19d6de0cda7b9f6e893bc19bb68e361c37c786",
"367709af13a857bd2b97701b27c88a7c430a0e791a76c72896b575e017d8d9d6",
"c9207c31bf4517e18513602801a0780242fdb91c1ef85924c2ad4ded7bbf1ada",
"9e48f7bd1d77dc7269d121584eb914303aacf25a336d42914300659e0f67871a",
"8a2b8b728756feef55e9c9bacc138eacf609589afb4422ba2ec2bf9aaaa6b0fb",
"5440c68bcfe6a804c5865c3bbf033033bcabe29e20dbd9f36f5968e2eb0bef02",
"432af6a45d6f2a44d5d6de8c82c4b43ebfc8b289b08866d0c4b4dbfe7337b31f",
"4fb77ac98b549ebda2ba41cf0ee99b55c23386dde4cb505ccc497c4337b243be",
"3f1af916ee3982bb79c31921da5c90a315c9719ef93d87be323bdfb13c6e2770",
"4268889b9776502d948382bc1c9e065793104a2ed0e8aa75b2153b62b4ccc097",
"e14719c99770cf507552d3d64eb822c8c7a6c4d12c769d6cecb6e6e05db85e47",
"70adecdd90fccabd0f39e9d41dc19c6ba9afd11ddb7f09c6ca9c3e568b9e7194",
"c9a94d170bbcb06d9170badf89f2f3533daf8e15b633dbe7ea1d02c62fd2d847",
"538c3cff924df23105e51cb100c844f356d0d05d06e3aacb7c30f98c91292f72",
"bee2c32fb72004ceb24d207bd890ba8fb4126848d2a7bb02ba580c2669f7d27d",
"98db2db86a3da56f16411bf6c2e27f2755afd38673bccc15af8991fca283cd8b",
"fd8f89cfc412008ec0752fabaec3ac72d6c89ad81286980e8138edf6ff4cd992",
"009704c84f0954d45036969fd15c7293048156ff97a76d9c72a08248a4dcd725",
"593b8d1e74c299da61950db52fd3b08f44d6cf972ec05a5c5914da9f230cacc5",
"e8a6d9cff900567aef290b62a57d8d5528b7468adbe2ee0bcef8ac47e2dc1d7c",
"9fbba3e66b12c7c926b88afb5b4a9eb03d1afaac94f673d45639ce9d4dd51416",
"b7f9c83320d1b04ecb9b4f714da462b7bb4e4ab7cf3625a5f0bb497f5405a038",
"4da28a828ab79336ff2e766d3f32e3a5ad11af8203c4428d97ce5c0054aaeca6",
"d1d9ee683589c16d6d043f383ec2023953c482f9c32704fe1a461ba17da05ea2",
"0706b6349613201f5bbb9c6125c48306ff53d4688f64dd994405abad1872d450",
"b22580d4aeda8ed6d73c59bf74efd26c3edbdeb0865c0c4b6ca61db39fc6fcdd",
"978e4abd23ead67962bb223e372c8873f283f2d6bc3b0b0ef6a21fdedbf48420",
"d37e209428acd60797e1e77636bdda5204c56af262d487469b6eb069dc5ba0d9",
"44622d438823091e0823695e5c08b633b3f0c46af0286989798e27530a20273a",
"8902b51c808d5143cf6e368faa11e4e86ff0d373cef041553662da373376ff59",
"8250faa8be69d0ccbc2df66b1046d1ccd6750503855943542b6610a9a6e9cfc2",
"e75d7f1982478da0379f975f964410f4e5645f954ace65f0ba0eeb1ba7d7b190",
"5836da561d17e30faac4342fc555878d144b1108f27112af7f425aaf90f42efb",
"b0d06739420bc6d96ccbae8336bb9b6a28adcac61f1f5712915ef42456222332",
"c8839deeb39bf4e9743d617cf5efc29e9a59f39d681128baa4e900203acab6bc",
"9fca90ccfc4d102cb60b2a6d992c9086a71b1f742dd805cb40b945e598bd255f",
"b08651ed30172874bdb63711d32ef549b43861bae4cee530da74b7874d0deffb",
"f59d3938a18249d47eae4be568d3098688df1c5eee393a913203af87f92ab871",
"68b30e55a656422b4f7757e887a7356781f17ec91acd25d2f062bb9012741423",
"ba79b09ddea8bbdbe7723a906c367b4a51cd8aa47fbe2836c169ec28b4e51af4",
"51b2803fc4d01eb5e9f011c74c5e6b294327f44052e9e56fd0b75475b3f2167b",
"2a40ad807c8ec22752fd4886570008b62762d208a5ea24140813808b64792c48",
"f2abe05e84099e996c1f9a2be789b77259322c5b28a1a24ec418038e77a7c252",
"e39996b22b171c30c0d9d7f3f9b89c8cdde606af69dbf6936ab50d4a8540a43c",
"6782c67e3849c9ce43967ee303d29b12545af84fea12c5cc4cf1f973214eb2d1",
"3477e62c947ab134c3242522425c234318e22998b4f6d7b08422427e36d01004",
"c2020358b71b1f043bff47e117027bc8112d4dd0d65131063e667da9e0974357",
"5e3c95247d735f46b45940288d0e8c0016ee553c4939aa4192ba7e52cbe63b63",
"f3ef5179680400a2a83fa5b01d823bc3906d68ffd29ef18923262472afb8c685",
"5a2f1f9be05ce5402fc0728614f98e6c5d8a30a7008fd7114d2e32f128b99468",
"80489be62cf13a2efe0f72ae08422eb8b9a033bb24783bb075e5a030b12f4d12",
"01aa376514be84131de256c9fd1f3cfa05edd4408a332e699c2f0512e8653203",
"6a59eb72f291d9209aa9ee2580a977707b28e3714d04859352826b7003759f1a",
"1ed1699d9c8af25571a1280b6f5251cf690d0005bbc222829ed1b5c8368fb7d0",
"2b8966e5eafc875e7df9b828674d7adfca2225a5c5458efe5d3490932c0011be",
"d0f30db6d5b92d763aa39c910bfd007d8ce08f58cabdfdb67e38b12478851a81",
"2b5370d6abbb3e0c0cf3d9187e5173d7784622b770dfba6c33b8d672e22e12c9",
"7a874cc8981afc43943b02be3428c2150ca2d94dc2735904be475872fd48bf4b",
"ab8bc740762787a90716c3f1fee072e57031a1525d52ce20214a984e793307b1",
"40983e94cc324c141ba33a7cc5682f3f187d832dd665a2503c4101ce3710b2d1",
"ea73153725b2ef43b2e10a05b7426aa8e241284b1702214e8dd9cd04b38df68d",
"4ab724b8efa9a325df30695daea6894d5da08aaef739f20e716619f4e595885e",
"cceb8bbf3b3bbef90da4b219fe547ad6a3edd9dcd2ae48066f2511a8769e286b",
"b8c442596d32a409e8fa7b4401d52cc8cd2e82ac216d374933dd9013535b443b",
"0a7d2aaff8434564372ad339e2ed316650f490f9932afbc9cfb5f9726edd227d",
"117e018ab57319440ca476a5799a3eb87eb7738a793fde1b95c34d32cbeb4522",
"7c84152e37659e4be0e0806e11fa7ab154e5dde6bba50409c8c475f480016120",
"4408ece10877a6ac3f4320941617b72c27fe122bf0a0b94932bec6f7f6c5953f",
"5b425b6d0c9bdb4fe93fdcb1314b2ecf3cafb77cadea5a3fbc1a377c04c77aa3",
"2352dff4400aeaefaaaa61cf37512d2076e3f5bea92d2ad51aa99f630ef25a67",
"08c9db753634d99a25264104c5b816ebc15b95e0d2f84855d32e52aa90aa5aa7",
"91d5571d7b2e0566426cef2498a5690d32e30268c0a3fc17d81e4d3acdaf65f4",
"71b408acc816438a0acf055260a433b5b0fca4a71e627e54ed7dc96079846c44",
"4c925a3c7a5c74d7ddc2095fd3c303fe9af708cc54ec1992f89719a45dd2e98e",
"60f56a735c8f2f31efd7580c90234e9fc622efcae366849c63a796bf80006a12",
"43961c4f8130c54f32b45f9ee39fe88faab957a734501e7b49e7d7ac8f81ba91",
"5a503cee0a815b1fcc4ee6000b8d88e7fa176f7fff7ebf9abe82379a9b87037c",
"b19e6f323d3ce96402d8ced832944a02728d9df0674a9a7bd8e18dc8896de94c",
"a743c955a7b559a34cd8907b9eb7a40d86f8f15a58e90b91c9fd87414a91b3ef",
"b40cb00eaa805c0d27e86cc289e34dd354d820453382954ed2ac24b27d38c2d4",
"e6016c78523ce714a360f77ad95b39bb8a724277430e6d2ea5a2130334011727",
"e8b448a80c197809e559b30fbff6a7a99d1bae7409ec00c766a129ab70e47f5f",
"4b42f9bb88185504e200703c9fa8dfbaf850978a60827cfe7688c434c502de0f",
"d48a1aaa1f36222f4acbaaa8218e249d5774acf8abea087c9e2ee9e21dfb2ab1",
"cd11b4f441f834863a99988fbecdf8b19be665edfd19ad4db62e9d290a98bd02",
"2d6152c003c48f8f6a1c2693dbb5cc5528e7e164a16beb798c772dc85bf2ee21",
"0f9af43eaaeadb7118498e562e45be1ee1e9b7f3787cbec3aeadf671a2c3138b",
"e87a2dab8e4945b8ad5fb7866efc8dc76a990638822542050506d1d0ce78fcb9",
"190a2cb2ea8d06d989d23ff075bcf61b236841a27975f89bdc085cff823e55b5",
"9b09d9ad2f3a069a4c9b33e77a833fdd6605a2095e8062f8b79a5fe197dda466",
"06dd4f3da3273bd8fe869a976006745235347ab53612247d3e0428fe152787a6",
"8dd9a7dcd863f7a8fe98ed2f452615a74560ab7ab964ff161834a6a6d5b21b4e",
"f68bdbccd9955c40848cd3acd5133f991becbcfbcf167e5d2018633229d1c0ee",
"d1990ee38345d528f0115a99aad45cf41d3a579ee1be601bee3820f181819f4a",
"b09339818aa6b2bd5bf955109969d4ed43830a672c479cf34bca1661e31eacf1",
"c5dc68711d6a27092ee6db8a779fb1972d769a4d571b759e6bca257493b1031e",
"6f7e4d57051949b2abee3b329b299d5a6f555d06cdd83811fdc7d47531ff7179",
"45862ace8f36c0a3a6d4326817f0f80f3041622e85e055e2eb89dbd20d0df324",
"b57841327c49f6c475534d0cd18ff578958790ec3c819fa5b97d8971252138e6",
"e83615f0779683ae32d0f019b20cbf2da935403f509bbb9d2856dc6201b613bb",
"be524d2863d41baa171561328c9435163eca92d6e085ebbc29a4e1e3cc6753ca",
"9dd3c020ae3e8be0f6fcc97e6fb0e8c76ce9694dd5ca8a2e8a122862f552a421",
"a7e5ca5d0be1d24c69f4992a3c1a8f6acee7929afb2538045cf737a5da62898b",
"0cdda68b16cf1e43b41e2d2eedd6547972eeb5491930f9057a3c07743219c1db",
"5c83bb522e9a09d6c81af19b7802ea30ad22484b2ef0c609ade92089e7cc7248",
"078a6ea5a4b2be65c7c423f7ad5e4ad909248729b08264b8f880ac5d90f009f3",
"47a73b39d4c6c631d148b9cc31dd43311d20d91592a9ed38d87579491cd9d855",
"7c625f9d16a27bd30064682fc896a15c4b504819233610fc4a88cccd271059a4",
"5f4c8d2cc5c67a0c393493474e74f770f8c09751cf4d712f0c906d9d3903fcc0",
"60a628f0347932c8679436a3990fe3dcf4d02fb9c24fe4fa9754717c176591e0",
"2fb12765c5e1eb877c55f574c7dc61a4123ebf7c7e72cec7d7e83420fa578853",
"2ef3b7fb03472c1f5a850b40e9b35d9a35d87f05292c1d0d43e863d7e7ec6b4d",
"16c54fff31b4da393130f6eb18111392a96e85421fcd1e928e17ae6359172221",
"56ba9c544d0ca5de806803a36a1a19f53ba914f286d92bce307f91eca1bf5652",
"e8df51a49ab47130db5332e1dd3f1ddafcc2ce80150ae3c37eb100f5627b6bf7",
"3df4f7f14f87f1ea6df31b9b8269cbdcac2d8590a89a2753d7bb11fb8ec576ce",
"ed2560a20088fa40572837ba321394fb3665cc60c15b19a2fd07333101636953",
"a5ecff5434cd0aaa835073066abb2b9f9e493dc4cb7b26983f93c94016c09297",
"af3ef059dd49490d483b8b9a99b245695483aaedbbab25bd1a54852a26b28802",
"39d2d8d4da53e0c373a1e39b4847821317f10d9fff8b7ac598b59b7e79e2be6f",
"b1b6815684cc275278a6a3b0a7de9d0c7d4216f8f1b8c8f1d075be64f70b79f4",
"fb2abc840ce8866537feb12531f420dc89ca9de12b4e192e1ef7cbe765cc4816",
"c7b6c8d3d4ec9457b4caf29f6a6198f893c51263d73d0b12e8bcf5630fea1e7f",
"aa5ae0d35bbba924165abccb826604c80f6ad55781c49e6016bd8207196f66bf",
"650d0eedab56b6492743e7c5692651e8aad37d1a9939963141a67482a686e9c3",
"22d0b3451a44adb8ef87a116097e3ac46b5f8345ebf0e5dcec960d2d55a72d93",
"e3110bee29e6162f431aa68c170d622f819bc4e289f6c3e1d695cc444c8dc171",
"92fc6ae91caffeefc1e16e816a0ef299e17c63a968d41bb91b7a6f587d34f8f2",
"76d986dbb1668f0069867df25251328e1aa15e6f31233eacc856e61b5d328e6c",
"560b821428968d6304aa517c6b0df4469059a097171e7180c0bdc1de4c8c2dfb",
"199db247cd1e61526d67823aa89c7d3e9a849a1c48983902f4e732d37491ac95",
"f3000de6fbdf5997bcd5067bddbebd4c1057346a69164446e4a2fd0fe575461d",
"a36d62775f7abac51834f25572e05a0238de20394f0b8a5cc1f33b47984c4a02",
"b6df530ded76cd3cac5eb5f6516b7b5aad5ee43beb0876c8f1eddc38f4e173af",
"a939753b3d570927cc8d90e512239cfb6e52d81b5d56ea80eb4d0c46572d9ffb",
"915cf3bab38606e7266a5f7c2179ad469b07b134765900ff6ca2a5ab83fbe80c",
"c084076c1d75861928f6a28f566527ad2913a2bf829489f57dfc8947c368c50c",
"b71e574bfd980be24d08395d32430a000953a021556ffc4d7693190c00e74e77",
"4cb8e212261c1ec6fbc52df8cac337d6f5d189537645f7d5a7f911db882db716",
"533abcd8780f59049a8462ab7ef505f5ccf1d342150c30dbab5949fb084cdf21",
"db533c3913044c03977baf092f0156071c2628208d14d81872162436b87123fa",
"ca8ac0dbf15bef994221f78c0248b9a6408ead1166e623c6db7652a16c016c06",
"0990b3a317a95d36b6b6ff1fc6736fea01529a39c0fe06e49b7fd564080b6df4",
"787469298f138d1c490251895a85d6080e52aa1df375643d195dbe7e87847949",
"68a371372ba0f489c8ab8672e257f265a418e50c6c969bbec4b24105850c371b",
"f8ba30581f3cf31050db47b7a43a5551d13b9ce7001c896bb79409f4f1d0a31f",
"23a5c21151808ad600e97139099b79c3e1ce23ac1252db87b2d4cb88359cde4a",
"9886c12c93ec0ea5d14478fa4a9a38c4a1025f8b9d595deb371d6aff79f93b04",
"4e4f81cf1628b6f43db1db218773db5f7a405311aa7ee5ae2072148a867a1437",
"a019556336364cf6a38501be26e917b0aa2cc2c37c137fc269659aa44a3e5ee8",
"7c6b6a1324fc40c2373c6215ad699f723b826f02397eb6f6326c1a5ed558a115",
"bd21001934e50a47ade3d713cec8dec036d54da0a976ed3b690ac080a7bc9ac4",
"4db0292758deb6ab35aac12fd6387276b2f32cdc859a15642f01931c845fb0ef",
"5431a87a0cd32b11db5ced545effb22f220ffc69a60ac552844db86bc7998e84",
"c6f343782af6f6ad784f9f85c1123fba0b82ac07119a61ac39ed2fbd92fc0a90",
"c412d2dea34ebbda964b17cc12c1da70e7dc428c92eaf494e17100e9ac65ffa4",
"e9b947aba6755de52a67725be3849e3383e187099aeb1bef5315d22609368b23",
"0b2d1949bead9e9995b717a821f6e5dc3136857b178638350a16c1a32149c6ff",
"dffb51c4bc98c9f0c07ce18a88877d48947706cf57f56cc6a29ce82cf2f74c07",
"97dbf9a48f3c92fd4674b20ed6f635bbd92af003de523feb5ecc4758169e5857",
"cf701be33d1b3abd3357a74ab2f7f03fa78f7ebe0362994256020fb1fad75251",
"fb26930bfdbbdd6f69be65c3c01536e09a30cedb747b69719035e31636e47937",
"5725b8ebf2345fe7e660579ae94b84e251259487da4428a5f1f0cfec19db0639",
"61b92f8043e5a035b2144fad7b1df3ca7130c56cabbe0dd2757dd737719719fc",
"35a2f85adbd0b6a818d84a16d8ccbc0947bda389b6cf43ce6ee9aa9b4aea19f2",
"69dbaa6d8a1d44259bf095b55311dd39ce028ab20de30ca49b1a173d6171109e",
"3b68203efda022be691480952c5132129d514b2cdceb0d3a8f137595be7f1c25",
"388d3dd82eecf369794186b42c964871575c03fa9772d57d31280d678f87a636",
"6b493f049d19b3d1e268babf0211d48abd018c912787a913ff71457d54ac3606",
"53261340605f5e63ecea85eabc5716f31be1d16d1c91c04f3a090773b288e62f",
"7bc9e1a6b36320bf97e60da91091c0ea848653a56cfda13f129e42719623c500",
"7347ad263d90e20635eca6fe1bc89df06a4ec273ad50e1ef78a27fb9fcffca13",
"fd286c0a1d9e4a0e0aaf97b7f2da4b219e385d7a9afc4982698574d72ae49daf",
"0f42f9f37bf77fc47e1c75e0206654e0059703f2b7dd261f91719e49e586e7ad",
"5c1eb8efa7c26ebb6a3e2cb19148783df0b7d5dac0e80b3c793ecb556166a88a",
"0fd0ace6df8a7ba03aa6d52f78c3e58a4720a3852ad936bba80e08bf7c61a287",
"020d473e1c9504366a2204d566b1ca6c968320e30382129f95a40c739cba7f19",
"ff7051698eaa84a3ffc25d5dbcf923933a1a59730db33e8161698160a090a45d",
"df0b1d015cf77e47512cda3d49be662782e52715fb747cd0f73934109a066ff1",
"930edae2fb341f18849c9b8aace01d5ed2cfaa013f59647cb542daf33ee60db6",
"acd5d0212d8d1bed17253050038a481d968cbb8007c5c69f35d328cc887723c1",
"17f76ba6af39c2d64b95554ba27b12818e60284d166a9da60a3110091c1dc3ec",
"e03914821b7b6185e239eae45598d504558175443c4f34b700c2b329beaf14cc",
"cbde6cf03818faf19d93a082a509c3601a6b043a66a222d389cd44d4a91d38cc",
"c42abe41dfa793e60e2ab797e626bd8a5904e03633b61c513c9f80c2be9ef0d0",
"b47f9040a5561c94bb5c11ac8042f34d80e144a3f5a8b7c0e47d7aa3c10812ec",
"07f44825dbef5d2c5fb089411e2eb2d4f7e7eeef6697852084acc7b1f48aa77e",
"ab143316522be7e11b267b89677251a5a1d48ce7c90ee27a6c66e1857d71e576",
"3e03c42ebff10fddf113e731d91c96cba59d8d29acb8f6e63e0fd171657414d2",
"12a073e1548bd7551d477f3ffaa790d42105596f7c161a623650f1a053c6f053",
"4882fb1b192fe817b836fff3baf788d89442f75d3ae7a529297febc3ea896779",
"a3b5c64eb6d70663ce13bad27c28cfe46ecbf721aa12d667f3903e155f37471f",
"19283ceafa4e91731909817f264f997836d529c523881913fef99c04c23f636a",
"2c9ebde51c783478616c534f8cf30c1d9bcba627e82873678054f8c05f72cd20",
"6addbacf1779166778a472eafa5388de1e51765c9264db7f44297808f30cc940",
"33c39d4cf80eddc5b93cbf11f5cf6de02023709b71c3388dfffd485becf93de5",
"73d7856eb00d8f0eef1cc6ebab299384aba68e5e7c90e4526c4a33a3f7b9725b",
"f45968304cd3eaaf430b7744dac3bd2c287c51ab1418e02973fb2f6bfd3d7847",
"1e18a797ff5a58a2a3251358d7ea2e84895a939dd63fb5a3c77753f324b9c86e",
"3ff531919376e2ad060436f9d27129b7ef17fb8ff29cfce1ef3726833aed96dd",
"92a1626588c06d5a3d74a59f23e506460f99323c09d35bf5d49bd73450803f50",
"be288f4cfe34bc80521860940d76e5a42c85f68ca190a4ad71dcdc18c4198103",
"9339b6786bf2c8c1dd4830c384e03dedac22e92bc1aa9cdc3449c674bef72ca6",
"1b22a0e578c641613e3602764129e027e101e2d423d9fde2a6718a7dbd726eb7",
"c6be938d80860b8ccc96ba087fdb2a00d980808a61dc79483710ba87f1529dde",
"4bbb241fdc1feccd155ac9feb2ab91cbe714030cab20dfbf34318ae72ecd4a6c",
"706c4c5215f54df3c0c256e9d6c54de897716618824d1fc630d00d3af059352c",
"93e883284fa263b442a033252e84dd637a6943f49f9db224855327139dc8417c",
"689dc122cf1c3b550ac11e0041b45844b794a45c31a2896a4238242422b23819",
"1aeed96414641bbf27a32c1a94b5bc224947f87bb915a53dd2362a5baaac9ba0",
"0c0f53761b2c3f168b01cb9cc05894cb86ee53a02ff0c5fd5f160a8d0d15ae76",
"da8b72cfb9146b496da6719d87da1c52f295086935e1f15da60a86b24bf29b97",
"2389058fa5e0174f217260522f49d07b76c7758b0d3f7296809104cf78561b40",
"0a59439df43ceb691a13038b87b7ed5ed2d05f7acddeb2cc502d6df537b71311",
"ad9989dc2e5e4d1a473e2f30f9581ad5dd161f68765adb6d2e70c8effb23f3ff",
"466309e21fe5c8555a231e5214596e196ad44683a8e8376e453daf42b8085d9c",
"a6ceea7c560556cdba4d7b433400688ffeffcbf27bc7d05ea507dd2d4ce948c2",
"b77e4ed4bee931d43571d6f22f0ae253ae2dc63871c5e4845c6676c7dd3f0eb7",
"7ebef185856fed824ebc3f38b79f82746b2983f8106c2ca6a8b64e410040de10",
"e9a0458703175d02b8fce2b8ca87d2a6062270e97499130aa81aea621b42567d",
"ae17cd0fa9460c9caf2c158e1ac809d0baa510933aca2413c316840ca42d69dd",
"0d485a3ddf329e8b8dd47b569c7ba6faf17d4dbe280521a520ece56136ecc218",
"20241e5f5bea83a9efe54520cb4e18b2bbda3eb83b0875f44c62994cc2f4a481",
"ecd706d3f483600f37f3b2b268cf38033db1290e0359a089e7dd44d35300eb39",
"326a9ece9955f2f872f0f6e401ff4281f1992d9f22f247ecaf25a44f5661c732",
"36f0d608c831ea7365b0ab0f2d78d44f9b6cf0a3edda625d02a0e8db1250c644",
"fb476cab0554ccbd17ef87ab086fb70310f1b468e61050e4c47a9c003f71a88f",
"eae0d52bc60c959f73cbf3ff7a84f1005b935e3d71b64dd076f23851b61e19df",
"c8320f5862f6c97350570d41ac318ab729aac137043d0ca73f467eca670fd2cd",
"ad83f844f80d1bdc54559399d55f09160e3041f63bd85f9482ef0e0159e576eb",
"faca90225e0b75e9ecdb380a4f45937016f843f188f48a956b24601dbe2e7eeb",
"da4e04a00f8b7a2724c60b78a8df4caf6d3f65a8f5b8a86561ceb9933eb87a72",
"c17975d1893a8b62915a085e714f9c6f85d9442f7916ddec6a822090c8dc655b",
"7b7f3cb7bf35478e8dab8f33acc8746aa6ed70189e0daa8e893783deb55fc50d",
"d0311b9d76278b80d7f55b8c4bacaa8dca293cccea20a784ea9fe254abe93b5a",
"91d99863528e63d01fd353457a910ad683d11614458708b31fae2454fa224b5b",
"b0ae1e07f65c9dd764db153aa46cf42f68d780e4b28e642a4559ec90e8e3cc39",
"43fea848ab8ea34e591ac9c9f98783b3f83a812a9bef6339e81bd380d4d0b0d9",
"80695fc224bc3d9f16e1be9078e62d91b1769c4147dc44421531a213b4a69460",
"ebb6cfe7e39f666efb4e256af94b5b21aac14902ef3c23e6788ffb32d16da24c",
"ef5b6beeb6cf57ad290d3be9fe6790221fe4685d99ced85082f66cea6b2e2d96",
"a4556671f393544c118880d5e2b6e0b6a9d571325e35972c8bfa5ae70a9aec8a",
"0df55165d1eb0fdd4b62a25222e060b21a4e5be7b8388e29380b86b2940efdad",
"19b60ec413d47f58a62173098d1591609281e701dd079656a09512e8684badaf",
"52e4284b527671369be86b4b20545217254f85faaa8abe39953b59fa1557442d",
"8eb1a4325c5783a09e0febbc365313f3c4d35a2c1618ee6532572ab2ef1124e3",
"48a251c051cc0c8b051b806600f00342ab81e3aa111e066e74adc044502379f9",
"97fefae91a85838a8b93a4a8cc0edadc2e50b43c1ac0e36a259a40fdf8a4e213",
"aa1342bfc905f3f255c44aa09df477228c41977c060fb5f936fc6b4838c5be7a",
"b9e6594d64492899962352ee5c918c3ade3efdf92e16bd4320e0da27ab3ce2ae",
"1a5db6b7d6da5386f76ef77cd6ddc99ff67de917819afa746dc3c5378a95f30c",
"bf64bc337a886d5d799d839f03eee210acab95f613a17db30165d3e249d07e87",
"37b794fdf56c4ab8d2b4d00506ae67f02060625d55adf6c208cd2f53b6787cb8",
"7df41b919abd69e7acee85a552ed81023aad7a4f1773b35f104af8d253e9020e",
"71be6114d2cd31bea00baa69981edc59bfaa7891ed5849178f3711f37e5a9223",
"7e8908c6f9e14300d44c2254d022578f689d8c0cab56ad73ab97c748a71e7371",
"06a70fc0c9e0e0a3a67dfec26eb5367836dc932f20f65770cd27511f76a4ef7f",
"5f902ed069cac194a12c903fd9231b3b9b73ae499e47206179a5db78053b7d48",
"c4587b59006d177ecb76f64a083c8bafc926b243a6e9ee6ef12bf0f3fae367ff",
"eeff57364b4cee2e43ed7811728c6e0dc155c94bd8630567981c00e7983c202f",
"d9ed39b27fc2cd3e1c3bdda317c856557795363bac22e5475f58614be9da5f0a",
"5fe8295650a3ca6dceb6adda98a9b2a52c8ff5aa2b879dbe74dc479c14df783e",
"bb74a5396ca5059aee5f6973f760285858dc7ee84f34631100b641d8f48b89b3",
"bc357b63fb90baaff808482eb645d5523323bf52d98c3fe493ac8eaaa4773677",
"2d052d15ac1ce4eae8e7988c586779ca83b7f20134899d1a72bc05bc94c0b35c",
"ec20f72f981ef2d1397d3f05c0cdb32110e4c7bb9b876a9aa8296f5daeee6cc4",
"039cb433d2315ab0011d4f1b3d040ec7e1f1006fc3278b96e9a8e0491d1a9d60",
"2dcdb4800462a1c11c0e832d04a1c49d9f62103f2da332286c48fe94b456b92e",
"4a8b6e2279a7392cefb1e7da03b42371a678f84c856de77cf13ff9c0891d9b00",
"57bcdcfc0ded16c30a50204f409dfc81df4ad4b1fe673d99920d9f79a397d8b7",
"0261b6d4b9c1c5a585ab93951761c05ae9cd62c56359dd821486d2b1fbbb3177",
"2a71c8ea5108d9a459c6ccb1a614cc2546ddbd85efa1eb39ab3ce0a504cdb916",
"251698409786d137dbce1f4490f83fecedaf384809eaea793c3e688bbf61811f",
"2ace8689de6c19ba00afddca95b6c4d32b9929390c628b9339a77ed21dd9ec97",
"10e81239fd71cd6fc6a7b858986c7c4e1d064811ffa0cedff96ec34e3fa9f454",
"1981916f528ccbc3547bd0daed092031c4045e1d1426398f88298f7d29e61f8b",
"271cf2cafb0c86c1058d1247771cf90cd398916ee1eb4988b19765673a2c03e6",
"9d086afd05abd5ed8e554891229752b2bd98bb124d83e5c517c727a6e41750fa",
"5f2c7ea24040a74f3badd941fc602bb8ba2c2f3dc8a6f12bf3565579587b5ac9",
"0cd14ff3e26eb0253503592d3c2231f067c0d34c9a08478b3ccb6f9708e63bb3",
"7d8c41eb7c106d34679fda959f40538e268441214561488988384d52bc4959bb",
"ad844d292ee314dcfe7b9673493aa46fc09437a3215984514f7d6e25516d82e1",
"1a2a86d0c46010632d2cc42225c28e81d33831a762904c07fc165696e0b21f56",
"dd5549881dea36dc21d79af4fe8fd523ea7198354b09f11d45cdbc16f2f1a593",
"f163f190fa2603da18b5c4d6a8ce38135027e1e27765786dda3d4aea2a9cb80b",
"6e09fafb8b6e87d6189f46e244bfac72ac097f881fd3e20548bc9b2b77a06494",
"050e25827579544b11a0659b33779e36091a9386e10529de15661476f621b4be",
"2e106b4ee4214443a32a625a8050bfbe23c994d5d11f7c06604d67449dc4b65c",
"f46f7dc3ed0045f94584f0638fed6b4a1428e757d0286e64a7d09b90bd379f44",
"4a2c43aa7fa22812393b64ef4735c4ce9dad96b2324d06204d17cd489d7ce412",
"98862e2f2fbafaf00755c99a60aa0476cb449041ee71556e1e7c6442e149e51b",
"4c118375e7aac9cd504042c81c94f58f123924bcc2dbdd07efdf3ac283bd06ec",
"bebddec9428e7802423acb00e58d998f5daa5a26bfdae57697deb463e9e86feb",
"53b03c24b8c7b3c56e56ee1e708df3eeb032bf383d7cb1b2d3fd0bb11cb984b2",
"784badbf46476520b5c6635401f74e99ef7c7a003a393aa1fd57867f185dd721",
"2f3caaeb46d182b613605bcb8bedd3831bfd1ea4e7a041c4f76e0d4718aa9eef",
"1b3aa9204c47e2d2ba2657e13382926d2ead35d868353551eaf9a66a70c669ec",
"c9f2a7d878c3f80d7627ae2b832007dababd27fd2fc13709901faebcb14b2932",
"5a39dc81cb0b6518f00f5c66ac659dbd72f881a78e0c0b13dc88ade430abb90f",
"2f0ee5fedfa55f94832fb2744a80af32bdbf7708ba65a3e0d08b446358da1499",
"1d07c7dda8607fe8e06cefe30123fb4a38302ca4e091f5ee9df4013778e13fb3",
"3fabeb2e7e8cb221b62d4e11ded6d5eaa1db1380b7639c943f60a1c5c30cad09",
"51a1fd08466d6b37cbe7a6bab184c21ca50c9feb5938283d58d89fdc1035fc9f",
"0708c2dc87f7ffaecd46d3c7dac910700bbdd5f9331f262819ec9fc90545d3c8",
"2d8f59f27fbf1306ba8453c032a2d8bc6a18ad2d8f3fec4ec260af16f6213dde",
"3a7455c90f216f2692b108f4c907cde0f64872ed13e6f75b44e5f857695ad824",
"5f1fe505ad82e5de86f16977be619103b511b0ca09393daed964ec61962cb942",
"3decaf9907eda934c124f603d3252929ccb9b99aeacf745018f2cd612ba3dcdb",
"4d232fa8d81cb6abd1fb6806b45c069b7fa7011248f55d1873daa335312dddab",
"55000d6b9fd4132be58fdfcc87b55b28dbb2bc259c33d50e03a9d470e503553a",
"225d9a9f991b12fab890ccf06ee654afad4878a3a8c0bb3ddfdd54af3ba74ee3",
"40df7f285dccf966031f1e8815bec7473a748f37c9405ad98b0ccd40c87f986d",
"c4156b9659801913909aa5955548725ed2a251e9d3b3a587786094dc299a8f61",
"5dc3a95d6f96b946237a9977b4c1e05b24799729f03c191b084c6118106fd712",
"118bf0b7868f02b1154198107b4a86873ef471153967ec7bb11341caf70c4355",
"1ad3a5310730b0b698512c8c7d3e7a8552f75b5c7eec4546860bfdc622f75e7d",
"fb74a1c13b1eb19423dd805a4d85ee771ecf52e3956b51b0409cc5bbeec34569",
"7405d158d51c83cfb8dabb3201f692e3bc089f020cae6b62a2af2c88dd8f03ed",
"08f20e5a8dea1f3217c990bc112fe510ca5aacdefabd5a2a6958339abb88ad7a",
"dec3f7bbee141e55a68d1d164e891d9bf832cab148061a1551475fe33c1bc868",
"0a311678a6266de62ceb20154e6ba5ba5560507d58d8c5798474967b4924651c",
"b4f48fd17a7cd9e0b26e90a8adfa2f9a150d47e9a203cb89df114585645c87b6",
"26a5c76a25d02b0feb4b22e549ac88447abb8fe7c86196a73292f13d8eea61aa",
"2f41b58911b04c3418bcf76dfcc500d03a55fbf1749ee83a4e981fce4e32eb4a",
"411a18b6785d5cabf9b666a9a70cdfc5a1e29228f92f80b9f8d613face0195f1",
"b17d0a2cb46dcc365e065267bbc2cc36e92e20bc0ce24d144089d69282e6fa19",
"30ede26b25bcc2e6cc42f248386c61499ae477d4fb392ee289238c40c88ab5ab",
"f1bbaafdc5f0e00a5dad95c9ddf659747c74d093e1cba8a0e72f1db1d5cd904e",
"09e411ef140daba69cfdc2c3c32fd84cd572a842f53388124b51aa2eb1e40fa5",
"2c408b685afb2574e9fe2a212e92c638090e851026ac80c9a639daf234fdb984",
"a342b54ed7092264595569a37a5e5140a48d5117f62833de3dc1923516d5b917",
"b90af846ef17cbdfdc06399f2d6790194fd2d781babbcb2c3ba005031a278650",
"16c65a8054f7c7c6beedb172498972f2c3dcf0e8da240cc8f120dcee7439c95f",
"8979da949593c80f9164828107f04602d70ca494947d6ca7722180ca85c8c0d2",
"eb4ef64a1eb138e6ec7414b3d841d24e61d6aca94a870d3568f89bfeec28ce5b",
"8db828055ca1154a1c1b60b992299b2a3cc9f9ff217e15a329b642c8d5515344",
"5813ff09a79cd74b6fb3307c277caf7e80f3506afb677eeec65555b7fdb8bccb",
"e15883831714acb3d5c08a3898ddc6280114f1b41c450f6e93a27bb36e7c6766",
"95ee3e0acc204a6bd5f5b484e907056695cf5ace25449fabe87f25d61b1262f1",
"8eb0d5da9c247c962eba9081b9b58413b8f7aaec03df2813c77ce44573a3ab1f",
"afb841db4f6c64fcfda654cf058f0a883166b4066fba6be6df5dad564da30515",
"68fce267894ffd76f551a169c9508e53810bb12e773015aa4c547a56a5806fee",
"6e614d1afb783e6b45301b2fa03788a1fe27f2808cd2b513eabeb1226e6241dd",
"6bb0cdb7d8686d79abb5453c3f5045c1acc2e268b3f2b32444e60796a18d4c12",
"9b99c863068f24297df3431025ec6564b66f2b9f64c1678b528a1dbc4bf71b16",
"204b6f2f3ec5bd0f1907fdb460e4ed6fb0d25de5cc12f777a1ce10aacbed40c4",
"615fba5e47ab0d959fbcef39996936da656e2615b954f03b61fbfaa8e1a4f500",
"529895a7de063cf6e2497d30d849a8df3c4f7339e22a486044cbb3e7496fec22",
"b7fd2e4c0b845850f044f32c5d5123af9d5eaaa693d4350c4ca8758bfb857b19",
"059e015cff4b33f019921f9242533cb45cd65e507ed882205367b746b27f4442",
"1b79153a3a25bc82c7f52a577c140d85854d76b3268e332b5871a4de4eaaa47e",
"b9730c36bf7402a5d06c8226dc11ebec9c0a4bd6a23762a6e9e78d1b996a4630",
"d22427bf91dccfacba55357d4a8038f797eeff2c4dab56220cb00d9ae897b783",
"da19f42f6dc60fcc3d075d6f38671949ce2dad31b37496a638d341757822e92d",
"78132589eb98ac63e53a329f7cee32584dd447bb9fbbbc01e27245ca29c23a23",
"e467ea63a727b9c36e666d435664875c822f94f047f60ac0d89f2733bd4d1f01",
"f4f89149b1a5779dfdfa3a9b7dc5b88791deb32c20db6d611fa013b9a2eade6b",
"7b40c196aef97aa032f8a1ba0b88aed12baf4331acacae6513e8f4fbb102dc98",
"dc87f4206941dfd0431dbae606358b03741e52c9c9830017847042f99caa1a89",
"293c650a8f2b442da199ba6dc31cbc7616c09bdfcb685d216fe5f6964ebdcc19",
"cf3736739c87082a71653540be254cad9dd2b80c788910ff51833053de0f6833",
"b7904a9d282ee147c41a87ab1de0c68f6fe6e8681b728a50b07dbf82ab61990f",
"ff43760bacfbd8a86b77ee50524df729bfc322d221bf39d73fbdcc5172be25cf",
"94b19511a901d6c9863b4e698bd3203bb45f459a706f17d5fd0217b7d4d2e880",
"5fb42d90123e7d17bdf84717dba17f8d6e2e4cb9856ebcb5dbf6892fd227d4f8",
"d403da452541afc98ea45671522db8605d28a1373baa96279149d70fec56e8db",
"c515c1f3132d7124546c2149d2f96bf8899954ed28db737d81149cbd9f84ba87",
"7559f506a7dfdd3ac7f13dbc616629b56b88f8e43e6039205182b17136e45e6d",
"6b3f153c83caaa5f7bff608f4fbc514feee1ad49652691393b26e60a3860ac49",
"b25dc960443d800d107491ed43a224db6df66c12b02b7dbd3415ad4cf38c1f25",
"a70e10b5d457c0c10ae765d7696e96d1721bbd0557386cd00db27f7dd61c8039",
"c12df355cfaa94c9154a29848e53dfb2d1bcc7b68cb1506d067f5feebeca2134",
"c9a697b7434305777c8068af8b5bfd654d74bc5ad82220f84fe16e1cc9cb2173",
"261dab494a2e8adcbdfa76b171a1dfeae0a70cfee528d781883537c35ad37546",
"df2aababde59eec1b7b499858984c1204557f599659f05f6671d1d66d2273d68",
"36bbadcddfe80758e7b91dc8bbd2d2cfca89aa1c50ad41a706c99bd192c1042f",
"bbbd1e0d041cf1b340f9b0873d876ead1b76c60f593e8ba82e2d700309ea5b4c",
"07708bd4113b5e2773ac0d65323a793e5dcc366b1260eb55f6ed80f6fb3eece5",
"b7fd39d21af1c3ff30225230a86cb382680bab72cd83c081495df252bbd31dca",
"a01f7348d23cfc9c72d4c6c8d41d00f25331a9f6b28f704e314f46b9a5fe8836",
"e14b6869725e9f7c8b4d0fbd88d1cbf9a969e800bddeb3b426ab13a9e1c6873f",
"ad16ff69baf5690783aba8de17d09a92af4fe62a985e33c0969ed734d09bede2",
"d3edfb7f2ee7cd654793fce245666efe24655095b9098152093b3e5a12cc41f7",
"50cdf981025f02190aef3c09b5aded26472fe5b155c689acd1600b6f163b0aef",
"d944eee476fcd32ecf4d85d5796e17ec2adca8f9f6ce1c1f66687e2d99a29f2c",
"6eae57da9514dd54a3f5920e1891529982d88c17e7ad6f6d8d24c731e1507992",
"ba0b8bdba07211878e29c71e21bb5aba5186e50fd45b4303f846897b8c409ae5",
"16828f8c425552366cedc41a7ca7f0df1c5e5a9dc543bfd9b0df65021d087a48",
"338222d8ae91833de9008c65cf519b1d021c6072d09cfc08f78d002300b6dbf3",
"c0a24805f980cbf60892cd89af249fb06c079c694e3cd84f0cba7f21f9e6fc9b",
"fbdde53f5541ec1feec1a381409d5ec9c6baffe97ca0c7e06f24e841d2b1161a",
"1752a73a37c14d5080efc1ec13bb1dccb9bcc0281a4d95cc2ef4b853ecfa6c31",
"fd2e0c2b50b472b90d7f4bd119085224219ee533a99922ebd8cb0f2cbee9cd7e",
"3a1d28fe96af222b8bcbbd2e937ad0d1f4128c7de8c7ae4ddf7015b07a1f6bc8",
"7919fe4c1265bc194272f2d3e0a0a0dd4853b9f318baf6287484549b01404b68",
"10f6bf39d6329af3916a571ea4ae1de70cc23a9818a866be45c267284d3abfd5",
"cb0c691d7266460c4af283861919c3ee427c09831e70161c0b7485b3f420c051",
"69d7916a1618b94a9794dbfffbdafe155f921b57b40c6a55e8ca17405d1183b0",
"0c59dc8c3caf16b480847e086cc53f4bcc55c0ad0b2d6954f943eedab457c86b",
"8accbc6c5c4abd38dd2574cf0a84286709bb377aeae9d50668b2145190ff94eb",
"66213a6bb4469587379b204233f5c4cb9213c9443c6ac8a8f5748f339223bcf8",
"1512294a5bacf0e03dd013bd22c0469b02c6a56ae6ab03d089d1b59f9bf47ba9",
"a5ed327b1392f514a7ca393657194e0cc1f5f454aefdba63e867a3905c9f3ba6",
"af21c0215b6b801617c9b590a5bbca4874f5a23e7fff46e2fc380b4e501b1b42",
"48d97a310cffb3c3f576b5615ca7d30491461980e9e6ddba01e9ab8b69c6fb87",
"c23b5db245f1cc4791a6a7f57dcbd3a72750431e1a67f5f783668c8a2825a0ea",
"ea2c2b9190a3a2e7bca55d33bdd1566863284587cbcfcdad74a617a571d006da",
"f00c701d6e9eb10e8ef79276cdc154e8ba8c4422f1d08ff330ef3f55d054d337",
"43a9d6c9ab48dc22ca3c9cf8250db069e7513537e53cd632424035f96371b52a",
"9668811e88849fe80a78b79fe33a05252ec3274a8c4c924609b8c85281ccd46b",
"f2f93449bf57bbd79c852a412dc55922802044e40a10d5b70b940a585ee720ee",
"d20bda52ea5a7e785ab94177f1d90f5688d21b3968326e9909c8d26cfe160b6c",
"1eee37e54171be9e11fdae188b2edfb0bc024b5f94de55dda4b175596d449bde",
"0af11c745a8c4891e888eed30309edc37748d712e154a078d4bdd5b13cf220b1",
"15982ded9a62a5482a3acc1ad4c33159fe6c42f09aa14365a292d1f8e4434861",
"429e21c28b9f0e415e2211ff953a01b408b9399dd2b67d0cbf212653aa9e3de5",
"9b21c3118ea6bd778beb58728a3e319c2bdc18fe9bb2218024e4d7d537758988",
"730d819c74a968d95a749664b659fece7f28f85ebb9e860542969b1f83f7135c",
"07734cbfaf9de00aa8bfdda5f205dd887fd7df72535ab729d873a5ea23080c8c",
"472f6c62614c64e30fa642fe8370b2108fc6c624bfc3652ddcabdc943b93d12e",
"41161aea39995afac088fa514c8df9905a21984920ab7ed9f5ef52f603932f4a",
"ff0ac19b15cf71021ba255bb88b9b48b8d813446364defcbd3648719c0ab4a4c",
"d9836a3268981bfe94ad1f77f2b3ced20b7079f09025391357de906d03c40e83",
"7e55b991f5f34ac4389f5574bb493fe43493e65668918329489fcd9e473eadad",
"d32bc70e6246bb9345bb5efb2ffb68f6173a0b675a8cd4c7ca74b354adaa2909",
"b9d8bbf671e794da22b3d2318c9ba690448e3a41f406b903f638b5025f7564d8",
"b28a5816f46942f4270bc625ec876659d37c5e40aaa913a6223e49e7576235d2",
"43781bb2014fa51a94bb3498c99623b76eb963f48238f9b1df9b6f31322c0970",
"8dc87e8f4df3ae436fae06c170909b87542352d349384b9c7027e950b402f65a",
"339cbb45be7f44b72f31f96503860c5a25c5f2abde498a93561fb59b433f293f",
"f2e6d476a7d47acc13d2eabd4d309398684ca739f8bce57eb55b1e79f3d1e519",
"56af0198847aa027beeb25867b66c211c78fddbf74d32c1d833d87c778120fac",
"9ac6f60c776459541ec6bc8801fb2fd02e36585debfcf3212fb0b1614ae2f6cd",
"e1792f3d1d3d161adf761720889612dd3cc96eedbbe2a432a03f7539b0cf405b",
"0618cceaafb6f8e91a6c592127ea2b5b0cb1194c3210c3d643cbd25e047a2c5c",
"c7deb398d09de0de32c114870e0843d7700252917eb69fb0546830437308e970",
"e0ac7eb0b844399d04bdf65c93459a19b00c9a23bfbee05b3deca40a05b9d389",
"23a16f8f604e45d067ae5a3b94755fd327505b4a0959844aab30ff5808f79b46",
"488b6589b506e1a4501b2485091e717411867900783807af78f87dff7a46cf0c",
"56c965124e66ae2c716bf67050bdb320f38385280e7a7c6cd51bd7f7ce43d32b",
"19edef6e3e69990ec222877913340628049da39409aab79c93af2b6948a93d58",
"128eab2b73e6a6e9c535e15b22559826c3e9d678859d92653a5b0611acd12d52",
"b60504a4e6fb685fefeb7053d02d89bff2c41c86795c4061a89d0c3685da8e84",
"6038bf6c7728e0927950e6865113a34a6646cf0ec0a2d15e1f1015b87ed6b091",
"1bc443a013d98a82943adba3b89cbdbbb38d8aabbc0d4df57d218717d50f50c1",
"9765ae2f7bd51d2631470a84f4acb6d9669f3e211ba7b3d1480b80a0cb53dea5",
"cdbb6c307084183baa8b44cd6a93f014687b2e8f6aaae063fec6eb2c61d3a331",
"d386012578fa5b91e761a714209d38301129c8ca4d1d393549a4801a9b1e0094",
"05387de7db27a628101147c5e01cf481a68866c5f4be570f35a50e5a96dd8976",
"ad2775261f5a12d7fcaea9666b48dac6ffec096d643df0bdb53dab400abc9fa9",
"c95adaffc299856ba5bdceb376860a43c0a55383ccda166614af9333986f18b5",
"2db34fa42ab7e9970883aa5744fd4ae926463a3acbd35ecabd5854f369bf3f5e",
"068881adabd87a5d568f27064212ab1bb362583ab9fcae18fdb03dbc0f3185aa",
"9ef7cd94ebb5f2b74db7933a06459ad972f43f21260ce84baf26904eae9090a6",
"99afd610f6087a27df4c16d1faa3e80af5dba4194e7aad1347dc282f493951d8",
"d036a9a86f34c9eda2f4d54a8f9df4c470c0f97695c4e5dc9de60e85af56a1e2",
"7f0137290a2f6b51638f1a439091c26c66ddd7afc9a8525c86d0490952957f5e",
"a755f2fa40c875c9592313dfad65fbe58d17940dd1fd5ffc38f9520f91b8fa63",
"6690697131f9aeea3f3a74f83c6e34475cf3c1d6c63e1555174ad875a908ece5",
"26f83c084041837eafe3647ce38404a2e24b2c3f5a870fbc57ee2f75fe863156",
"aa90255d432e68be319e26ab5b1423400d2013117121636cb27ec494a887ce49",
"72a7f09acd5ab6283df40bd92802a67c66c5308f661e98f3c12b2dd3c26817ce",
"de85e7574117c4c773bec442121ac01cdcdecd533946624f5956258644eed440",
"51e4500dcd4477c425cf9276a556041162c6d9978d56f394d32a10c963f3049e",
"7a37ec2c99e082dac260c89e7fb72c23a1f958c31e50624217391cb31b715ef4",
"1611fa2786e97a786d6f0a9eed8bf4b9a30a2158c6b9722eba150b4d53398e1e",
"0ce07e0ba171681afaa50f91d3ba9e1c1801f6c9d49d7d695d2bee3ca563dab2",
"4a9cfeba7938b7c64cd17a04e6191e9ee3b07eb39720f76794518b264817eaed",
"ba2e9a35c933057f7775202da766bd3686c4268f32d9287d8cd3e0a371002d76",
"41e92e37ed2717cac094610c3da3c64079d81b0f18adfbfbcdc46860082d05ba",
"1dd6a4446b8615ea23597f2f1fb4f01e8bb999c5cd098099694dd2d9fba09e71",
"a32552daccda15299cf311e0bb4c7ef3378f303997e5b2f3892cf3265c9aafd0",
"4a17194413577d14d26f1c1fce778081c7cedee904af0ed3a25abbde34774885",
"2d5b0ed95502bae6f4bd6738def6edf4e7e351f879b8c034646fa7421d0bf675",
"0c32676576aa6862d224cbc313ee6576fdcfb71c8041e83a789380c58413354e",
"f1c53b8e6989c4f0d55a5a08239393a9b8a5517244d8f04577300048f9e21e87",
"4c6e479e828fbd26116908338cf72758557d523d190b7cbe3c33cdb00f91f281",
"fcbab6fae7d8bacee71d82f2c1ab679c48a85ea750247f93478baafe4d8682f9",
"f79fced898dfdd08f18178825490803c4203a029faf29cbf08d8f1602f032430",
"d2f0731c4ff11f4cb6234e6f22717d0a2ae395409329cac53785269a7c26ec3a",
"535b3030171da4c461763c488d7da9e89c8cfd7c1c2dadbd360bb99edeb9b0aa",
"9f5e861a8376f92be1917f3157180c119f5b2bea66ef40bdfa77ec8f6136df7b",
"9a7f91c1a05612ddc81567d6637a6279b614dc9fba3cd0322777f437f6cf11ee",
"3e1474061b17403e96e750b3ad725b570d4ca96f98f583e0cd5dd26b84877cbe",
"c046e99c6ceb99a1ee02f92bf5099e2c44a5adebd5290dee742cc5ae9da7076f",
"0736d3d6b42c0b68cea5a9c774183db0d7ac138e6303036e46da245dda405f44",
"2677862a927266eedf5f926a1844495ed7f31f671dac9f58996ae17c637ca140",
"df622da8693db1d4245400e8bdf8a28190c1d29c27d30046f9fd1178a7554c67",
"b0adea932e628a977282825083c96a26a276dc13e623380a45a590fccd543be1",
"1c54ee5a29b8ed8013b00cdcbdd654272965ce4be0e38d7afb413e65cc8525e3",
"62b605565cc85abfa0861daebbdb0b13d58732e59bc1163d9ee5b411fc6f7af3",
"7b7226d49d687fd471e0eae0f54d9529f330d58b40a255aa871ccd36c8b048c4",
"9ea175109678095977395a2337781a4b7a0bad3984d030b6bb0223772487d27e",
"949862062b71287fb7eba6eb72efed9a06402d4372e8d4c32de15961298b9455",
"4200d4862ab89d7e11f465dbb15e722eea2ead1b6eadcf55eb76cdee2dcaaeb2",
"daeb4b3ae41eab84db5c30d4032541872bd9910f36c2f3708467b640f3d56217",
"8340ac58b1ea529e8f4f0bcf297dc402d89f412252deb830d9e6ea626ec2221b",
"b1a09ab896bccb3a2b2dd487d97392e5a3de1f2a8937cb30091a5be8320e43d6",
"772812821e2409ab4b668507b3cf42fe3bef220d4970081db69cfbb992c54a0b",
"af59ff44fe6084dcb0f148dd58429a66985c8f445d58bf7d734ee5d6cf80002c",
"308def2d531cbe674b75dcc421bc3a5ef9d1ab5c8df737243643b2692a7280a6",
"e207877fa88deb5ffae9b19ebc61d0ee6453d6c7bf911aa01263030cfa64f8a2",
"eea9b387577ce6c76eae8f5d2d4fac9de61dbfe4b03382024a752c7f90a8e366",
"ebd0fa6d638bbf5ef8948054b2c2424d490b16dcf19ba35801c25cb388a4004f",
"0f41ea73a5debb480585af132f3910f3c7b98a577fd595882121631431af470a",
"4dd11303be6ed6afbdc8a9017827c6fbf2fa8ea263117a9f08f09284559bd3a2",
"77dce608339c3e4933ebda49d99d52c3eba9e585f81bb6b94de1eeb6c4f19aff",
"e6bca493413498ac5b2ecb083cd17687e02f2fbfad5da93d4c31a02c9eb72c81",
"4b7eaef4ba7578f43422618c729ce5b1d362a11c437f4d9693da8eee9bbe6b01",
"0fffe2e60e034ee0092da0c22f560bcdce5553fc95eaf8478c3aed2d9713dcf1",
"d7dc0f79e6077711fbd11be2c49a57d984dfe43e2357de902f694f561cce6691",
"51cfd0c3aa1b96da6be92c65ef7dc25ac5f10236b515403cb7f8492791f3bbc3",
"309d74e89ffd04cc8f050dfc4be50085f197f6c23ac5f84c22f79a2729ca62b1",
"a139b028838d489dce5fa08da18ba5ea10969860dd813eb64c755f9f8a0c856e",
"2987cd385ac6ee4a84b0c2c472fea3828306b7addd11cdd28aa416ad9950a9f2",
"97e9199855dfed3d4fc6a8746ed9dee32586d73066e024e8a96bb124a187b3c6",
"d5aca4fca7529a7917cd26c7710c20eefad94ab118b592db8fa22a4c258e99ff",
"08a67a8a0f262f70e4039e10091a296fcc196e9520d5ac37f836ab109205181c",
"e71586f3b63c70b6d65672a7d84781aa67ce0d70f41e4240f56066ab67d1baeb",
"f2bfba19ad8573d2c7d48527ab2cc275f91fe08d82829908013f53dacb9478e1",
"8af272ab08b9367911a97394a580c59d6e6ffe763aadc619edef7c3b827bc927",
"8980fd4836c9ff27cfd5a999fa5a535ca557e32adce854752addef70c4144aa3",
"5d976c7296257e3a0b8411bfba3f372f8d35bd7e73ed92bc26af88e322177178",
"a01565d4915e7fb6689db3f1fb7fbddfc9e8647381c115e1c0a7b1490e8f755b",
"a8fcedb1c3ed358fc5305bdc8b618bc0f354781472eccbb8960c8ca3a0f3233c",
"094ac7a83a427bfab8eff10ecbce65c26670bacd70c941f623ff0298d354edc3",
"d7b2b22315b3ee15e124dcf4560d3bea585842f4163daf0b879a8b0c55390637",
"e6e8072a24ab7bffa9ce6e9a359c33b210e8b66172e1d35a5c8ed28871c40029",
"39c1bcabe1c30d0798d8bbc275d83a503299b08fa2935552892ce03bad2c0bc9",
"2ce057410a13bb152f276afa305eb94e0e31c5dd82a2eb828d0a01710a276756",
"86b8f99ed5240df548dcd85fd87fb2dbc78e21e117524eacebe7ed88d7340a8f",
"0ace53d368852d27daea0ec59bef8f1d5088ceda03719add6a02bc70e3aac785",
"48c7e89b19636c77e186a093b1f2946ddd692f964ba6f2d2ed136b8c2f490566",
"6d9e0dcbe46da467509a5a8a2aa709a31d47795f9f3bdb3a01812ced98dddd5c",
"1526564dfcf5b6ae528444ee7a260771bbf30aa846da37d07dafb1d743c9f68f",
"2987aef1d875722ea6f1684883eefb0ad566fd0017b7ef6094a1752e2ba68550",
"22bc33eea0b2fdfd447021a90c90d10d24652add142991676418a72e8151682c",
"0d72148b5f75fe9f6e36c5f042244bb5e35a27b62777db7ca1e1072eee9a8e48",
"ef71137c514cfa65fa5fda9b517e3c267a9c7a7a7fcd4b9177dad57d0fc2add5",
"11efa0f3f84cd47c1cb0c2d4634f317202ce00e52fa18468910a68cb317326fa",
"750711ec221178fb1ee7549333d5dfa060283226953f9096782c24cf78771345",
"9d621cbeb49423a46c56581dd621246766d6c1d2e885f38cd36ca18f88c6966e",
"e459b29d49a394e84000903ccad0edde2b83096f73e93d144cf8a4fd041d37bc",
"902e39fc44a6a9a712c9d42e0b98a08f793f9eb468ab13c120c87bf6309b68f6",
"5fd3dd562fb5d0c97a66fc5d6f2d047b7c12e9518b95d6d4b96d3cc649e893c4",
"ae5a35203af76d78f8d4c506b18fb4e1c67e5798706d7a1b98912e9fbf6669ed",
"8806e940bc2274296217b392b69987b4772bac5aa5a96980a848c1ec769bb8d5",
"bad155b7d45404ede0f07382e8d74d344dbbfe462c8b3658dc6ead106d418e9a",
"fcf3012d4e101fd7affd972b1768ea8200fddce6e0fb7e403e4fd9ba3f01bac0",
"8ce68b64c7b5675e0663e81e61c4b4379cc5f8845dbdf191031b591a0e10914e",
"ec2253aabaa2731500b94ca5b60c8226e405ea23831e87882fa127cacbed1e70",
"8333c77cd6b63b5e538dde44a5f1c37822c5e1259d7c6674ebc98d17431720af",
"abecc9a68c658a5c31008c6c594d581d36fee313f8ec2aaac469f2fdf4525569",
"e4b493bfaeeb85f35f83e84a318b3a1df7df1497ba1b03b498099e747956ef52",
"8dda479f521d6dfee106e861380824d6d06c770d1472a189bcf251a1bf0a0f55",
"e38a654a52e216ff4a200af142e4a8b9c38c448876b70b84dfc9de5211ca7024",
"12b0bf0288ad6eaad0392192143f5765bddc84d7c99c3ce7e33711083251e878",
"98055e28a5af0dbe2cdc674820e18c92a38ac89cd2b6d3e2f87a589e1f054eab",
"8e05d03fef5e1e2f69f9d4fac674d82e351e34106ad29073ae9490e9ffc15b25",
"bcbb675310f133824ce336a3c43f36f8f6bc1dc9be8efbfe3e7270fa0e7eb5af",
"20af3852b4aef5ea3fabd3847cd03c064cd822b30b5c1652b91b414d08704fb8",
"cc18a3362023966193c072630da0afe74cc08d9eb767866d85c557e6a6f26387",
"950e603915e7fcedf0dc158daff822db034c0a240f7cdc5063bbb428d1408414",
"12658fe8bebcd857c22f584c8e31d6172a87f089e1d883130b7dcb4c1600518b",
"661d8c02f86e16355681f3a682aa0efea86a985ad29e2b64b343f5315a9268b2",
"617a333e2cd2482f83715845421a1e25506724d4737f7bf8dbe9f3faa5a94aa9",
"1cf208a9abaff984c259300f9345c92683eadd83d11a6a4024ee47b3b4d1d045",
"db15ccc93275a34f2728c92076086f0f4c7b2068fab2b009adf7f0d48bdb888a",
"befb08a1da6b7c3136dca3d29c7c0c853c2d91644e55e4303cfc8be64f699538",
"ca3755a1d62e3b4a74fc458daa9a7faa3316fe7f6fb40a62282e9128882d4675",
"4fe123bbaa5d874195f63e85aea06ab08355e0e57f2204308439917ffb080a92",
"cae10b8938dd5806cfe5ea1944b39296a0a73b5957a82f308d9141558b21c6eb",
"124dfeb77b60b21d782aeb2e4998ef15ca8755a3809fc3420b1f4a7125a1f4f5",
"406e044140ce58e8cdf36d57a41892fe4b15a16871f8318afb4ba0ce43365b5a",
"59f62af4c197b3ab5b58998677a39f42ae62738fb962f775529889cd7db10925",
"7eaa2867fa01e79b9e64e17f41df246f099a3f1ec05f9feef690274f55b00182",
"3c0125bf287ec0efa250f7dfdc4f784a4b11475e7bdc5ecccbf7c6dc591d0284",
"06b9701560e87fcad9f9f9eb761b9b78bed1eb979bcbc252b9ebaaa465319a2b",
"64bf409c31578efb2717df97ff8125c218e5b2740cce771186288de418110e2c",
"91adc1e2ecabaa94988334b107b23a78af49d6cd6a8a7fa45dd0a3de7e7a5bb5",
"99ae7e7cbf973d9eee35901a95212ced0cacccdea07eac0d88b5cd29e980b956",
"563e70183d98c899d0f0fca96634f77ec89ad4bacb3f52ed2f736555149779e0",
"7f01f980bfd6c3c60f3628d61afd9bc5c92f50998b3ebb0813db0487d2c23f56",
"aaa5cfc4028fa4a0b2f1303372ab35e5c4e4a6d5816bd6b819926e8949a4bd73",
"52968b2efd496a5de2dcf26a6502e8c6c74dd1249a40723a17e84bd331dae9b6",
"9137b4da3041a7e4a3b88deffe35f371c0d8f746867c9959eca986d4a24034eb",
"1d81a4be4ab49d3baa09a94794061d770bd224d3701fe00b76680297ca819bee",
"628cc2eb26c7278894ed8ec317b4c60afe8ad5fda359f151300e1501d6b27091",
"cc9378c99c54db8ea7cfa4261e74349b30e53fea0232dfc65e595419b7311c78",
"3f3a959ed7bd378b9ea2822b166760ececc99ff65c340e9a99b550b4e233bc38",
"234aeab4fff850bdd013574828def84a96ebf53a59187fae764d691c1e16fc9b",
"b065e4e7d29530028fe92e1f48fd4944cfbcd4a4bb1aeedab43866b694f0fba5",
"5df39fea0e235a747476259f34f8b66d739f9d7bf47f50c19891222fb66ed6f3",
"67fef34becf3a89191220819e985761682583e9e2fac7fcce2181843e567b13c",
"587293d74305af4ad1bcc2d88f6ac16c47ba265e3ac5ffa5f0f6235ea8cac952",
"36a9a03e9fbc0237bd52ecf7fa23626d8ac83e91d54cc0471cc9277929582879",
"78a673152ae87540f2b3a38ba47ec5bd5cf047da62cd6be3682a723bc87ee1a9",
"8b48afe535024d84514d81fdea58934ca0f23e031565d7f74d05ec7a7d946801",
"d81ee7e407ad1311d68f0b53994e6fb68131c596735329f76cb4d18c4ddbfb77",
"16be4607f8bee1e191857372b0263ed401bfa173f2752736fbe50abb7e58da98",
"d05083dd5e6d5e0a2c320a1752c724d3a13428b9dbd2833fc67c86628f6eb1c3",
"0b2f6370271a17242d09d0292a1e0344d2806cc89e8e6e125c72ed47317171c9",
"aa1332229c78544ada666a1e7cc54fb5fa31c586370de5388bfadd86176b2250",
"d605e3d0ca62ce111f73d2ea48c5fbb56c5d47c2bc28eb68c398515703119072",
"9e0549f039e6c530dc1432adcaa40a3ee2d69329fe1a2245c6c0461c16931eaa",
"cb2f3789ae09d724f9eddb3f104e755ed2ddc3f5bac87aeb91f76fa53784e881",
"6e3b3835f989decf5441e8c524aa95b6b312d5732d614fe24d80f9dd39bad1c5",
"318440cfef57053d806d6f9c03c1331947018cf2f479b71d9f5ff4d1bf940ae9",
"51050b2569885e0a61fc2487c8428e6fdb8861727de7e8d97f7901e6f583acc7",
"02e37462d082a033c382c04ec6d90c629bd96cd0379eac6399a718d9988bf3b9",
"3515eaa553cf9f35d85fdeb367eb3eb930a79dcdefcdaf2e6eb00c550deea9f5",
"1321c47c060f371589bf9a1dc6557b9b49434a4ad6ad15f6749a2bf71e26ce14",
"627cf526b8c336e3a3d8c3e82e5503fea6338f14a438e8de6bb3dc5674a10da6",
"7cd3b2289dc1190b6ea21b9d011ec5574fa251d222af63a52bebefecbd89d7c1",
"9bb3ad4efd34c6839bf4b641d1f745d8ce60c829f22b773de0fedd566c3ca60d",
"679c477e999ae78bde65ce99acb6c2bacbcea8214ba4b7fd477ae91b1d21792d",
"bd3ec90f50cdbfa74372cfcee0f017fe7342935eb93d9367ca277dff7b02eaff",
"6a73b3ac5c74db3e940df13ea5e049432e2488b3997767dfd700e9aeb34f9cfa",
"a642e0ef2b4c17cbacb868ec0ca7d43ae9cefee5e0dc29e59e561b44aff05615",
"1a77398f0d8673a9fccd3342338f6e5fc1e96800beebe04f4aba48afdd41f6a3",
"d2bf9e00bf6050ad68e7a3ea1261b3c9f9b6394d53da2f9f1712199ff5fa96ac",
"d17c0276250825f6c8ab121c999c61cc892874488a4bc95a104dc0382e511aaa",
"7be2cb478a857b81957d7169a01c6692a254e7b029b42995b6c262e6d30f0038",
"2af54e9f62193195b0b927462e63a661c5abe69fff22037e047257dd41089646",
"120849c155437bbec39e71267d3320eae464e949c7ed1e812c91f3c5ead6ba1d",
"4d77309ed2522ec89b7e8e0f0189cfe9124babae465007ab5c905a9541d63a4b",
"4eebf5a0cca448832d9a5224a39250ecac4a18c650baafe2d8804241c274dfc1",
"5d29b8c14ac83e531b87534ef17531cfec84f49c764e6410c8d5682fd80204a7",
"625d9a10f136b103e85f0e7863df74db8049f77a75e52361748873fbdb2a3f73",
"eb21a9d33e58daa0ead2dad3a71d4e5eaa7b0321c6cc2d4e86464c70cf366634",
"6b9066c0d9049b0634edf92b34140d02a49e7a6d76483d14c32125f3ea41d8f4",
"b68f5ebb20554bddbcbd92371c4e536210a0674e61577d552b6b405939acddfc",
"2f8fc98373422a6dce98f183f25488520794b45b947c18ab0e1b924dee353b61",
"64643340086927f78905c52784692557869bcf723b2ad19b69fd0349601aa7e5",
"39c72e17874ba3a3850231ad77319c564e5fc1f23414c80d0531f8e618895ac6",
"9e2afd30de5bfa30e237d9f2f773766a82e20d1a7efa10d34e37048b172d2e91",
"c0888a46377fe1194a84313d3e9f64e90cb94648cbadc93ca1c077960b2946bf",
"c7a54836aa914f27df8424e40d4c42183c7dce32798f7964fade258768beaa4d",
"485865c169e3e60c2b0cd97fe7caf04bb5592a9a08c5abf53de92f5fa745845a",
"77038185b0024d9e2e0881b8d57e4dea0b59fcbd2bc2a776c8d7b29b5356a240",
"19be080d3f5d828b2826c221f35a07200540c47c5bd5c374175f8d1b55dcc8e9",
"32d5a77433130085014cfa02eb0b0ff36be96763b8f100502ee09a93fa4a62bd",
"9572c95caca053688f8cde1436a7d5652f1bb5bb4da92dd200df11d2a27da378",
"b3db618f9e7680be0c485377b1f9e874798b5b9cb2800a098053b025c47e70f6",
"67a77a0cdf101d5fca5d17bf2b49f3c00632bb4a53c4ef06617762f36c8c8e07",
"1fff3805be7779014868c91462838db4e8f88e7759179f144008534a1724fcda",
"efd453c249b898711874f643c4b66efd58e91ad5b3aee1aa6ad7a477b7248a94",
"bf94e5f1c7b5c8483285a8dea4345e7519581d486fcb27a8da43a2b48be22346",
"7ccb34279395a288bc3ce100245c6de77fd9fc35956f9ece35e6475bbd6f6ef8",
"810ce536aa750b60cfc6acff3ff65b36515f60c1abe5816aa5e38549b0cf21ad",
"be1c2775730ae524f44e05fc989ea33b24d262db5cb630cd13d56a2324f8fe37",
"7b8bf85e45285fa4b800e544da002c0c43c2b87644dfb62c42090631c5abd1d5",
"96e286ddeb65c5e54b4a8325cd695b53f4aff1fda635ce72c7b14ce1e926c7d4",
"12e0310edca52b08cb8a18dd2e382da62908b476f14b1a8e0aa993a945e84399",
"e8ceee44ab4241cb19d5da582abc8b9c7ec4d71bbfa456bbda2d3dfb120c1e82",
"e3951d2637df7a24c3fb48360da87247d998c9f092d7ebe349bf5b493cf89034",
"2657c928cb139ac30cb495a790e8a125d452a541267e71ca1635cb69d830c349",
"4d0fab3685c9e14d8382253670d0453430010fdb95da9a0cf5427760ff8f4bf5",
"85a65d69081dc88743067a1ae0f5abef0adf79ba23500954217f990bdd17246d",
"b3d6e83386b11a0d736d43f1eb3235388abdfaf2c90e94ba02d4c50a3c830a66",
"f1f207e702a02318635f35a70141ff96d50b1058f57c01f84fd5973112eec5bd",
"10e412a4f7c37f47b63d39cbde4721f65670bc2085ec8db8a6ebd2db0f19531c",
"a7679d3b0d86f7d19b865f9c25aa91c1bbcfcc89cac3415138393f68958699f2",
"9be5b69545813b368cb6fd8e8e2f0843a3299c268f3c78691d62f14cc08e1fd5",
"c7ef2594ead75dd56e8effb151e72c72efd2e3151c22f113a9952c2d2a094ef8",
"43406fa30813bf114ad791f19f91783ee623dbf5882e9361dbb9dd42dcc124a9",
"f45c2618d639e25d60a6ff4e3d3c54aca3afda8887feeda48b3931d5fb3a890d",
"021d36f9b63ae9509a139f5919a2c7c6daaa8b775b67d175d9fdc2caf1545247",
"221662e3384acfda6b419aca64194a7e2b515c470eb515641a43ad280f5d8c64",
"93a2280c52123349f7143d8f90b8862985eab8856ce01c1e65847f74e82f3585",
"97595d2f3e15492623c1180c3448d91e27e8caa91a2286ffdde6e0e01d73487c",
"554e51f4e422d00765369712a73dbe5e18c4f59aa55546b9aff3f1b94c8f75ee",
"373c9b4a6fa3fc747881123d342ad6fd4bfe280c1550517f329e7b5fd9c90824",
"5466a29fb42efa17c090eedb46bb213988ef7656634eff61d399c4540bf185d4",
"68882db32387229d3c096e4f075c9075d1128759c3fdf5e5d8bcdfe24072d559",
"f703f98c5b75380e73f861b3ceb685094aee6341309d5161b761fcca78acda0e",
"59f93b2d63f4643f566199a92d955bd78caaf7ec7e3078fd5264f5b478ac09b2",
"639731cfd7ab582be092da8ec8da53718c206b8f0fa5c75953fcff3cb116a172",
"2bfe2a097a074fdff140fef54c104953996a032dc162edf32dc357e09abb3fcc",
"466dd64bfa5468a071705d8b3f86206a481673ced10e0a4f172d7486cd29e8ce",
"a40e511b719b6275dedb1b46f2c5f8b0cd725312ab239132c5b9b29547f6f764",
"6583f450fd9001e5355551acb58a3c95ac663f8f58a82cc3f9f31135fe492442",
"2a818d069c34b05be52769437dba3051f931aae1b1453e950c591b3920c3b3ee",
"0b26d32e1e31400f4c3a5e2750fee52239b2dc3728f927ec455ba49fcc16bbbd",
"7d90705556fd11248be8e53c04bafeb395b123c3b42d3e0e07f02ae5bba74681",
"79ad2329c40c96cd2e4d694d51d2610b8a28971d6b253f5a54c22301afdb293d",
"147eed7b0ff213c3ba36f679ba864cb2b050de968fdedcdcb48e6916bc264574",
"d027dfcaaf6e04f676c619244515b823e7adff3dd01da6730342421168a61c45",
"e2199dbc29264ddf0edc446706d684cc19ab7c81fd19f2c25a6aedfaf38bff61",
"74219656debd84f572508135fb03c4ddb80a992c629a1483a4b32535156ee1b7",
"cc6b74e9616a1facb82a483e19039348ccbc6a387a3c6991f50133ca844bb499",
"3084b541105fe892ddfad7efe4d428a8cfb5890c6970d4c4d05bc1b1e7ea38ef",
"a0b5c69bf883147418969ffca6cd45e9f710223b8da9bd93d77ce8aec76d4bea",
"e08c7e844d6fa6cdcabb04975fb6c66ceda4cadef3b1e4fad7367207d674e973",
"6033e2342b470e18a442cc73eebfc5e77303cd4ecb3507930f777cd2fb740a15",
"3c20d132ea8e829fd8fb7b18cf5f9a5a71dd88bf35bc81f7cf37b4ab4cc7b961",
"0ee98db4b01bea147bbcb1bd492a66c85abe9e20985738bb5a035d587badff8d",
"bd78400ee797aba19c82c3bf060a13d720be4cab6358a39075e1ad721cfd0b99",
"91c0f7efc5e43eefa3e587d1e2685bbbf68a7b064c06da9b21f3e38be2f8915e",
"f0c2ff1abe61e4c0c3092afba482e7eef6f0744c267b5334e060485d01974b18",
"dd4d830bd248066832624a2a5ceca133b9f5b9fa66c1d3a41eb4cc29169f955d",
"04175c02b43883fa4b3c4b990334e2c3e23e85ddc36edcf04bee9f86e8a116af",
"2eafcbc1db5005dbf74c90a56554ba71201e21d21ef4a77094f4b1c6c6d10497",
"f6c826a659eef7eca7685ce1e574066a007906163041aaba2ac90a12f0315660",
"2dc4d5de794e832b499f493c99fa948e10079f74552f23fc5d3700722e8d0f8d",
"c02e4905c3876a3fa382c1a7f90cf91496d66da1b2495cb3f5a345993360280a",
"5a375be2718ac37a38ee1c84b84476695a384e2a2ff43068c8d7989b4fd3cea5",
"b70b2e6d667be606bd1c511f7e2cf631f533948cbb5af26db8650d4101253f63",
"35a49d20ab277ac8c092985c9faad58320d1af7427124c4828888f4bd7491b36",
"2a67df5cdd3e8c2a1241dfd24554af46feee6b138b4809663f86e9012ec47b27",
"b50c7e29386970d39258f395e05f3caeb8648d9a40a0c14a603ba1e729c1782e",
"0db1d79fc1686e0388b8439fe7331862314b77ced506dfdaccc2a21faf74f44f",
"6b3393eacda7dc18a2ce451f2541681f5dd4e9af21a2624956542b60268a9405",
"8e17ed5e690277e1156294c6904f6899de1497d15d8862a98cfe349c5296ec13",
"e44b9eb141e8ff07acd5bc5a2fdd6d334192e27b27b5f4c26a225ad28cd9ab9a",
"02b6fe45acb7af83932640c81519a7cf4d33af40e8c66510855286f1b869df7f",
"c8aff4d8670456d4e64051e65f018226f7abcb40dc77b7a36a934f4afeb42888",
"aa4a4dabb9038bb1bc8dafa93397b77b81e263fcfff59eb86c07920e6c8c218f",
"3b8203b9ed708044720313b67f9b98cf9e96544e95ada0200bc4ea0e54a3c633",
"524aced0165da7aa4aed8d02720276c3895a37fcfd8db9cffbc9d353ccc960c4",
"553fcf8e9e53d37da153a4f8bfd16a2c5379da0472076719b05a26d10100801b",
"fbb7b3e31f1d0d1606dc34bf1c624db7c62133e173203dad5cf4c3792351fbbb",
"e62eddd4a815b35bf6916c615a52f185395baceaa52cee8a836de3a4db0c5381",
"9ea285ecbb3cc9189511d2148e3d732bd98582324d2a597ccb942e8b0158548c",
"6c9ecf00a9f605bd50375d0793e8ebad382060daebbbad0ec1427d5501b95186",
"00a5392f9bf5114694596652d3f47debb758a1ef4a408490688a8b3b6f4d076d",
"c9d5bf16c017b12a95d62a92b270c9c100fee78fc85c91f830c56be00235ce7f",
"68ea43f029fa915aafc14bfa5eb8ab1ab1e6e20c467c0985dfeeb72af1859659",
"172c4fada590aedd1eb45a16ca2ac669cc0371f12aceecf1467e0dd6e2af387c",
"0e8c60669d5b505ff9f6fb941f3247bee6458fa1d6f1829c1444135c55b5b58a",
"83e174c96ba972dd05b14f9e7d8dc0923ad96cdf6b2926c81baece8c7c3ccbc0",
"55699232a0c96bd45cf5bbb81ae2e033d22b534b2fcec3b70ab661d22bc25b0f",
"9d4ba8d5cb7404ae253587e6a583c595214407007c049988a08b51e8c05a67ef",
"1d63978b718b86d8d84bd1f6e7cd053fec76dbc922c597abeeee64066d02b57a",
"6d03e10f0787dd16296266414cb6bacb961387fbec686348f586a4d053718f02",
"e4ae9203d1b61a37a98b21769f110e46de7ab6772d15b4af93a9f39cb2d096a8",
"a5de66a7fa9666e03e6dd9e114d3cbed11e14454758fb20f42586685509f315e",
"f0accba58611444a9eb7c3d41218740ffed85556762d5245f4d1bbd6d958d488",
"95de4a732eaee2996786c28c3ae80a7bbfd34ad276694cdd64194e7d45d6b1b8",
"59b03bd978a4a5ed212fd094e90048aca406d16c196410eb8be8122f2856d1d0",
"2b6c3018cfd7cc55746864434c9b2c610a4971e60d9128a338451d46c78bfc86",
"2428da7b24364be8aa93c6a255543d7da27f4cbe57dde5f14a8512fa5ffb981d",
"bce26d655a0efb6f287be49da07393f30feee6bb6c2306bbad88e04c8984e7d0",
"0fe2ad6dbadcd9c423b5eebde12b78365ff1c4fbc85e933206523afc2a2f8a48",
"67482decfd58bdc49de9ec5a8147945130a928b98202457647c66865ca336c71",
"7d22130b398f4085766f4909a68b4f7fa2c4b26db1e107f3a2ef29417ee5cfae",
"98778612b5124e3d7d455f725f4f2462ef780f0323e0c36cb9bc81811c00a045",
"51e7511c0f2ef6bfc7e17c7906fd604e42e862f3f4475d50d86bfc1401099d0d",
"f120fe5e0ef2b223977b4519069cac7e4e77c587c5b011663d06aa08f80fd477",
"9d00ace943765ba7f2a3a414f534d8e751af83fed0f8e872c36b311a15ae21bf",
"93cc266fd13aaa341f03d20115f066cb126497bc0d6d5de719c9f80604a2e57c",
"ddddd5d3636ab27be531f09a9a93e5d8b39fb2c03a79d4b7908f2b40b52bd1f2",
"626c9f4c4e3bad8d65523b0f4b820f4e59a720007fc35aa925bc99d9deae3e00",
"af9d9060c20e16bb1f94b3da86b8f4c074c472f2d402ebcadb879d9d5853dc78",
"309db5e72eed85d70fb56caffd8bfc1dffb79fb9b599916468a68982c975dca9",
"0738d677af3228b95cf444baba3469dd67aaeba54a93c91ae62845d2ab12bb3b",
"720666a5e21383c6546a87b8cc93be7044c87c015ee2995f87b55bb291e9924b",
"21d91ecc9946962e60ae1119f45687a670eb725a392425e3dca05d108808a314",
"253c1ba525d54f4075c8aa01ee5383d0ea6a41b62d243fb06d4f90987e557578",
"73429a7a5981f25624a1ea521c95c1aa4e744bca69c6b63f495e3c72571d403f",
"e92100e5825a11d06c55a544f83e71a1cb86516805549d0d16c085a690645682",
"3969b8d71699943cd01e410fb2b072638ffdc59d10eb3316ee12a98783c09181",
"3dd6b9d720af724e3bba14e7fc41213a0c6b7fd5c4a6d6081cdde8b05941023e",
"a8c6b92481b9b52f50fc996f3fc023f720b832f79f306aebe9e1db5d5d680f33",
"84bde27cda62db77fac212cc9a399467cf466e0d5af32984b04f389c28e6b0b6",
"d416c534ceaa07ce856d3fe9fb6d8cae21f28aa45eadd4fee27b791e69c8f045",
"0b370fe3369b09d22ddd43f870a428c4b65974430a18261c59781ae77d941480",
"906ad75351144066d6d0d914c5145664825d2004d778aeb41aec56644f81ba25",
"3c57221b786a6de68d8d8db9db8ed3928a20eff9e688ad1121d73085a0fe9d75",
"e1c262992728e3ede684e77f4a06efde3e2eebf8f12a0406dcede1aafe299648",
"c60819a050b2d4e6ac4d72ea6683fde04dbaf6b66bd74ff988fbc7d2b29b9bf2",
"e8468896b3f9734cd0f7c721ee0896ad1548902340242b7fdd16e39b361c4ac5",
"6a8f24b12c66adc9e771cc6b52392688bb8535c1ba026ca7f79d26ce2c7ed9a2",
"f5d607b7d774d7c5d81d6c8d58b4a7ed576403a4dfce8f2e63e1b7ce9c7f8a02",
"011d439d089fcb3c7d44c2d5a6420cf60cf1b8716db31286f7c9ce390a0f2fa6",
"d6fe9c609aefadabb0efff44e5375ea4eacc5237c21b58a2e199cc2899dbfbb0",
"3a0b54bd93d3305354b07b6bb7807bace50476c4e120a0b327de1cdb93617079",
"41e55404a5998f71571a200c032127a6241b2e7b232e82147fb6769d8256bd29",
"5756ac43c1df14927d3af8ef161c403ee1f92b1ed296d0adc72e2cb45d98d7de",
"f82cf2b7895ba7802d0478d2b20b069d3c8500637fe98d4194da02c884cf9d17",
"3a10b6cc7cc3bb244fbd0d49910e588abe7dbaf759d4cf44783a7139af064824",
"5a9b9b31eaedbb651f42d207a14b502b4b73885330c37f8e615ad89e3e61213b",
"e61688578b28b999d906798525736d64a5aac1b5544b7507badb20b34b556d8c",
"45b27a6ef06340c3ed81433083ac81ce99abcc951f5e334919f3ff56cd1c75d6",
"fceb7a9bd727f1e8438f617d02674039902f195dcbbfb01b43d5f72edea02831",
"d19c5e3b8aeb8f8b4c08ee8b61f34277bfe579398a76e28e58b972cd69089b61",
"a32c7ab77af334e2d5c4eb3caf95d3aaad689f28a2dc3a7557f2528be402407e",
"b6c17c21cecca5ac92a1fdc1032369e4c6d9cf2fd4f1d5b4406e1d7e7606b2ac",
"be1b81276adee2c0f4df4cdc6d1b82df87dceaf516b7e4d994e023a937479f9f",
"439251ab04c231c48b891702a2061921fa88cfef44741ee173853b6bf8490430",
"26b7068c7272d9feaab03fef3083e50d49885e375f77792d59ff0cd502c03df1",
"85dce2eba1a9ae5a41d06854f4db88dd7fe022727be35ad6b18e6087c8b91f1b",
"e4f7178d36429096577518bf47e2d296c021ae7349aca78e2c0a4c606acca5a8",
"e8d88f547187b278275c799b25a94d814f3174bac46077df9820a338b4d9c267",
"ac8f48385b06e1c43da7fb74e522d347603b7b973ac3c3d06412ad72f5762fd6",
"22f39a936e8e401a404457cbbef921c3568ce016a5c75de9256011b988c252c6",
"77fa7038e7ded01577a2ae592cdc9663311b5e1e42f5f87ad8a66ae0e9a54c28",
"87f6e5ae2adc65a736c9b1746ec1f18340bbee45481d7c1f5509ad71d5f3c9c2",
"180e9ee8a321a1e91c490cd90afd74d556ae2a9bae223ec6c094587f359870b0",
"f6c87366cdd0be058ebf9295d8b6b42729be58a0f7f057fe3243f9b2949ada26",
"d45c27211e8a4b77a9e76c12db25e6e9ba9d03647f3691d158edbd8b7c38ab69",
"8ebac15b55c4a2c5d3f4866858fe3ab9324bd785036dc0ce8ababa396419eb35",
"6a80d86e69694ebeec5f6f5a5d37d12c2f813147c1116d5d26538d25f8882729",
"2cf7e4c33c2a63ef54c444020bac3648738bee48779db4a3a0f9e72ca5b4e380",
"9d101afcd85b7331d4008230f29b761b9f798e8814d123140e8b648b230261f9",
"c6ee0ade266785f9dadcf6892bf4b98d7bbc292aaf2bfe5b7dd484785760375b",
"94d239b78781096e3e8e7e6a7d9ad70d0804adeb6a6675fc5da4f05d1152c19d",
"55ca49e0e313f14ae0f214ac0a51843158ee07aa5f381cb9d596b8612dbd3f36",
"e3e3672131fe9a71f54a41b0e8143c63bc0aeb823288527bda069a1616a41529",
"ad1b386b668b79c7cada251a6c2bd19c53e51045e4a4562b4b9212852d334556",
"bd08a3ba2d8603332b31b2394a556edf6ef949ec8d49e5d54a13318213a0da65",
"b34731e855ce7fc834aa0846c72ce7f455f40564b11181b340ec07a003787e88",
"ae292c8d03de63af642539e6559960770d80dc4e9590c46f54ab8a74b68f145c",
"10a28c04e90016bc744986e50d2a240ff553cea32c8ccbfc218445d6f9e32271",
"182df763c8b4dc2c1698567546dac90ed5de00c033322c9f731a64f08cf7ae61",
"eaad2e6f6dbc000fe3b8f60fc7ce7011c22c4d062ae2c33a3621098190027381",
"1e7d630f59f8c968c54a803f8c70e15d85a1214be4e0f8e82cab9b2056df4ef6",
"af485e0990350c9814bf8a8b3db91f44d4d459f513f9e0635ff54a444a45055e",
"c5339ed11420ef44af6d7eec085a7495ac1f59264119184d3183a937d7012295",
"ee4c98e7b5e1b5fc19c8e5e75b9be39690ebf15bc9b1e5fbb3ecb75a2ec89d3a",
"c88b24689438c8f097cec81f2178fd162d4c53ba51f1b835c9b7d1f33f3bfed4",
"b3f12ee06f773536bc4882441d7b40153fd02ff4abd97a5686bc8ec294de5303",
"74b69c91d7b24cbc734d5bbfccf3442b10aa94f835dd49e84aeb9fb93d48f984",
"7249af9eedd2ff198a93c9fd96d3847d05fd24e4a2dee3213f8b0157028a7a1e",
"4c663e23616d31135cf9b4c33a89556d9973b2df0fe8b5a851163ce3e770df33",
"4afede394dff0a2b6f0b1b3dedf82614ca5133814c9466e7856a53cf33a83359",
"b7f3d596f87080e6fe4b0c5e17364dc87ba269ca561689d20085c9890270145a",
"a91c666326b9198e9954c4461da9e173c21042edbc8e63e6527f69aa06144ad5",
"c11375b5ba44d9be64cf8ccc8eaba4689ce8d0a1d75f4b932d14b4e26b962ba8",
"c737cddd051af963d4109063a7c98bfbbe500abdf2761545fb2e3f592f1c3183",
"9b09f03742db7491a7a96f20d2735d669383b59570c919c5f8f4d804ccf552af",
"112ba278ae78125b0ee2a9ae9d4c857d7b09d3636d8afd9e175a3557917409f2",
"3ec2366bdb151bc04838ad4459790d217d7e70104dbb6a13de48c8e97873c874",
"e592d021807bc768bc2eb1b6b7832d7326565c39b82658ce9c340ee50a443626",
"446de54c9e312644e2fd20f49b8d9926edeb2c995e627414da25b664f14e4fb2",
"c0e6c970fb25f5ec11f0c76316e7eff5bb180acd21bc777616ad3212edf5cb3c",
"32c3a1e954262361dfea8dcd6d4e74c436d53e6518a2bfd080302187e454ef3d",
"af6c5f72dbd65e75a91a40ba9c6abad575f12b7fd8b66c41d88948fa8e026f3d",
"2f858194e1da082ac8ba94373768de9fa1842a1adba13b2bf6c67474d0a233c8",
"74b19f6456e34582f963dba6d7faebb6289050227f55d5bead6aed9f6394eb41",
"e249aa1cc573b722bfb4e6613dfc70e2a5d6cb7df94ba1002e7f549f57aedcef",
"0ad80c6bbea362b8bdb966cbc50135bfa321bb8cbb0179f76f445dde3d156c8b",
"898f699a5c52bdada6a62d24ac05ec8cb043f5679b554ae5a9b4d666a440fb76",
"305cf536a22fcbdee3353cdf59ddbd42e24ea1a8b91967d5038ca3f9094868c5",
"2847f3395f902b011e2eb0ce5e995cd97af861c925e04021a5bd893447025060",
"91f09953dda135db571d5e159e07a495b0ca9d2eb6ba584b6bff019ae5693624",
"648126d6266a94fd567040da2a9becb5e6be4055f9f4176d252ea8b29915b8a1",
"46451db7b8576c094fa561a81e6d1300220b42b886e3e3b5faeb95c78090e6e0",
"97817465e9219742eaf8121d0d053224793083991313a7b376093f5cdf7329b2",
"4e5c52de7f2d110910f12126b36f9ee712f4a70ec48a86ef10b21767b876396f",
"6510078a1522e2f137600f9183802c1581f882bd9fa0f8f1391484f84cf0fb43",
"2b687ea5a740865b89abc5657546a55b7d5f7fe4e4796354b4b4266f0c0ec10c",
"879d6960613b3138e2a92c821026f5858a99338db1f769923ccb7f32ec4afcd6",
"6c37cd022e745b6666c0388b81296be90dce442972de52400fa3adb8e734d2ee",
"e58f22310f59fdddb90479cc36c763c1fcf60d6e09501d51c495dcb95c033d05",
"70ac02944106daddc97b53db0a0f9bdc1cdf7e789b698b4234a88d8acb945233",
"e797d50c461ed06e255f8106694f1e3c3dff45ca342b631c9d93fd6868ee7862",
"d645d1ce9d365a5ea79ccaa9b24ec597a029e07e667bdd5461a7cec83344f83a",
"2fdc7e98eaa0910fd04914e2ac4c1216e2a4d37621e23c69daa7539b6d403ad6",
"3ea00f497980193dac3261c3e12d7593b1668465227775c53b01e0029a3dbaee",
"eff07e9c0aa7f889f74bd0daabfa20017aeac105fb09d11647059f37eb1027eb",
"69d3cce33ba2f60e895201dd8d0a92db55e4db99b04de54976d3f11ca280dfe4",
"64aef37268e77bcbbda83cb568ba365aa650c4363e22f08ebd9ea8dd4c5ec3ba",
"837f82d3bed0341335bd5ab9d633bb5b1117a0b71664315643f710321451b08d",
"52b1677f38980e1ba9eee33faf8a60f50d76a9020fc18aadad44ef12d102c630",
"c5727a2a22170ed9a40b4e003e7039bb6f51ef719faa103159869f715cd79d64",
"2bd8376008ef3339ad49383a12754f63710ab01657cf717aa945f8ebeb351d26",
"617d5e3734a176c6aaa970e78f412532263398023f922604d69d73a34d7c9600",
"b508b6f323862d1393522ce67c9f267f8f7a08c4f17ec2d7e9230df6a7dcc83d",
"003b1c8857c2366b415d5b1eb23ab8c0705065bd87fe08e7c25114098bc2d020",
"9c18e71750ab5a52520fa5c6f4b48047d34af42b9feedfcfa96a9b9cf6c2231d",
"c3d69220994caf490d6d8f4c7f7689da6e533bdbf775309af7b13b25359c15db",
"64945a074fe5d593413f740fbb0fb036efc1585073a5c769e6b7bba5083bff67",
"da64240fb5aefe994b80dcbf86c6775e1d8b9827c90ea914dc89ed96994c1b06",
"f3dcceebebff82171d500aa5bfa42d923af47fd9d935ff3b24e4246c2c240bb0",
"5e9c33d78cdd3d5f71a74981aee540c199f9928c132f047ff975f9c4528929ed",
"e83e08ca018747334d5bef54eff1527d03fc478a9a2ce3bc1d08eb74b1e05c5a",
"2b4404ceb208a4cbcca4eca597cc25e50c156d1d4320b937795c201bf62e8e27",
"6cf6e54742a3e3a2469296b51863123d6939a3e4f18973bed3350f361a0a7fa1",
"173648ce3c3faebf66b1b400e2ba1d09a6f7a0e90c4f6eb259cf141cf2702868",
"1602f84cd08034833d4d6b6f0a63017840b0517fcd716dc5bb82071f81cacf22",
"5c9a5a89db7ce103784cd0a185ef589967930fa6e92aa90fb8c02031694a9404",
"a99a83be39be7d0d247f3805d7c78f47bf16a3babf9d63cb68e28c0f630e15c2",
"9a92a01899a649676ac792b2a2be8db3ab24f1f464a1af6b3c03b7f67e572510",
"e0448af4bfdabe13a044362ab133a5560a77e8e6605df7d9b36f22a9ccdd806f",
"8f675662f98a9961e9a67114a98f442359b8797f729c94c5a041ebdb937e0b57",
"6dd8437315fb9be06fcbb22ebc82103648da5b142622857175dd75a0f78c7a8f",
"6c4a96d440dbfc0f26f1bdf1e1c0ac273b573c36f14e55342fd98435e806b676",
"700725449099dc98933ea1c8f1b9fdaf21ccb7f7439451cbdcf763e7b633e52d",
"22c986a29a24c02703a8be6fc3a17f00975fe6f323366da8284a4c1070b18160",
"037036f85de49e6136d1f54c2b1f754d61c262bb88c806b72a156e272d60c535",
"8813017f3878a97b15c272982b95b3534a4475dbc3a6f40aaee3eb9dd593eb2a",
"403a7a97d3c47c57e89982086de458cc1c62d01449945e9adeb160bdb487e7c8",
"e1ae2a3ca0a102d9d7b80462c5c75ce1fd49a341a3ae60a497a98c9e84dc4d2c",
"7d3cf5fdda0516c200a2a5d622c256d481f9764d6a72799995e01b31c97f4f26",
"a080f0e1bf33dc8190c844c3b13c56c058ea08af44e1c7363d55e8fd8a7a3afc",
"a611f43917fd4c23e5bb65ba8dcbde6db510142346cad2b9ab596fa75635d9e3",
"ba068f56418356e2c0ee98119cc3030fa7a9b8c27d5530c93f134e899afedc02",
"81a7d27fa4e8d911410a733248f102e5a9eff4d8f5617114e97c1267cbf3d348",
"ea711ec0f66cec18c17b3bfa39967b00480a0df0575412c0e8a7aa8869ab93ac",
"dc2efe412c0c7cf5d7e838641bdbe2d59877ca74357536da58aaa0fd1b711ac0",
"93e321c3371d69fade1451f2f537579c54934aba5271a018540f70d4ac91a78e",
"8f1368dfc99618f3e1b2302ebee88319371106bef78471b0eb876f2f06a3a818",
"5fffc415587f815bf9645acdd481294fc4d83ac5b9a37275e8725921eaeed7f7",
"3f29e067de0e036efd2684b9c54e0e6b2787fb9d83504c1201c4d0a017a0785f",
"07f4a000178a78a4a8faa370d5aea0aa5628ff669522fbf6ee0d016ce016f8dc",
"773ac8e936b1618243407a82d1ec9a6feaa5ebd9cbd82619d19b5bd7f0297536",
"af56203cef3a9126c3442d964fe09bfeba50d9243fd9bb87ec38a961c59b5960",
"fbbdfc94f38b514470de4290bba2ebdff7aac5523d97a0abbb20859ebc82065a",
"471ab6bea6f7cae837a9fc601f70c7c8e53e84a544e43008d945875d61df04ad",
"e20fa6fa46cd4d80d54d393c86e49b282ea1526c5f339e579bad5b39304498b8",
"cac629d37126684710d0bb74fb52d529f2d16c73734f2005de6de9a504ad84ff",
"a953032ffba659a809d5f733daa9db681082aa65dd08c0b05664dbefd87707ba",
"5bab2244233e9f9f2d7191dfbe1ac968652ea1bc0fac48a5557b01c40d260f4a",
"9d09dc8281294423fd516835ab30f15416cfd011e74dff4bf5e05f87416f0cf6",
"893776d2cccda1f86b0e405d13a75a11a96528a45e0872e4ffc0b87513594100",
"758a1e6461aeb3ffb55c231caacce8f663d83eef4d12f8cf94d69b09252b6e06",
"0dee497dd3a7bbc26c1b2b2f807e55bc62765b3557cd50960e8b913a2e3acdba",
"35a08cc32bdce97e91ba274bde6d6f19c74ae3fd3566cf1c40002a0775872505",
"689104a13715e4e881a4640fd5e4bcd46687c67f53c91db4b8cae8d21cf90722",
"e48d19e8a8a211358e7e7ffe964e981d3a1d11ae76a2b44a44faa856566abc5b",
"28d7c2498774be7540d3b85cd67e873db198267ebd59cefb1164969d56544940",
"8440cbb16acf418689ac4fe6d2b65ddd949e96458542539d30bfe2125e3a88ca",
"6f837c7e4a9f4c4c1b17fb202a5bc7479add8cc0d26564766328f77455627961",
"fb786f9dc125141f04857fd1393abe9172ad9c3aade782bd4d8dc23018c662bb",
"be101e3278740014287a572b2b27fe3e20712bf589db356e800fad1e633d34b6",
"02770ff50283c20a9a9de291de391fe7ebb4744da607a7780b10a20c49a753c2",
"84801d626b5998746e0865aec4fcd1378bb376edcc763a80ee96373b01cbf72c",
"1da1dd3aa77a4e2d8aa0857ccd857d4952e58ab49c26a1f0cb60275030f6607e",
"04fefbda5ec9f182c2a22ad6bbbc42ffa322338e3562976b8d32b3406c2e38c9",
"e8ccdcb248078a482359f4f7973d3b2069794b9777c4e2ac21558fbffee59c8c",
"51507a05fbdfcc522a1f29099cc06458591bcd5809d2b210901e275dc1daed7d",
"05e6b311d3a3241022b0152924627706edf857161004dc785983c5c8e4059b19",
"986ccd7ef43c8085b738a0e2eb84b98aa920fd19f372c34c37569a5c7354d6df",
"37c4370297131fcef6101bb43e37ada63ee4c63eadd53c683cdffda2c22b6a5f",
"c8a736669a5a1c69c6088735306b2aa6da1fa685584446b27c53612344a28d39",
"0c829d4a74a40e4338a406a268de64a9ac1b58ad2f0655cf1412cfe10a81f128",
"ea8aeeeb0fcfa66319b5d1560c1c7e805cb445b678f60735a5450233a08f5146",
"0c03e2902e4374dc2ae6e9d46b27028af86c461ec65b9708829f6e341c5dfa86",
"427623b7f21f13216b47d64b3cce69d8695a12a8b76ceda909038e8ed1ad7ad6",
"309bd0bf85e4b9bb130a17df032a6d057d2f4774abca3a8af6fdbf25de9182d9",
"7f3da6402da41b66b0e5e957a40a787c53a3a31228f06d45f6ddfc275c06e815",
"9453352b0b6541e28b5c36d1ef833b7f49dad472ac7bc01712f04a1d0bd8cb3d",
"35b6a024cb364ee9e7ac55b3ee07e137b7dc7756c6e7131d02d603613f876578",
"6ce8b20bf01933590374ff85f4a2fcab43cde2bbf9bf7b56c7e4c21acce02af1",
"f02acb1e0f786b78b042e5d5e4d25fe711ecc05b2cbdc37077a4a1b66d925808",
"b5697acfcc9d3d4b58bf01ee959bb519b165d6e2b3ff799dcd8581f2e4ecc4b4",
"e5dcd86553008584de8d4e67edb1049198922900801bf51da55efcb7de45c37b",
"e0c3e5997bd114db9c09728c21b8b35748eee68f8eb305b5cc099be3c265d327",
"6c1e0ef8496d1c39fcde030239772ddf1182807dde25d54fea68085434a08b02",
"4fbd6bcb31a607f792cca7f514d8259a05f684092be8ac91b242bc90169a7042",
"9dbd18a509716c53037d8713d0353094d55b48253cb0d38cd7bc08959d7ff014",
"a444e2b82333cbd5dfe250e393e245d5db8b78f91bbb6a572761a0a43ed56b38",
"b163cba8c2d0441ac59033f7742733cb77812bd74de1147ae8173faae4f9269b",
"0ac9c6fc35728d1317490b51b36277e825a49ba95be2a6783ef7af99e49228f7",
"abe44cdbc6aea6876b8f009d6279479dca2c4f17c650c51bd7de410bbf23cd24",
"4b9370d4ae2fe08db33f468ffceca5d9fe6b0273ef2887a4ea8522293870e0a1",
"98b3b29996faf548b808efa1fd4ca779882bb75cc2ab3304f049b429a3638a97",
"dfb57e8a34f4911773133529e0e222f6a5cf691b25a65c288f8d6baa68b5f406",
"d1e35d54b3df21193102e9dcbb194a294323522ae35c68597b4b08f53cbf36ec",
"53e8bb244f3c2c90fcc8ceb1662e03aab3e1a781fa1697f7383e0bdc59831195",
"255874e4ced532485777b878f2d779c62853bd8d4d05ddadfa6163465703dc8c",
"6b61c176da93e56226cb6fb7a4f8acf1df87d02be81f823dc851680ae64f80b6",
"f035af0a109e467fd4ecd7c45bed043dd1ba0d02164c2b2aa0ab1989d8eaeff7",
"81b239e1213841934e989034959c9ca0448ad64ac3ab919751c2289600a20723",
"251b4f7823c8449e2e154cbab4aa72fb2cc55495da5fdc2d31075aa5647ba4cd",
"0769a11a881bfd2f02a087803235d344ad2f005010e40ecd7af5db96245dd719",
"f4963f675eefacf4cdd14ff7b759d5752aecee4cd704744e58b9bbbe078e0faa",
"28916a97e55790f8e0a95c1203c1f8f1eac99b866aac5800445ef2d888b4be87",
"575a46ecc4c7757656b9371e9b8dc058f99f9d9ad20a3e6de2d4e6cbc193711c",
"935994c1df9323d2bdcbab8762904e48edf6298904f3ae7e234599366bfd86ef",
"dec5bac62e0ef64db4936f818e325e12aed29ee0933277259185da1298dd0a28",
"3ba063cbea967fc0b7bb9a25c5a12ee801eaa92f5570d1d1a977a229834fd0a0",
"3327cc41ebebc9e82f06f836d5868f9c5023b05498bd73d836f04179d24fc7b9",
"8d70f449bda2223d0d647d7543bc3a2c29fedffaef789dc5bd73d25a6f0afd38",
"9902826a10b226265f357562bb20774358dbc636e790257a57af7f791b600acf",
"c5821a347232865496580de7f3043822ca56eea4f8266c51e3be4a16016cdeed",
"2817d6dee3e6706b92989f2dcef7cd0fef5d2263ed3d1c5dab8ba99550b1e5d5",
"b918f2ce206701dfe60eee1d40fad119540e928b8da813fe29d77a2e26c2738b",
"7f836479ecd2c4aec31c96935e2ce932135249c6077184b837f724fbdd425408",
"1381c39fb5a68c134b948aacf72b5127a7b0d5a721ed2091da25a3856b9a9af8",
"80e6ab5756de5eba8551f62d8943e5f650f4ae8864ea6bdffc3257ef1072679a",
"ae7dd5fcf4688844f5ef72471cc0273e0e2f8f43ba4fc3dd41208f70b880e5d4",
"e0f1d8c1a745ede1198fefbd0555bc118f7ccbd9ee783d8ed7a148f54fb1903f",
"33c8a75fad49fd3b3bb1e031fb283858f79b05a8b461eb1f8f0e9d41c53474bc",
"3864e97cd6f47c2eaf3fdcbb105e014accb4eb902be8a43dfca77dfe0d92761e",
"e524e7c40053d3d1da35ac8a584ad7034cd30de0e9513bf7731f8e5f51f7178e",
"12e121ad8a9be231659d08746b1a8b2b9247304dddc69cec074711970986cc6d",
"149a0d197a6c2dba3044e43f5fac90f6a797e0d4c8d91e241725e963083bb472",
"6a062ba02e79d2b2c001e1689daa1b3ade7c917ef26b30987798123818b202bd",
"99e47c124d128f741f30e7c5bc7575f11a005befaa26ab60b560fe4a65717aa0",
"147961e3d28573540582cb4a6e266f3a677d9e5b24da19c29fa611d3f8fba8a9",
"59261c94c9000fe26b3b050c4cf7ab06343d4ffcbe3934da65f12d8a7b0c6862",
"7428bc174ef7fd68911d46b35da30bbf8a292bb6b9ea99489b0c28bb55876e54",
"6fbff71f7187e67e5cc11f85ecc7d063284c6829ffc2b647d9439cf6d80c71b3",
"d49db17aa1e54596333d1962db0050b54a96abc6184f28b46778ac3eb9bc2290",
"082436ca15376750587883056c2b5fceafd232f6fd91d839dcf7f138583565d0",
"2d6c7614ddf121cedd9db989f73da61c3e5d5d7a876139d2d441d8dc28bef0ab",
"10b5eb9db4b22b9047b2c9a2b40abefc9786d8f0b33514bcef81c462f241ca60"
],
"key_material": {
"scan_priv_key": "000000000000000000000000000000000000000000000000000000000000dead",
"spend_priv_key": "000000000000000000000000000000000000000000000000000000000000beef"
},
"labels": [
0
]
},
"expected": {
"addresses": [
"sp1qqtnvg7hxjck9ag24naytgd7pjwsmevwh95ydwht58w3uh7uw0ta7kq6xcdal4dazgg2txp472hdz4svms98328lqdflmpxppmc6ykamcrv9s7w9g",
"sp1qqtnvg7hxjck9ag24naytgd7pjwsmevwh95ydwht58w3uh7uw0ta7kqmk4a3pm24z0yepw6aw27pku56md0hq5ace0l3p3jstkqaajwrsjqc5dde5"
],
"n_outputs": 2323,
"tweak": "022c333a8938ca0c7433c5e39d440b469f58374d0363b5bffc66aca1cc10d7b609",
"shared_secret": "03abe0979dbbe4e1bb2cd2e06524a411c0b829c1d2282052da817b46f1d6e598e4",
"input_pub_key_sum": "02bca87f72e604e8850064552bedf380ca4584227057efe12a6cc238470658aaa3"
}
}
]
}
]
================================================
FILE: bip-0352.mediawiki
================================================
BIP: 352
Layer: Applications
Title: Silent Payments
Authors: josibake
Ruben Somsen
Sebastian Falbesoner
Status: Complete
Type: Specification
Assigned: 2023-03-09
License: BSD-2-Clause
Discussion: 2022-03-13: https://gist.github.com/RubenSomsen/c43b79517e7cb701ebf77eec6dbb46b8 [gist] Original proposal
2022-03-28: https://gnusha.org/pi/bitcoindev/CAPv7TjbXm953U2h+-12MfJ24YqOM5Kcq77_xFTjVK+R2nf-nYg@mail.gmail.com/ [bitcoin-dev] Silent Payments – Non-interactive private payments with no on-chain overhead
2022-10-11: https://gnusha.org/pi/bitcoindev/P_21MLHGJicZ-hkbC4DGu86c5BtNKiH8spY4TOw5FJsfimdi_6VyHzU_y-s1mZsOcC2FA3EW_6w6W5qfV9dRK_7AvTAxDlwVfU-yhWZPEuo=@protonmail.com/ [bitcoin-dev] Silent Payment v4 (coinjoin support added)
2023-08-04: https://gnusha.org/pi/bitcoindev/ZM03twumu88V2NFH@petertodd.org/ [bitcoin-dev] BIP-352 Silent Payments addresses should have an expiration time
Version: 1.0.2
== Introduction ==
=== Abstract ===
This document specifies a protocol for static payment addresses in Bitcoin without on-chain linkability of payments or a need for on-chain notifications.
=== Copyright ===
This BIP is licensed under the BSD 2-clause license.
=== Motivation ===
Using a new address for each Bitcoin transaction is a crucial aspect of maintaining privacy. This often requires a secure interaction between sender and receiver, so that the receiver can hand out a fresh address, a batch of fresh addresses, or a method for the sender to generate addresses on-demand, such as an xpub.
However, interaction is often infeasible and in many cases undesirable. To solve for this, various protocols have been proposed which use a static payment address and notifications sent via the blockchain'''Why not use out-of-band notifications''' Out-of-band notifications (e.g. using something other than the Bitcoin blockchain) have been proposed as a way of addressing the privacy and cost concerns of using the Bitcoin blockchain as a messaging layer. This, however, simply moves the privacy and cost concerns somewhere else and increases the risk of losing money due to a notification not being reliably delivered, or even censored, and makes this notification data critical for backup to recover funds.. These protocols eliminate the need for interaction, but at the expense of increased costs for one-time payments and a noticeable footprint in the blockchain, potentially revealing metadata about the sender and receiver. Notification schemes also allow the receiver to link all payments from the same sender, compromising sender privacy.
This proposal aims to address the limitations of these current approaches by presenting a solution that eliminates the need for interaction, eliminates the need for notifications, and protects both sender and receiver privacy. These benefits come at the cost of requiring wallets to scan the blockchain in order to detect payments. This added requirement is generally feasible for full nodes but poses a challenge for light clients. While it is possible today to implement a privacy-preserving light client at the cost of increased bandwidth, light client support is considered an area of open research (see [[#appendix-a-light-client-support|Appendix A: Light Client Support]]).
The design keeps collaborative transactions such as CoinJoins and inputs with MuSig and FROST keys in mind, but it is recommended that the keys of all inputs of a transaction belong to the same entity as there is no formal proof that the protocol is secure in a collaborative setting.
== Goals ==
We aim to present a protocol which satisfies the following properties:
* No increase in the size or cost of transactions
* Resulting transactions blend in with other bitcoin transactions and can't be distinguished
* Transactions can't be linked to a silent payment address by an outside observer
* No sender-receiver interaction required
* No linking of multiple payments to the same sender
* Each silent payment goes to a unique address, avoiding accidental address reuse
* Supports payment labeling
* Uses existing seed phrase or descriptor methods for backup and recovery
* Separates scanning and spending responsibilities
* Compatible with other spending protocols, such as CoinJoin
* Light client/SPV wallet support
* Protocol is upgradeable
== Overview ==
We first present an informal overview of the protocol. In what follows, uppercase letters represent public keys, lowercase letters represent private keys, ''||'' refers to byte concatenation, ''·'' refers to elliptic curve scalar multiplication, ''G'' represents the generator point for secp256k1, and ''n'' represents the curve order for secp256k1. Each section of the overview is incomplete on its own and is meant to build on the previous section in order to introduce and briefly explain each aspect of the protocol. For the full protocol specification, see [[#specification|Specification]].
''' Simple case '''
Bob publishes a public key ''B'' as a silent payment address. Alice discovers Bob's silent payment address, selects a UTXO with private key ''a'', public key ''A'' and creates a destination output ''P'' for Bob in the following manner:
* Let ''P = B + hash(a·B)·G''
* Encode ''P'' as a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] taproot output
Since ''a·B == b·A'' ([https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman Elliptic-curve Diffie–Hellman]), Bob scans with his private key ''b'' by collecting the input public keys for each transaction with at least one unspent taproot output and performing the ECDH calculation until ''P'' is found (i.e. calculating ''P = B + hash(b·A)·G'' and seeing that ''P'' is present in the transaction outputs).
''' Creating more than one output '''
In order to allow Alice to create more than one output for Bob'''Why allow for more than one output?''' Allowing Alice to break her payment to Bob into multiple amounts opens up a number of privacy improving techniques for Alice, making the transaction look like a CoinJoin or better hiding the change amount by splitting both the payment and change outputs into multiple amounts. It also allows for Alice and Carol to both have their own unique output paying Bob in the event they are in a collaborative transaction and both paying Bob's silent payment address., we include an integer in the following manner:
* Let ''k = 0''
* Let ''P0 = B + hash(a·B || k)·G''
* For additional outputs:
** Increment ''k'' by one (''k++'')
** Let ''Pi = B + hash(a·B || k)·G''
Bob detects this output the same as before by searching for ''P0 = B + hash(b·A || 0)·G''. Once he detects the first output, he must:
* Check for ''P1 = B + hash(b·A || 1)·G''
* If ''P1'' is not found, stop
* If ''P1'' is found, continue to check for ''P2'' and so on until an additional output is not found
Since Bob will only perform these subsequent checks after a transaction with at least one output paying him is found, the increase to his overall scanning requirement is negligible. It should also be noted that the order in which these outputs appear in the transaction does not affect the outcome.
''' Preventing address reuse '''
If Alice were to use a different UTXO from the same public key ''A'' for a subsequent payment to Bob, she would end up deriving the same destinations ''Pi''. To prevent this, Alice should include an input hash in the following manner:
* Let ''input_hash = hash(outpoint || A)'''''Why include A in the input hash calculation?''' By committing to A in input hash, this ensures that the sender cannot maliciously choose a private key ''a′'' in a subsequent transaction where ''a′ = input_hash·a / input_hash′'', which would force address reuse in the protocol.
* Let ''P0 = B + hash(input_hash·a·B || 0)·G''
Bob must calculate the same ''input_hash'' when scanning.
''' Using all inputs '''
In our simplified example we have been referring to Alice's transactions as having only one input ''A'', but in reality a Bitcoin transaction can have many inputs. Instead of requiring Alice to pick a particular input and requiring Bob to check each input separately, we can instead require Alice to perform the tweak with the sum of the input public keys'''What about inputs without public keys?''' Inputs without public keys can still be spent in the transaction but are simply ignored in the silent payments protocol.. This significantly reduces Bob's scanning requirement, makes light client support more feasible'''How does using all inputs help light clients?''' If Alice uses a random input for the tweak, Bob necessarily has to have access to and check all transaction inputs, which requires performing an ECC multiplication per input. If instead Alice performs the tweak with the sum of the input public keys, Bob only needs the summed 33 byte public key per transaction and only does one ECC multiplication per transaction. Bob can then use BIP158 block filters to determine if any of the outputs exist in a block and thus avoids downloading transactions which don't belong to him. It is still an open question as to how Bob can source the 33 bytes per transaction in a trustless manner, see [[#appendix-a-light-client-support|Appendix A: Light Client Support]] for more details., and protects Alice's privacy in collaborative transaction protocols such as CoinJoin'''Why does using all inputs matter for CoinJoin?''' If Alice uses a random input to create the output for Bob, this necessarily reveals to Bob which input Alice has control of. If Alice is paying Bob as part of a CoinJoin, this would reveal which input belongs to her, degrading the anonymity set of the CoinJoin and giving Bob more information about Alice. If instead all inputs are used, Bob has no way of knowing which input(s) belong to Alice. This comes at the cost of increased complexity as the CoinJoin participants now need to coordinate to create the silent payment output and would need to use [https://gist.github.com/RubenSomsen/be7a4760dd4596d06963d67baf140406 Blind Diffie–Hellman] to prevent the other participants from learning who Alice is paying. Note it is currently not recommended to use this protocol for CoinJoins due to a lack of a formal security proof..
Alice performs the tweak with the sum of her input private keys in the following manner:
* Let ''a = a1 + a2 + ... + an''
* Let ''input_hash = hash(outpointL || (a·G))'', where ''outpointL'' is the smallest outpoint lexicographically'''Why use the lexicographically smallest outpoint for the hash?''' Recall that the purpose of including the input hash is so that the sender and receiver can both come up with a deterministic nonce that ensures that a unique address is generated each time, even when reusing the same scriptPubKey as an input. Choosing the smallest outpoint lexicographically satisfies this requirement, while also ensuring that the generated output is not dependent on the final ordering of inputs in the transaction. Using a single outpoint also works well with memory constrained devices (such as hardware signing devices) as it does not require the device to have the entire transaction in memory in order to generate the silent payment output.
* Let ''P0 = B + hash(input_hash·a·B || 0)·G''
''' Spend and Scan Key '''
Since Bob needs his private key ''b'' to check for incoming payments, this requires ''b'' to be exposed to an online device. To minimize the risks involved, Bob can instead publish an address of the form ''(Bscan, Bspend)''. This allows Bob to keep ''bspend'' in offline cold storage and perform the scanning with the public key ''Bspend'' and private key ''bscan''. Alice performs the tweak using both of Bob's public keys in the following manner:
* Let ''P0 = Bspend + hash(input_hash·a·Bscan || 0)·G''
Bob detects this payment by calculating ''P0 = Bspend + hash(input_hash·bscan·A || 0)·G'' with his online device and can spend from his cold storage signing device using ''(bspend + hash(input_hash·bscan·A || 0)) mod n'' as the private key.
''' Labels '''
For a single silent payment address of the form ''(Bscan, Bspend)'', Bob may wish to differentiate incoming payments. Naively, Bob could publish multiple silent payment addresses, but this would require him to scan for each one, which becomes prohibitively expensive. Instead, Bob can label his spend public key ''Bspend'' with an integer ''m'' in the following way:
* Let ''Bm = Bspend + hash(bscan || m)·G'' where m is an incrementable integer starting from 1
* Publish ''(Bscan, B1)'', ''(Bscan, B2)'' etc.
Alice performs the tweak as before using one of the published ''(Bscan, Bm)'' pairs. Bob detects the labeled payment in the following manner:
* Let ''P0 = Bspend + hash(input_hash·bscan·A || 0)·G''
* Subtract ''P0'' from each of the transaction outputs and check if the remainder matches any of the labels (''hash(bscan || 1)·G'', ''hash(bscan || 2)·G'' etc.) that the wallet has previously used
It is important to note that an outside observer can easily deduce that each published ''(Bscan, Bm)'' pair is owned by the same entity as each published address will have ''Bscan'' in common. As such, labels are not meant as a way for Bob to manage separate identities, but rather a way for Bob to determine the source of an incoming payment.
''' Labels for change '''
Bob can also use labels for managing his own change outputs. We reserve ''m = 0'' for this use case. This gives Bob an alternative to using BIP32 for managing change, while still allowing him to know which of his unspent outputs were change when recovering his wallet from the master key. It is important that the wallet never hands out the label with ''m = 0'' in order to ensure nobody else can create payments that are wrongly labeled as change.
While the use of labels is optional, every receiving silent payments wallet should at least scan for the change label when recovering from backup in order to ensure maximum cross-compatibility.
== Specification ==
We use the following functions and conventions:
* ''outpoint'' (36 bytes): the COutPoint of an input (32-byte txid, least significant byte first || 4-byte vout, least significant byte first)'''Why are outpoints little-endian?''' Despite using big endian throughout the rest of the BIP, outpoints are sorted and hashed matching their transaction serialization, which is little-endian. This allows a wallet to parse a serialized transaction for use in silent payments without needing to re-order the bytes when computing the input hash. Note: despite outpoints being stored and serialized as little-endian, the transaction hash (txid) is always displayed as big-endian.
* ser32(i): serializes a 32-bit unsigned integer ''i'' as a 4-byte sequence, most significant byte first.
* ser256(p): serializes the integer p as a 32-byte sequence, most significant byte first.
* serP(P): serializes the coordinate pair P = (x,y) as a byte sequence using SEC1's compressed form: (0x02 or 0x03) || ser256(x), where the header byte depends on the parity of the omitted Y coordinate.
For everything not defined above, we use the notation from [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#specification BIP340]. This includes the ''hashtag(x)'' notation to refer to ''SHA256(SHA256(tag) || SHA256(tag) || x)''.
=== Versions ===
This document defines version 0 (''sp1q''). Version is communicated through the address in the same way as bech32 addresses (see [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP173]. Future upgrades to silent payments will require a new version. As much as possible, future upgrades should support receiving from older wallets (e.g. a silent payments v0 wallet can send to both v0 and v1 addresses). Any changes that break compatibility with older silent payment versions should be a new BIP.
Future silent payments versions will use the following scheme:
{| class="wikitable"
|-
!
!0
!1
!2
!3
!4
!5
!6
!7
!Compatibility
|-
!+0
|q||p||z||r||y||9||x||8||rowspan="4" | backwards compatible
|-
!+8
|g||f||2||t||v||d||w||0
|-
!+16
|s||3||j||n||5||4||k||h
|-
!+24
|c||e||6||m||u||a||7|| -
|}
''v31'' (l) is reserved for a backwards incompatible change, if needed. For silent payments v0:
* If the receiver's silent payment address version is:
** ''v0'': check that the data part is exactly 66-bytes. Otherwise, fail
** ''v1'' through ''v30'': read the first 66-bytes of the data part and discard the remaining bytes
** ''v31'': fail
* Receiver addresses are always [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] taproot outputs'''Why only taproot outputs?''' Providing too much optionality for the protocol makes it difficult to implement and can be at odds with the goal of providing the best privacy. Limiting to taproot outputs helps simplify the implementation significantly while also putting users in the best eventual anonymity set.
* The sender should sign with one of the sighash flags ''DEFAULT'', ''ALL'', ''SINGLE'', ''NONE'' (''ANYONECANPAY'' is unsafe). It is strongly recommended implementations use ''SIGHASH_ALL'' (''SIGHASH_DEFAULT'' for taproot inputs) when possible'''Why is it unsafe to use ''SIGHASH_ANYONECANPAY''?''' Since the output address for the receiver is derived from the sum of the [[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]] public keys, the inputs must not change once the sender has signed the transaction. If the inputs are allowed to change after the fact, the receiver will not be able to calculate the shared secret needed to find and spend the output. It is currently an open question on how a future version of silent payments could be made to work with new sighash flags such as ''SIGHASH_GROUP'' and ''SIGHASH_ANYPREVOUT''.
* Inputs used to derive the shared secret are from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list
=== Scanning silent payment eligible transactions ===
For silent payments v0 a transaction MUST be scanned if and only if all of the following are true:
* The transaction contains at least one BIP341 taproot output (note: spent transactions optionally can be skipped by only considering transactions with at least one unspent taproot output)
* The transaction has at least one input from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list
* The transaction does not spend an output with SegWit version > 1'''Why skip transactions that spend SegWit version > 1?''' Skipping transactions that spend unknown output scripts allows us to have a clean upgrade path for silent payments by avoiding the need to scan the same transaction multiple times with different rule sets. If a new SegWit version is added in the future and silent payments v1 is released with support, we would want to avoid having to first scan the transaction with the silent payment v0 rules and then again with the silent payment v1 rules. Note: this restriction only applies to the inputs of a transaction.
=== Address encoding ===
A silent payment address is constructed in the following manner:
* Let ''Bscan, bscan = Receiver's scan public key and corresponding private key''
* Let ''Bspend, bspend = Receiver's spend public key and corresponding private key''
* Let ''Bm = Bspend + hashBIP0352/Label(ser256(bscan) || ser32(m))·G'', where ''hashBIP0352/Label(ser256(bscan) || ser32(m))·G'' is an optional integer tweak for labeling
** If no label is applied then ''Bm = Bspend''
* The final address is a [https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki Bech32m] encoding of:
** The human-readable part "sp" for mainnet, "tsp" for testnets (e.g. signet, testnet)
** The data-part values:
*** The character "q", to represent a silent payment address of version 0
*** The 66-byte concatenation of the receiver's public keys, ''serP(Bscan) || serP(Bm)''
Note: [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP173] imposes a 90 character limit for Bech32 segwit addresses and limits versions to 0 through 16, whereas a silent payment address requires ''at least'' 117 characters ''' Why do silent payment addresses need at least 117 characters?''' A silent payment address is a bech32m encoding comprised of the following parts:
* HRP [2-3 characters]
* separator [1 character]
* version [1-2 characters]
* payload, 66 bytes concatenated pubkeys [ceil(66*8/5) = 106 characters]
* checksum [6 characters]
For a silent payments v0 address, this results in a 117-character address when using a 3-character HRP. Future versions of silent payment addresses may add to the payload, which is why a 1023-character limit is suggested. and allows versions up to 31. Additionally, since higher versions may add to the data field, it is recommended implementations use a limit of 1023 characters (see [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#checksum-design BIP173: Checksum design] for more details).
=== Inputs For Shared Secret Derivation ===
While any UTXO with known output scripts can be used to fund the transaction, the sender and receiver MUST use inputs from the following list when deriving the shared secret:
* ''P2TR''
* ''P2WPKH''
* ''P2SH-P2WPKH''
* ''P2PKH''
Inputs with conditional branches or multiple public keys (e.g. ''CHECKMULTISIG'') are excluded from shared secret derivation as this introduces malleability and would allow a sender to re-sign with a different set of public keys after the silent payment output has been derived. This is not a concern when the sender controls all of the inputs, but is an issue for CoinJoins and other collaborative protocols, where a malicious participant can participate in deriving the silent payment address with one set of keys and then re-broadcast the transaction with signatures for a different set of public keys. P2TR can have hidden conditional branches (script path), but we work around this by using only the output public key.
For all of the output types listed, only X-only and compressed public keys are permitted''' Why only compressed public keys ''' Uncompressed and hybrid public keys are less common than compressed keys and generally considered to be a bad idea due to their blockspace inefficiency. Additionally, [https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type BIP143] recommends restricting P2WPKH inputs to compressed keys as a default policy..
''' P2TR '''
'' Keypath spend ''
witness:
scriptSig: (empty)
scriptPubKey: 1 <32-byte-x-only-key>
(0x5120{32-byte-x-only-key})
The sender uses the private key corresponding to the taproot output key (i.e. the tweaked private key). This can be a single private key or an aggregate key (e.g. taproot outputs using MuSig or FROST)'''Are key aggregation techniques like FROST and MuSig supported?''' While we do not recommend it due to lack of a security proof (except if all participants are trusted or are the same entity), any taproot output able to do a key path theoretically is supported. Any offline key aggregation technique can be used, such as FROST or MuSig. This would require participants to perform the ECDH step collaboratively e.g. ''ECDH = a1·Bscan + a2·Bscan + ... + at·Bscan'' and ''P = Bspend + hash(input_hash·ECDH || 0)·G''. Additionally, it may be necessary for the participants to provide a DLEQ proof to ensure they are not acting maliciously.. The receiver obtains the public key from the ''scriptPubKey'' (i.e. the taproot output key).
'' Script path spend ''
witness:
scriptSig: (empty)
scriptPubKey: 1 <32-byte-x-only-key>
(0x5120{32-byte-x-only-key})
Same as a keypath spend, the sender MUST use the private key corresponding to the taproot output key. If this key is not available, the output cannot be included as an input to the transaction. Same as a keypath spend, the receiver obtains the public key from the ''scriptPubKey'' (i.e. the taproot output key)''' Why not skip all taproot script path spends? ''' This causes malleability issues for CoinJoins. If the silent payments protocol skipped taproot script path spends, this would allow an attacker to join a CoinJoin round, participate in deriving the silent payment address using the tweaked private key for a key path spend, and then broadcast their own version of the transaction using the script path spend. If the receiver were to only consider key path spends, they would skip the attacker's script path spend input when deriving the shared secret and not be able to find the funds. Additionally, there may be scenarios where the sender can perform ECDH with the key path private key but spends the output using the script path..
The one exception is script path spends that use NUMS point ''H'' as their internal key (where ''H'' is constructed by taking the hash of the standard uncompressed encoding of the secp256k1 base point ''G'' as X coordinate, see [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs BIP341: Constructing and spending Taproot outputs] for more details), in which case the input will be skipped for the purposes of shared secret derivation'''Why skip outputs with H as the internal taproot key?''' If use cases get popularized where the taproot key path cannot be used, these outputs can still be included without getting in the way of making a silent payment, provided they specifically use H as their internal taproot key.. The receiver determines whether or not to skip the input by checking in the control block if the taproot internal key is equal to ''H''.
''' P2WPKH '''
witness: <33-byte-compressed-key>
scriptSig: (empty)
scriptPubKey: 0 <20-byte-key-hash>
(0x0014{20-byte-key-hash})
The sender performs the tweak using the private key for the output and the receiver obtains the public key as the last witness item.
''' P2SH-P2WPKH '''
witness: <33-byte-compressed-key>
scriptSig: <0 <20-byte-key-hash>>
(0x160014{20-byte-key-hash})
scriptPubKey: HASH160 <20-byte-script-hash> EQUAL
(0xA914{20-byte-script-hash}87)
The sender performs the tweak using the private key for the nested ''P2WPKH'' output and the receiver obtains the public key as the last witness item.
''' P2PKH '''
scriptSig: <33-byte-compressed-key>
scriptPubKey: OP_DUP HASH160 <20-byte-key-hash> OP_EQUALVERIFY OP_CHECKSIG
(0x76A914{20-byte-key-hash}88AC)
The receiver obtains the public key from the ''scriptSig''. The receiver MUST parse the ''scriptSig'' for the public key, even if the ''scriptSig'' does not match the template specified (e.g. OP_DROP ). This is to address the [https://en.bitcoin.it/wiki/Transaction_malleability third-party malleability of ''P2PKH'' ''scriptSigs''].
=== Sender ===
==== Selecting inputs ====
The sending wallet performs coin selection as usual with the following restrictions:
* At least one input MUST be from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list
* Exclude inputs with SegWit version > 1 (see ''[[#scanning-silent-payment-eligible-transactions|Scanning silent payment eligible transactions]]'')
* For each taproot output spent the sending wallet MUST have access to the private key corresponding to the taproot output key, unless ''H'' is used as the internal public key
==== Creating outputs ====
After the inputs have been selected, the sender can create one or more outputs for one or more silent payment addresses in the following manner:
* Collect the private keys for each input from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list
* For each private key ''ai'' corresponding to a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] taproot output, check that the private key produces a point with an even Y coordinate and negate the private key if not'''Why do taproot private keys need to be checked?''' Recall from [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] that each X-only public key has two corresponding private keys, ''d'' and ''n - d''. To maintain parity between sender and receiver, it is necessary to use the private key corresponding to the even Y coordinate when performing the ECDH step since the receiver will assume the even Y coordinate when summing the taproot X-only public keys.
* Let ''a = a1 + a2 + ... + an'', where each ''ai'' has been negated if necessary
** If ''a = 0'', fail
* Let ''input_hash = hashBIP0352/Inputs(outpointL || A)'', where ''outpointL'' is the smallest ''outpoint'' lexicographically used in the transaction and ''A = a·G''
** If ''input_hash'' is not a valid scalar, i.e., if ''input_hash = 0'' or ''input_hash'' is larger or equal to the secp256k1 group order, fail
* Group receiver silent payment addresses by ''Bscan'' (e.g. each group consists of one ''Bscan'' and one or more ''Bm'')
* If any of the groups exceed the limit of ''Kmax'' (=2323) silent payment addresses, fail.'''Why is the size of groups (i.e. silent payment addresses sharing the same scan public key) limited by ''Kmax''?''' An adversary could construct a block filled with a single transaction consisting of N=23255 outputs (that's the theoretical maximum under current consensus rules, w.r.t. the block weight limit) that all target the same entity, consisting of one large group. Without a limit on the group size, scanning such a block with the algorithm described in this document would have a complexity of ''O(N2)'' for that entity, taking several minutes on modern systems. By capping the group size at ''Kmax'', we reduce the inner loop iterations to ''Kmax'', thereby decreasing the worst-case block scanning complexity to ''O(N·Kmax)''. This cuts down the scanning cost to the order of tens of seconds. The chosen value of ''Kmax'' = 2323 represents the maximum number of P2TR outputs that can fit into a 100kvB transaction, meaning a transaction that adheres to the current standardness rules is guaranteed to be within the limit. This ensures flexibility and also mitigates potential fingerprinting issues.
* For each group:
** Let ''ecdh_shared_secret = input_hash·a·Bscan''
** Let ''k = 0''
** For each ''Bm'' in the group:
*** Let ''tk = hashBIP0352/SharedSecret(serP(ecdh_shared_secret) || ser32(k))''
**** If ''tk'' is not a valid scalar, i.e., if ''tk = 0'' or ''tk'' is larger or equal to the secp256k1 group order, fail
*** Let ''Pmn = Bm + tk·G''
*** Encode ''Pmn'' as a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] taproot output
*** Optionally, repeat with k++ to create additional outputs for the current ''Bm''
*** If no additional outputs are required, continue to the next ''Bm'' with ''k++''''' Why not re-use ''tk'' when paying different labels to the same receiver?''' If paying the same entity but to two separate labeled addresses in the same transaction without incrementing ''k'', an outside observer could subtract the two output values and observe that this value is the same as the difference between two published silent payment addresses and learn who the recipient is.
** Optionally, if the sending wallet implements receiving silent payments, it can create change outputs by sending to its own silent payment address using label ''m = 0'', following the steps above
All generated outputs MUST be present in the final transaction. If an output ''Pi'' with ''i < k'' is omitted, the receiver will not be able to find outputs ''Pj'' where ''i < j <= k''.
=== Receiver ===
==== Key Derivation ====
Two keys are needed to create a silent payments address: the spend key and the scan key. To ensure compatibility, wallets MAY use BIP32 derivation with the following derivation paths for the spend and scan key. When using BIP32 derivation, wallet software MUST use hardened derivation'''Why use BIP32 hardened derivation?''' Using BIP32 derivation allows users to add silent payments to an existing master seed. It also ensures that a user's silent payment funds are recoverable in any BIP32/BIP43 compatible wallet. Using hardened derivation ensures that it is safe to export the scan private key without exposing the master key or spend private key. for both the spend and scan key.
A scan and spend key pair using BIP32 derivation are defined (taking inspiration from [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]) in the following manner:
scan_private_key: m / purpose' / coin_type' / account' / 1' / 0
spend_private_key: m / purpose' / coin_type' / account' / 0' / 0
purpose is a constant set to ''352'' following the BIP43 recommendation. Refer to [https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki BIP43] and [https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44] for more details.
==== Scanning ====
If each of the checks in ''[[#scanning-silent-payment-eligible-transactions|Scanning silent payment eligible transactions]]'' passes, the receiving wallet must:
* Let ''A = A1 + A2 + ... + An'', where each ''Ai'' is the public key of an input from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list
** If ''A'' is the point at infinity, skip the transaction
* Let ''input_hash = hashBIP0352/Inputs(outpointL || A)'', where ''outpointL'' is the smallest ''outpoint'' lexicographically used in the transaction
** If ''input_hash'' is not a valid scalar, i.e., if ''input_hash = 0'' or ''input_hash'' is larger or equal to the secp256k1 group order, fail
* Let ''ecdh_shared_secret = input_hash·bscan·A''
* Check for outputs:
** Let ''outputs_to_check'' be the taproot output keys from all taproot outputs in the transaction (spent and unspent).
** Starting with ''k = 0'':
*** If ''k == Kmax'' (=2323), stop scanning.
*** Let ''tk = hashBIP0352/SharedSecret(serP(ecdh_shared_secret) || ser32(k))''
**** If ''tk'' is not a valid scalar, i.e., if ''tk = 0'' or ''tk'' is larger or equal to the secp256k1 group order, fail
*** Compute ''Pk = Bspend + tk·G''
*** For each ''output'' in ''outputs_to_check'':
**** If ''Pk'' equals ''output'':
***** Add ''Pk'' to the wallet
***** Remove ''output'' from ''outputs_to_check'' and rescan ''outputs_to_check'' with ''k++''
**** Else, check for labels (always check for the change label, i.e. ''hashBIP0352/Label(ser256(bscan) || ser32(m))'' where ''m = 0'')''' Why precompute labels?''' Precomputing the labels is not strictly necessary: a wallet could track the max number of labels it has used (call it ''M'') and scan for labels by adding ''hash(bscan || m)·G'' to ''P0'' for each label ''m'' up to ''M'' and comparing to the transaction outputs. This is more performant than precomputing the labels and checking via subtraction in cases where the number of eligible outputs exceeds the number of labels in use. In practice this will mainly apply to users that choose never to use labels, or users that use a single label for generating silent payment change outputs. If using a large number of labels, the wallet would need to add all possible labels to each output. This ends up being ''n·M'' additions, where ''n'' is the number of outputs in the transaction and ''M'' is the number of labels in the wallet. By precomputing the labels, the wallet only needs to compute ''hash(bscan || m)·G'' once when creating the labeled address and can determine if a label was used via a lookup, rather than adding each label to each output.:
***** Compute ''label = output - Pk''
***** Check if ''label'' exists in the list of labels used by the wallet
***** If a match is found:
****** Add ''Pk + label'' to the wallet
****** Remove ''output'' from ''outputs_to_check'' and rescan ''outputs_to_check'' with ''k++''
***** If a label is not found, negate ''output'' and check a second time''' Why negate the output?''' Unfortunately taproot outputs are X-only, meaning we don't know what the correct Y coordinate is. This causes this specific calculation to fail 50% of the time, so we need to repeat it with the other Y coordinate by negating the output.
*** If no matches are found, stop
==== Spending ====
Recall that a silent payment output is of the form ''Bspend + tk·G + hashBIP0352/Label(ser256(bscan) || ser32(m))·G'', where ''hashBIP0352/Label(ser256(bscan) || ser32(m))·G'' is an optional label. To spend a silent payment output:
* Let ''d = (bspend + tk + hashBIP0352/Label(ser256(bscan) || ser32(m))) mod n'', where ''hashBIP0352/Label(ser256(bscan) || ser32(m))'' is the optional label
* Spend the [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] output with the private key ''d''
==== Backup and Recovery ====
Since each silent payment output address is derived independently, regular backups are recommended. When recovering from a backup, the wallet will need to scan since the last backup to detect new payments.
If using a seed/seed phrase only style backup, the user can recover the wallet's unspent outputs from the UTXO set (i.e. only scanning transactions with at least one unspent taproot output) and can recover the full wallet history by scanning the blockchain starting from the wallet birthday. If a wallet uses labels, this information SHOULD be included in the backup. If the user does not know whether labels were used, it is strongly recommended they always precompute and check a large number of labels (e.g. 100k labels) to use when re-scanning. This ensures that the wallet can recover all funds from only a seed/seed phrase backup. The change label should simply always be scanned for, even when no other labels were used. This ensures the use of a change label is not critical for backups and maximizes cross-compatibility.
== Backward Compatibility ==
Silent payments introduces a new address format and protocol for sending and as such is not compatible with older wallet software or wallets which have not implemented the silent payments protocol.
== Test Vectors ==
A [[bip-0352/send_and_receive_test_vectors.json|collection of test vectors in JSON format]] is provided, along with a [[bip-0352/reference.py|python reference implementation]]. It uses a vendored copy of the [https://github.com/secp256k1lab/secp256k1lab/ secp256k1lab] library at version 1.0.0
(commit [https://github.com/secp256k1lab/secp256k1lab/commit/44dc4bd893b8f03e621585e3bf255253e0e0fbfb 44dc4bd893b8f03e621585e3bf255253e0e0fbfb]).
Each test vector consists of a sending test case and corresponding receiving test case. This is to allow sending and receiving to be implemented separately. To ensure determinism while testing, sort the array of ''Bm'' by amount (see the [[bip-0352/reference.py|reference implementation]]). Test cases use the following schema:
''' test_case '''
{
"comment": "Comment describing the behavior being tested",
"sending": [],
"receiving": [],
}
''' sender '''
{
"given": {
"vin": [],
"recipients": [
{
"address": ,
"scan_pub_key": ,
"spend_pub_key": ,
"count":
},
...
]
},
"expected": {
"outputs": [],
"n_outputs": ,
},
}
''' recipient '''
{
"given": {
"vin": [],
"key_material": {
"scan_priv_key": ,
"spend_priv_key": ,
}
"labels": [],
},
"expected": {
"addresses": [],
"outputs": [
{
"priv_key_tweak": ,
"pub_key": ,
"signature":
},
...
],
"n_outputs":
}
}
Wallets should include inputs not in the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list when testing to ensure that only inputs from the list are being used for shared secret derivation. Additionally, receiving wallets should include non-silent payment outputs for themselves in testing to ensure silent payments scanning does not interfere with regular outputs detection.
=== Functional tests ===
Below is a list of functional tests which should be included in sending and receiving implementations.
==== Sending ====
* Ensure taproot outputs are excluded during coin selection if the sender does not have access to the key path private key (unless using ''H'' as the taproot internal key)
* Ensure the silent payment address is re-derived if inputs are added or removed during RBF
==== Receiving ====
* Ensure the public key can be extracted from non-standard ''P2PKH'' scriptSigs
* Ensure taproot script path spends are included, using the taproot output key (unless ''H'' is used as the taproot internal key)
* Ensure the scanner can extract the public key from each of the input types supported (e.g. ''P2WPKH'', ''P2SH-P2WPKH'', etc.)
== Appendix A: Light Client Support ==
This section proposes a few ideas for how light clients could support scanning for incoming silent payments (sending is fairly straightforward) in ways that preserve bandwidth and privacy. While this is out of scope for the current BIP, it is included to motivate further research into this topic. In this context, a light client refers to any bitcoin wallet client which does not process blocks and does not have a direct connection to a node which does process blocks (e.g. a full node). Based on this definition, clients that directly connect to a personal electrum server or a bitcoin node are not light clients.
This distinction makes the problem for light clients more clear: light clients need a way to source the necessary data for performing the tweaks and a way of determining if any of the generated outputs exist in a block.
=== Tweak Data ===
Recall that a silent payment eligible transaction follows [[#scanning-silent-payment-eligible-transactions|certain conditions]] and should have at least one unspent taproot output. Full nodes (or any index server backed by a full node, such as electrum server) can build an index which collects all of the eligible public keys for a silent payments eligible transaction, sums them up, multiplies the sum by the ''input_hash'', and serves them to clients. This would be 33 bytes per silent payment eligible transaction.
For a typical bitcoin block of ~3500 txs, lets assume every transaction is a silent payments eligible transaction. This means a client would need to request ''33 bytes * 3500'' of data per block (roughly 100 kB per block). If a client were to request data for every block, this would amount to ~450 MB per month, assuming 100% taproot usage and all non-dust outputs remain unspent for > 1 month. As of today, these numbers are closer to 7–12 kB per block (30–50 MB per month)''' Data for Appendix A ''' These numbers are based on data from January 2023 until July 2024. See [https://github.com/josibake/bitcoin-data-analysis/blob/main/notebooks/silent-payments-light-client-data.ipynb Silent payments light client data] for the full analysis..
=== Transaction cut-through ===
It is unlikely a light client would need to scan every block and as such can take advantage of transaction cut-through, depending on how often they choose to scan for new blocks. Empirically, ~75% of transactions with at least one non-dust unspent taproot output will have spent all non-dust taproot UTXOs in 150 blocks or less. This means a client that only scans once per day could ''significantly'' cut down on the number of blocks and the number of transactions per block that they need to request by only asking for data on transactions that were created since their last scan and that still have at least one non-dust unspent taproot output as of the current block height. Based on taproot adoption as of July 2024, a light client scanning once every 3 days would use roughly 30 MB per month.
[[File:bip-0352/scan_data_downloader_per_month.png]]
=== BIP158 ===
Once a light client has the tweak data for a block, they can determine whether or not an output to them exists in the block using BIP158 block filters. Per BIP158, they would then request the entire block and add the transaction to their wallet, though it maybe be possible to only request the prevout txids and vouts for all transactions with at least one taproot output, along with the scriptPubKeys and amounts. This would allow the client to download the necessary data for constructing a spending transaction, without downloading the entire block. How this affects the security assumptions of BIP158 is an open question.
=== Out-of-band notifications ===
Assuming a secure messaging protocol exists, the sender can send an encrypted (using the scan public key of the silent payment address) notification to the receiver with the following information:
* The spend public key (communicates the label)
* The shared secret portion of the private key (i.e ''hash(ecdh_shared_secret || k)'')
* The outpoint and amount (so it's immediately spendable)
It is important to note that these notifications are not required. At any point, the receiver can fall back to scanning for silent payment transactions if they don't trust the notifications they are receiving, are being spammed with fake notifications, or if they are concerned that they are not receiving notifications.
A malicious notification could potentially cause the following issues:
* You did not actually receive money to the stated key
** This can be probabilistically resolved by matching the key against the BIP158 block filters and assuming it's not a false positive, or fully resolved by downloading the block
* You received money but the outpoint or amount is incorrect, so attempts to spend it will fail or cause you to overpay fees
** There doesn't seem to be much motivation for malicious senders to ever do this, but light clients need to take into account that this can occur and should ideally check for it by downloading the block
* The private key is correct but it wasn't actually derived using the silent payment protocol, causing recovery from back-up to fail (unsafe - no implementation should ever allow this)
** This can be detected by downloading the tweak data of the corresponding block and should be resolved by immediately spending the output
Wallet designers can choose which tradeoffs they find appropriate. For example, a wallet could check the block filter to at least probabilistically confirm the likely existence of the UTXO, thus efficiently cutting down on spam. The payment could then be marked as unconfirmed until a scan is performed and the existence of the UTXO in accordance to the silent payment specification is verified.
== Changelog ==
To help implementers understand updates to this document, we attach a version number that resembles ''semantic versioning'' (MAJOR.MINOR.PATCH).
The MAJOR version is incremented if changes to the BIP are introduced that are incompatible with prior versions.
The MINOR version is incremented whenever the inputs or the output of an algorithm changes in a backward-compatible way or new backward-compatible functionality is added.
The PATCH version is incremented for other changes that are noteworthy (bug fixes, test vectors, important clarifications, etc.).
* '''1.1.0''' (2026-03-02):
** Introduce per-group recipient limit ''Kmax'' to mitigate quadratic scanning behavior for adversarial transactions.
* '''1.0.2''' (2025-07-25):
** Clarify how to handle the improbable corner case where the output of SHA256 is equal to 0 or greater than or equal to the secp256k1 curve order.
* '''1.0.1''' (2024-06-22):
** Add steps to fail if private key sum is zero (for sender) or public key sum is point at infinity (for receiver), add corresponding test vectors.
* '''1.0.0''' (2024-05-08):
** Initial version, merged as BIP-352.
== Acknowledgements ==
This document is the result of many discussions and contains contributions by a number of people. The authors wish to thank all those who provided valuable feedback and reviews, including the participants of the [https://gist.github.com/RubenSomsen/21c477c90c942acf45f8e8f5c1ad4fae BIP47 Prague discussion], the [https://github.com/josibake/silent-payments-workshop Advancing Bitcoin silent payments Workshop], and [https://btctranscripts.com/bitcoin-core-dev-tech/2023-04/2023-04-26-silent-payments/ coredev]. The authors would like to also thank [https://github.com/w0xlt w0xlt] for writing the initial implementation of silent payments.
== Rationale and References ==
================================================
FILE: bip-0353.mediawiki
================================================
==Copyright==
This BIP is licensed under the CC0-1.0 license.
==Abstract==
This BIP proposes a standard format for encoding [[bip-0021.mediawiki|BIP 21]] URI schemes in DNS TXT records.
==Motivation==
Various Bitcoin and other cryptocurrency applications have developed human-readable names for payment instructions over time, with marketplace adoption signaling strong demand for it from users.
The DNS provides a standard, global, hierarchical namespace mapping human-readable labels to records of various forms. Using DNSSEC, the DNS provides cryptographic guarantees using a straightforward PKI which follows the hierarchical nature of the DNS, allowing for stateless and even offline validation of DNS records from a single trusted root.
Further, because DNS queries are generally proxied through ISP-provided or other resolvers, DNS queries usually do not directly expose the queryer's IP address. Further, because of the prevalence of open resolvers, the simplicity of the protocol, and broad availability of DNS recursive resolver implementations, finding a proxy for DNS records is trivial.
Thus, using TXT records to store Bitcoin payment instructions allows for human-readable Bitcoin payment destinations which can be trivially verified on hardware wallets and which can be resolved relatively privately.
==Specification==
=== General rules for handling ===
Bitcoin wallets MUST NOT prefer to use DNS-based resolving when methods with explicit public keys or addresses are available. In other words, if a standard Bitcoin address or direct BIP 21 URI is available or would suffice, Bitcoin wallets MUST prefer to use that instead.
=== Records ===
Payment instructions are indexed by both a user and a domain. Instructions for a given user and domain are stored at user.user._bitcoin-payment.domain in a single TXT RR.
The TXT RR’s RDATA MUST consist of one or more DNS s (see [[https://www.rfc-editor.org/rfc/rfc1035#section-3.3.14|RFC 1035 §3.3.14]]), each ≤255 bytes.
All payment instructions MUST be DNSSEC-signed.
Payment instructions MAY resolve through CNAME or DNAME records as long as all such records and the ultimate records pointed to by them are DNSSEC signed.
User and domain names which are not expressible using standard printable ASCII MUST be encoded using the punycode IDN encoding defined in [[https://datatracker.ietf.org/doc/html/rfc3492|RFC 3492]] and [[https://datatracker.ietf.org/doc/html/rfc5891|RFC 5891]].
Note that because resolvers are not required to support resolving non-ASCII identifiers, wallets SHOULD avoid using non-ASCII identifiers.
For payment instructions that have a built-in expiry time (e.g. Lightning BOLT 12 offers), care must be taken to ensure that the DNS records expire prior to the expiry of the payment instructions. Otherwise, senders may have payment instructions cached locally which have expired, preventing payment.
=== Resolution ===
Clients resolving Bitcoin payment instructions MUST ignore any TXT records at the same label which do not begin with (ignoring case) "bitcoin:". Resolvers encountering multiple "bitcoin:"-matching TXT records at the same label MUST treat the records as invalid and refuse to use any payment instructions therein.
Clients resolving Bitcoin payment instructions MUST reconstruct the bitcoin: URI by concatenating the TXT RR’s fields in RDATA order, without inserting separators, before parsing.DNS TXT RDATA consists of one or more length-prefixed strings with a maximum of 255 bytes of content; see RFC 1035 §3.3.14.
Clients MUST NOT concatenate across multiple TXT RRs at the same owner name.
Clients resolving Bitcoin payment instructions MUST fully validate DNSSEC signatures leading to the DNS root (including any relevant CNAME or DNAME records) and MUST NOT accept DNSSEC signatures which use SHA-1 or RSA with keys shorter than 1024 bits. Resolvers MAY accept SHA-1 DS records.
Clients resolving Bitcoin payment instructions MUST NOT trust a remote resolver to validate DNSSEC records on their behalf.
Clients resolving Bitcoin payment instructions MUST support resolving through CNAME or DNAME records.
Resolvers MAY support resolving non-ASCII user and domain identifiers. Resolvers which do support non-ASCII user and domain identifiers MUST take precautions to prevent homograph attacks and SHOULD consider denying paste functionality when entering non-ASCII identifiers. Wallets which do not take any such precautions MUST instead display non-ASCII user and domain identifiers using their raw punycode. As such, wallets SHOULD NOT create identifiers which are not entirely printable ASCII.
While clients MAY cache the payment instructions they receive from the DNS, clients MUST NOT cache the payment instructions received from the DNS for longer than the TTL provided by their DNS resolver, and further MUST NOT cache the payment instructions for longer than the lowest initial TTL (which is signed as a part of DNSSEC signatures) received in the full DNSSEC chain leading from the DNS root to the resolved TXT record.
=== Address Reuse ===
Payment instructions with on-chain addresses which will be re-used SHOULD be rotated as regularly as possible to reduce address reuse. Such payment instructions SHOULD also use a relatively short DNS TTL to ensure regular rotation takes effect quickly. In cases where this is not practical, payment instructions SHOULD NOT contain on-chain addresses (i.e. the URI path SHOULD be empty).
Payment instructions which do contain on-chain addresses which will be re-used SHOULD be rotated after any transaction to such an address is confirmed on-chain.
=== Display ===
When displaying a verified human-readable name, wallets SHOULD prefix it with ₿, i.e. ₿user@domain. They SHOULD parse recipient information in both user@domain and ₿user@domain forms and resolve such an entry into recipient information using the above record. For the avoidance of doubt, the ₿ is *not* included in the DNS label which is resolved.
Wallets providing the ability for users to "copy" their address information SHOULD copy the underlying URI directly, rather than the human-readable name. This avoids an additional DNS lookup by the application in which it is pasted. Wallets that nevertheless provide users the ability to copy their human-readable name, MUST include the ₿ prefix (i.e. copy it in the form ₿user@domain).
Wallets accepting payment information from external devices (e.g. hardware wallets) SHOULD accept RFC 9102-formatted proofs (as a series of unsorted AuthenticationChain records) and, if verification succeeds, SHOULD display the recipient in the form ₿user@domain.
=== PSBT types ===
Wallets accepting payment information from external devices (e.g. hardware wallets) MAY examine the following per-output PSBT fields to fetch RFC 9102-formatted proofs. Wallets creating PSBTs with recipient information derived from human-readable names SHOULD include the following fields.
When validating the contained proof, clients MUST enforce the inception on all contained RRSigs is no later than the current time and that the expiry of all RRSigs is no earlier than an hour in the past. Clients MAY allow for an expiry up to an hour in the past to allow for delays between PSBT construction and signing only if such a delay is likely to occur in their intended usecase.
{|
! Name
!
!
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| BIP 353 DNSSEC proof
| PSBT_OUT_DNSSEC_PROOF = 0x35
| None
| <1-byte-length-prefixed BIP 353 human-readable name without the ₿ prefix>
| A BIP 353 human-readable name (without the ₿ prefix), prefixed by a 1-byte length.
Followed by an [[https://www.rfc-editor.org/rfc/rfc9102.html#name-dnssec-authentication-chain|RFC 9102 DNSSEC AuthenticationChain]] (i.e. a series of DNS Resource Records in no particular order) providing a DNSSEC proof to a BIP 353 DNS TXT record.
|
|
| 0, 2
|}
== Rationale ==
=== Display ===
There are several ways in which human-readable payment instructions could be displayed in wallets. In order to ensure compatibility with existing human-readable names schemes, @ is used as the separator between the user and domain parts. However, simply using the @ separator can lead to confusion between email addresses on a given domain and payment instructions on a domain. In order to somewhat reduce the incidence of such confusion, a ₿ prefix is used.
=== Rotation ===
On-chain addresses which are re-used (i.e. not including schemes like [[bip-0352.mediawiki|Silent Payments]]) need to be rotated to avoid contributing substantially to address reuse. However, rotating them on a timer or any time a transaction enters the mempool could lead to substantial overhead from excess address generation. Instead, rotating addresses any time a transaction is confirmed on-chain ensures address rotation happens often while bounding the maximum number of addresses needed to one per block, which grows very slowly and will not generate an address set too large to handle while scanning the chain going forward.
=== Alternatives ===
There are many existing schemes to resolve human-readable names to cryptocurrency payment instructions. Sadly, these current schemes suffer from a myriad of drawbacks, including (a) lacking succinct proofs of namespace to public key mappings, (b) revealing sender IP addresses to recipients or other intermediaries as a side-effect of payment, (c) relying on the bloated TLS Certificate Authority infrastructure, or (d) lacking open access, not allowing anyone to create a namespace mapping.
==== DNS Rather than blockchain-based solutions ====
There are many blockchain-based alternatives to the DNS which feature better censorship-resistance and, in many cases, security. However, here we chose to use the standard ICANN-managed DNS namespace as many blockchain-based schemes suffer from (a), above (though in some cases this could be addressed with cryptographic SNARK schemes). Further, because they do not have simple client-side querying ability, many of these schemes use trusted intermediaries which resolve names on behalf of clients. This reintroduces drawbacks (b) and often (c) as well.
Finally, it is worth noting that none of the blockchain-based alternatives to the DNS have had material adoption outside of their specific silos, and committing Bitcoin wallets to rely on a separate system which doesn't see broad adoption may not be sustainable.
==== DNS Rather than HTTP-based solutions ====
HTTP(s)-based payment instruction resolution protocols suffer from drawbacks (a), (b), and (c), above, and generally shouldn't be considered a serious alternative for payment instruction resolution.
==== Private DNS Querying ====
While public recursive DNS resolvers are very common (e.g. 1.1.1.1, 8.8.8.8, and 9.9.9.9), using such resolvers directly (even after validating DNSSEC signatures) introduces drawback (b), at least in regard to a centralized intermediary. Resolving payment instructions recursively locally using a resolver on the same local network or in the paying application would instead introduce drawback (b) directly to the recipient, which may well be worse.
For payers not using VPN or other proxying technologies, they generally trust their ISP to not snoop on their DNS requests anyway, so using ISP-provided recursive DNS resolvers is likely the best option.
However, for the best privacy, payers are encouraged to perform DNS resolution over Tor or another VPN technology.
Lightning payers should consider utilizing DNS resolution over native onion messages, using the protocol described in [[https://github.com/lightning/blips/blob/master/blip-0032.md|BLIP 32]]
=== DNS Enumeration ===
In most cases where payments are accepted from any third-party, user enumeration is practical by simply attempting to send small value payments to a list of possible user names. However, storing all valid users in the DNS directly may make such enumeration marginally more practical. Thus, those wishing to avoid such enumeration should carefully ensure all DNS names return valid payment instructions. Note when doing so that wildcard records are identified as such by the DNSSEC RRSIG labels counter and are differentiable from non-wildcard records.
== Backwards Compatibility ==
This work is intended to extend and subsume the existing "Lightning Address" scheme, which maps similar names (without the ₿ prefix) using HTTPS servers to Lightning BOLT 11 payment instructions. Wallets implementing this scheme MAY fall back to existing "Lightning Address" logic if DNS resolution fails but SHOULD NOT do so after this scheme is sufficiently broadly deployed to avoid leaking sender IP address information.
== Examples ==
matt@mattcorallo.com resolves to
matt.user._bitcoin-payment.mattcorallo.com. 1800 IN TXT "bitcoin:?lno=lno1qsgr30k45jhvkfqxjqheaetac
u4guyxvqttftvqu0f5sneckep3lkwdut7mmhhpcyjmlmnjn4hze8ed7pq88xqkxt2dcw5mlxhz644fms82f7k4ymfxs2ehhpjtxw
xly0w5k8xdtlvpqyd8xzdq4tq8lgupnueshgydr330lc3j5kdcqh54gt7jdg9n68j4eqqeu7ts8uh0qxamee6ndj37tc6mzgejth
vvjqj96p8dz2h" "rsh5z5n27qfk6svjz5pmkh0smq26k0j2j4q36xgq3r5qzet9kuhq4lydpen5mskxgjdvs5faqgv8pmj7cfd7
ny84djksqpqk9ky6juc7fpezecxvg7sjx05dckyypnv9tmvfp6tkpehmtaqmvuupetxuzqf4t0azddjdcpasgw6hxuz9g"
* Note that lno indicates a value containing a lightning BOLT12 offer.
* Note that the complete URI is broken into two strings with maximum 255 characters each
=== Example proofs ===
The following are valid DNSSEC proofs to be included in the PSBT_OUT_DNSSEC_PROOF record in a PSBT.
This encodes address bc1qztwy6xen3zdtt7z0vrgapmjtfz8acjkfp5fp7l to simple@dnssec_proof_tests.bitcoin.ninja valid on August 7, 2025. Note that the second TXT record (which does not start with, case insensitively, "bitcoin:") is ignored.
2773696d706c6540646e737365635f70726f6f665f74657374732e626974636f696e2e6e696e6a610673696d706c650475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100001000010000001e001110626974636f696e20697320636f6f6c210673696d706c650475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100001000010000001e003736626974636f696e3a3f62633d626331717a7477793678656e337a647474377a3076726761706d6a74667a3861636a6b6670356670376c0673696d706c650475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100002e00010000001e006100100d060000001e68a70b7e68948166d0e207626974636f696e056e696e6a61007e51ba5c43c4d18dc62a54d4647d1fcf2cfa594cd6bfddfe834c7b9bc6f1849490972441ea34283c6c7dbab3ed783deabebb3f1081ade02e57795a85220051bc07626974636f696e056e696e6a6100003000010001614500440100030dff753a27b08c3e48a642b210d6fcc444ff9ed4faf9c1241103db4ed3c19a95c3afbb52c0c02eb392ee048cc9e28ac2d272b1053bdc052bc18d5de05d7710196c07626974636f696e056e696e6a6100003000010001614500440101030df65551925ce6321888e685981823d617fbc10f329bffe4081bf18c2372632a5548010bf62e6556a92722629275e0bd001e3d7837d325a353f6a851c5b965259607626974636f696e056e696e6a6100002e000100016145006100300d0200093a806898c73468863d1c716c07626974636f696e056e696e6a610002fd1bf18c2ebb5ece5e28ca76bf30650695636c55633bccae8179c2d1ee7b97e78d188e08ffc869a8f67847bf557516ac12465ebea1acc281d6d636fdab612007626974636f696e056e696e6a6100002b000100000cfc0024716c0d023f7ad5a303e9c1cd1474b8df2ae56f3f82da8637ca55db4d9a2bb85960ca698e07626974636f696e056e696e6a6100002b000100000cfc0024768a0d02ce46a9aff9a06e789c1bdfe250b0ef6ba8d39a53b2a3427c551f5ad375e059b607626974636f696e056e696e6a6100002e000100000cfc0099002b080200000e1068a89268688cd4d892dc056e696e6a61004d88897d7d5f5d920ca436e81ee67b1bb22f1a96309693454ab9d0b06434794162cc42846a4b51a40475a5b44e940c04dd1ac2c902a190ca2251ae89184520b0f3f22c12c51403d0a6e1cd95792e8f6f5036cd2d50dbdfa5eba3b2ee70ff78d40dc2eba2cc899af26954a55e5b5d344d478cabd9423418495caee45c550b1144056e696e6a61000030000100000cfc0088010003080301000197edb59d4f181e2761dd8d0465854339afc71fd89e47155981ddd175cdce79477552aeaf7b5a08fc4ac6025555f60582f2060e630edfb35b9c7cc30990fb9c3dc9f2fd036c962f67b94c9670d4ceaacd77973bca82ab7c9615f7e4320dda5b6d74dec673017c6fa448b5542a804e08ac873c509c1945ff734c320491e4b18e6d056e696e6a61000030000100000cfc01080101030803010001c71e4c9dc49249a27b3ef42fcb8d56b4c3ac76715c7ad01c41d0d432590d15c3c62cee4b2d29ac35f2d72c9b32a70a0243cbd08aeebc9f6f1e0e63d9e1cdfe133c455a82435c0780b750012c942f7ed5b662eec8d9ae885a58993fa78d7561fedcd11d9e1c171acb02d0025837ba61a3c0a6756427414470c9ca0906b298168b5f4d9640e62e1b75dd06be664104ed32cfe447fa21f37401712c720a0dca4bb1bc20f3fa3103cad336bde20b16f73948e6b80dda0a528db536a958868c3870ecddcfb02dfb3cb4d22e2ad49a4b9f78c90ff6c7e10e301b3fb36fe859a94c30084660665741c14ff60d0535013fcf439840ecad82fc9278e4ace68ba95e708249056e696e6a61000030000100000cfc00880100030803010001d28cb7e2bb163d5815838bedeca1006dde8551b379cb963c8a2cb42bc360127e3a5cf88ffc851a67414815b875f65d78c39b58d2fb29a1d4e76d50cb6b4a58a11fe2fb7c1b6db7bf7d72f5a1401e381c57fcc76f599cc73f05095d2bd14d9895e4fa1cff21bd760598a734b640102d11bc159c6b2ae73dbfd2741518142584d1056e696e6a6100002e000100000cfc01190030080100000e1068a89268688cd4d8b402056e696e6a6100646e04cf5f76daa775ff98905ded3d2caad68d3198fc161340d558262c7ba7da28e7538a7f32d5a6485e4448037e8edf55759b7059fdc084f1017f790aa7c0d8f0e4af6c9af04e4afd16ce6052c30da59314c9c98075fd32bb77a81f34bea6190631b9d0a4351a764c14152ea217e6271647bf95b0df4c3d7cc00937bec01b65ad1b5209c976a4843e399f173f196a012c0876bc9afa3457d940d6ad7b9d50b3d496836d7342cf3aec75ac4785563e20574ddd2dab1cfb6b5da32508edf7186aa516b0451b221251652ee44353710cbe35928b79fff4293c5e8eff7ab371ce43595e2300305bda0108b911c3ef7d4d15c70d68686fddf28422d5fcbcdb967e84056e696e6a6100002b0001000151800024b4020802c8f816a7a575bdb2f997f682aab2653ba2cb5eddb69b036a30742a33befaf141056e696e6a6100002e0001000151800113002b08010001518068a55650689424c0b569007f4d7bbce2d77380e115f8469a3c6d1d4bd9be1145eeee843332f1d54da134a25f7d259ccfa36a2e833106139ba37bc28651b7717dabfc8c450e889c5d5d6d39d12f1004252fa08692794af4a7f29a94f6611f9b000ba899d90d6a32e91c54e63720811546b251fb265b7f62615391ab330f83a96841f0367347e67522112f63f3efda891ae0f7265ed5b89673f184027cdb9b5e94b16a9b1f99877cc8e078abf246cad1f76a48a34474977dbd89dd3b41f381df89a82e2939aeb06830f656253e4e347cd04ee6dba0c8377e818f919f80a7e6aefa0f8196d04845bc26b498b0115022ff75e363711e55337de505e50df69b840699160467516d15e8235aa4cf00003000010002a30001080100030803010001b11b182a464c3adc6535aa59613bda7a61cac86945c20b773095941194f4b9f516e8bd924b1e50e3fe83918b51e54529d4e5a1e45303df8462241d5e05979979ae5bf9c6c598c08a496e17f3bd3732d5aebe62667b61db1bbe178f27ac99408165a230d6aee78348e6c67789541f845b2ada96667f8dd16ae44f9e260c4a138b3bb1015965ebe609434a06464bd7d29bac47c3017e83c0f89bca1a9e3bdd0813715f3484292df589bc632e27d37efc02837cb85d770d5bd53a36edc99a8294771aa93cf22406f5506c8cf850ed85c1a475dee5c2d3700b3f5631d903524b849995c20cb407ed411f70b428ae3d642716fe239335aa961a752e67fb6dca0bf72900003000010002a30001080101030803010001af7a8deba49d995a792aefc80263e991efdbc86138a931deb2c65d5682eab5d3b03738e3dfdc89d96da64c86c0224d9ce02514d285da3068b19054e5e787b2969058e98e12566c8c808c40c0b769e1db1a24a1bd9b31e303184a31fc7bb56b85bbba8abc02cd5040a444a36d47695969849e16ad856bb58e8fac8855224400319bdab224d83fc0e66aab32ff74bfeaf0f91c454e6850a1295207bbd4cdde8f6ffb08faa9755c2e3284efa01f99393e18786cb132f1e66ebc6517318e1ce8a3b7337ebb54d035ab57d9706ecd9350d4afacd825e43c8668eece89819caf6817af62dc4fbd82f0e33f6647b2b6bda175f14607f59f4635451e6b27df282ef73d8700003000010002a30001080101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b500003000010002a30001080100030803010001b6aec4b48567e2925a2d9c4fa4c96e6dddf86215a9bd8dd579c38ccb1199ed1be89946a7f72fc2633909a2792d0eed1b5afb2ee4c78d865a76d6cd9369d999c96af6be0a2274b8f2e9e0a0065bd20257570f08bc14c16f5616426881a83dbce6926e391c138a2ec317efa7349264de2e791c9b7d4a6048ee6eedf27bf1ece398ff0d229f18377cb1f6b98d1228ef217b8146c0c73851b89a6fc37c621ca187e16428a743ffea0072e185ef93e39525cee3ad01e0c94d2e511c8c313322c29ab91631e1856049a36898684c3056e5997473816fb547acb0be6e660bdfa89a5cb28b3669d8625f3f018c7b3b8a4860e774ee8261811ce7f96c461bc162c1a374f300002e00010002a3000113003008000002a30068a66180688ab2004f66007d114bf33e6d20e7588fdfde9a9e2a8ebd5593ce8bc06419e1d1a4afa8766abc1626504ea6243ca5fc9bce55a3f03c0e7eb488409690d84c3beb30f299da007ab69299d0e203c5b44b94328248768089a9b68982650e9ca2d37526307cbd9f06690e58c3c4a1703b1d1193ea0501417944b937b593294e339571eec42a3c700ce075d9c446e5d32bf979396c1c7935f69bd7df2826567fe582a3615d6095368be991b1e5dc39c0af3b0c39e0e353bbcb928e52e886193ac88da0cd8665ea992b642975aa5486f2e6514d0b5086c66ddd58fe8f7a27ecb128211e3ca1bdc4cad91f3cc9b63c526ebaea86075318e33bfc5a53c919e6f01262b24d178eb2cd04b1
This encodes address BC1QYYQ734DCNHHCWYW8YJXSWXG4P7K9NXU0QT84QZ to override.x_domain_cname_wild@dnssec_proof_tests.bitcoin.ninja valid on August 6, 2025.
3d6f766572726964652e785f646f6d61696e5f636e616d655f77696c6440646e737365635f70726f6f665f74657374732e626974636f696e2e6e696e6a61086f7665727269646513785f646f6d61696e5f636e616d655f77696c640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100001000010000001e003736424954434f494e3a3f42433d4243315159595137333444434e48484357595738594a58535758473450374b394e58553051543834515a086f7665727269646513785f646f6d61696e5f636e616d655f77696c640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100002e00010000001e006100100d070000001e68a5c51b68933b03d0e207626974636f696e056e696e6a61002076be9a243f968dad8a1fff2bce554e231998ca4e943a525a4ceb1d9cda053f7e95c4ca9e3fd5e9bd3af44b2d049c42a4f2f8fd273c9fb068267d6b9d69a2dc07626974636f696e056e696e6a6100003000010002a62900440100030dff753a27b08c3e48a642b210d6fcc444ff9ed4faf9c1241103db4ed3c19a95c3afbb52c0c02eb392ee048cc9e28ac2d272b1053bdc052bc18d5de05d7710196c07626974636f696e056e696e6a6100003000010002a62900440101030df65551925ce6321888e685981823d617fbc10f329bffe4081bf18c2372632a5548010bf62e6556a92722629275e0bd001e3d7837d325a353f6a851c5b965259607626974636f696e056e696e6a6100002e00010002a629006100300d0200093a806898c73468863d1c716c07626974636f696e056e696e6a610002fd1bf18c2ebb5ece5e28ca76bf30650695636c55633bccae8179c2d1ee7b97e78d188e08ffc869a8f67847bf557516ac12465ebea1acc281d6d636fdab612007626974636f696e056e696e6a6100002b000100000cda0024716c0d023f7ad5a303e9c1cd1474b8df2ae56f3f82da8637ca55db4d9a2bb85960ca698e07626974636f696e056e696e6a6100002b000100000cda0024768a0d02ce46a9aff9a06e789c1bdfe250b0ef6ba8d39a53b2a3427c551f5ad375e059b607626974636f696e056e696e6a6100002e000100000cda0099002b080200000e1068a89268688cd4d892dc056e696e6a61004d88897d7d5f5d920ca436e81ee67b1bb22f1a96309693454ab9d0b06434794162cc42846a4b51a40475a5b44e940c04dd1ac2c902a190ca2251ae89184520b0f3f22c12c51403d0a6e1cd95792e8f6f5036cd2d50dbdfa5eba3b2ee70ff78d40dc2eba2cc899af26954a55e5b5d344d478cabd9423418495caee45c550b1144056e696e6a61000030000100000e1000880100030803010001d28cb7e2bb163d5815838bedeca1006dde8551b379cb963c8a2cb42bc360127e3a5cf88ffc851a67414815b875f65d78c39b58d2fb29a1d4e76d50cb6b4a58a11fe2fb7c1b6db7bf7d72f5a1401e381c57fcc76f599cc73f05095d2bd14d9895e4fa1cff21bd760598a734b640102d11bc159c6b2ae73dbfd2741518142584d1056e696e6a61000030000100000e100088010003080301000197edb59d4f181e2761dd8d0465854339afc71fd89e47155981ddd175cdce79477552aeaf7b5a08fc4ac6025555f60582f2060e630edfb35b9c7cc30990fb9c3dc9f2fd036c962f67b94c9670d4ceaacd77973bca82ab7c9615f7e4320dda5b6d74dec673017c6fa448b5542a804e08ac873c509c1945ff734c320491e4b18e6d056e696e6a61000030000100000e1001080101030803010001c71e4c9dc49249a27b3ef42fcb8d56b4c3ac76715c7ad01c41d0d432590d15c3c62cee4b2d29ac35f2d72c9b32a70a0243cbd08aeebc9f6f1e0e63d9e1cdfe133c455a82435c0780b750012c942f7ed5b662eec8d9ae885a58993fa78d7561fedcd11d9e1c171acb02d0025837ba61a3c0a6756427414470c9ca0906b298168b5f4d9640e62e1b75dd06be664104ed32cfe447fa21f37401712c720a0dca4bb1bc20f3fa3103cad336bde20b16f73948e6b80dda0a528db536a958868c3870ecddcfb02dfb3cb4d22e2ad49a4b9f78c90ff6c7e10e301b3fb36fe859a94c30084660665741c14ff60d0535013fcf439840ecad82fc9278e4ace68ba95e708249056e696e6a6100002e000100000e1001190030080100000e1068a89268688cd4d8b402056e696e6a6100646e04cf5f76daa775ff98905ded3d2caad68d3198fc161340d558262c7ba7da28e7538a7f32d5a6485e4448037e8edf55759b7059fdc084f1017f790aa7c0d8f0e4af6c9af04e4afd16ce6052c30da59314c9c98075fd32bb77a81f34bea6190631b9d0a4351a764c14152ea217e6271647bf95b0df4c3d7cc00937bec01b65ad1b5209c976a4843e399f173f196a012c0876bc9afa3457d940d6ad7b9d50b3d496836d7342cf3aec75ac4785563e20574ddd2dab1cfb6b5da32508edf7186aa516b0451b221251652ee44353710cbe35928b79fff4293c5e8eff7ab371ce43595e2300305bda0108b911c3ef7d4d15c70d68686fddf28422d5fcbcdb967e84056e696e6a6100002b0001000151800024b4020802c8f816a7a575bdb2f997f682aab2653ba2cb5eddb69b036a30742a33befaf141056e696e6a6100002e0001000151800113002b08010001518068a404d06892d340b5690081d888ee9bd744185f24bfbaaae70172bb03b6c0a899dcd6801c44b2e3e6acd5fe2192f4f06e5690ace176cb08557f2d5ceef5e9d9eb72f4f639dcf34650eebdef5cb91cd546fbdbd8a529d7ef9bb2168160ae800790d7a7266b531174d8d9be06cad2f1d0f062d9431f7de4beceb02f30ddc97bba44535a703e2d3cc01d2341bb48eb7b25d938f0ed2a7d4c53818e7cb883dc14ffce5899504265869fd3133953c96f48b99ff2055acd53b9f69d2eb8a911bb1f05e2fb8d1d0cc391e1b9ae19fc32b00727a9d8551e1a09319ba94da44cc317bb66e8f372385560cdf8455f858d4afd602307d982d996f729a16c263efa9b8cebe7862b7f9a88ac9fbaf445a600003000010002a30001080100030803010001b6aec4b48567e2925a2d9c4fa4c96e6dddf86215a9bd8dd579c38ccb1199ed1be89946a7f72fc2633909a2792d0eed1b5afb2ee4c78d865a76d6cd9369d999c96af6be0a2274b8f2e9e0a0065bd20257570f08bc14c16f5616426881a83dbce6926e391c138a2ec317efa7349264de2e791c9b7d4a6048ee6eedf27bf1ece398ff0d229f18377cb1f6b98d1228ef217b8146c0c73851b89a6fc37c621ca187e16428a743ffea0072e185ef93e39525cee3ad01e0c94d2e511c8c313322c29ab91631e1856049a36898684c3056e5997473816fb547acb0be6e660bdfa89a5cb28b3669d8625f3f018c7b3b8a4860e774ee8261811ce7f96c461bc162c1a374f300003000010002a30001080101030803010001af7a8deba49d995a792aefc80263e991efdbc86138a931deb2c65d5682eab5d3b03738e3dfdc89d96da64c86c0224d9ce02514d285da3068b19054e5e787b2969058e98e12566c8c808c40c0b769e1db1a24a1bd9b31e303184a31fc7bb56b85bbba8abc02cd5040a444a36d47695969849e16ad856bb58e8fac8855224400319bdab224d83fc0e66aab32ff74bfeaf0f91c454e6850a1295207bbd4cdde8f6ffb08faa9755c2e3284efa01f99393e18786cb132f1e66ebc6517318e1ce8a3b7337ebb54d035ab57d9706ecd9350d4afacd825e43c8668eece89819caf6817af62dc4fbd82f0e33f6647b2b6bda175f14607f59f4635451e6b27df282ef73d8700003000010002a30001080100030803010001b11b182a464c3adc6535aa59613bda7a61cac86945c20b773095941194f4b9f516e8bd924b1e50e3fe83918b51e54529d4e5a1e45303df8462241d5e05979979ae5bf9c6c598c08a496e17f3bd3732d5aebe62667b61db1bbe178f27ac99408165a230d6aee78348e6c67789541f845b2ada96667f8dd16ae44f9e260c4a138b3bb1015965ebe609434a06464bd7d29bac47c3017e83c0f89bca1a9e3bdd0813715f3484292df589bc632e27d37efc02837cb85d770d5bd53a36edc99a8294771aa93cf22406f5506c8cf850ed85c1a475dee5c2d3700b3f5631d903524b849995c20cb407ed411f70b428ae3d642716fe239335aa961a752e67fb6dca0bf72900003000010002a30001080101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b500002e00010002a3000113003008000002a30068a66180688ab2004f66007d114bf33e6d20e7588fdfde9a9e2a8ebd5593ce8bc06419e1d1a4afa8766abc1626504ea6243ca5fc9bce55a3f03c0e7eb488409690d84c3beb30f299da007ab69299d0e203c5b44b94328248768089a9b68982650e9ca2d37526307cbd9f06690e58c3c4a1703b1d1193ea0501417944b937b593294e339571eec42a3c700ce075d9c446e5d32bf979396c1c7935f69bd7df2826567fe582a3615d6095368be991b1e5dc39c0af3b0c39e0e353bbcb928e52e886193ac88da0cd8665ea992b642975aa5486f2e6514d0b5086c66ddd58fe8f7a27ecb128211e3ca1bdc4cad91f3cc9b63c526ebaea86075318e33bfc5a53c919e6f01262b24d178eb2cd04b1
The following encodes both the on-chain address bc1qztwy6xen3zdtt7z0vrgapmjtfz8acjkfp5fp7l and the BOLT 12 offer lno1zr5qyugqgskrk70kqmuq7v3dnr2fnmhukps9n8hut48vkqpqnskt2svsqwjakp7k6pyhtkuxw7y2kqmsxlwruhzqv0zsnhh9q3t9xhx39suc6qsr07ekm5esdyum0w66mnx8vdquwvp7dp5jp7j3v5cp6aj0w329fnkqqv60q96sz5nkrc5r95qffx002q53tqdk8x9m2tmt85jtpmcycvfnrpx3lr45h2g7na3sec7xguctfzzcm8jjqtj5ya27te60j03vpt0vq9tm2n9yxl2hngfnmygesa25s4u4zlxewqpvp94xt7rur4rhxunwkthk9vly3lm5hh0pqv4aymcqejlgssnlpzwlggykkajp7yjs5jvr2agkyypcdlj280cy46jpynsezrcj2kwa2lyr8xvd6lfkph4xrxtk2xc3lpq to a.x_domain_cname_wild@dnssec_proof_tests.bitcoin.ninja valid on August 6, 2025. Note that it requires following a CNAME to a different domain.
36612e785f646f6d61696e5f636e616d655f77696c6440646e737365635f70726f6f665f74657374732e626974636f696e2e6e696e6a61056e696e6a6100002b0001000151800024b4020802c8f816a7a575bdb2f997f682aab2653ba2cb5eddb69b036a30742a33befaf14107626974636f696e056e696e6a6100003000010002a54400440100030dff753a27b08c3e48a642b210d6fcc444ff9ed4faf9c1241103db4ed3c19a95c3afbb52c0c02eb392ee048cc9e28ac2d272b1053bdc052bc18d5de05d7710196c056e696e6a6100002e000100000d2b01190030080100000e1068a89268688cd4d8b402056e696e6a6100646e04cf5f76daa775ff98905ded3d2caad68d3198fc161340d558262c7ba7da28e7538a7f32d5a6485e4448037e8edf55759b7059fdc084f1017f790aa7c0d8f0e4af6c9af04e4afd16ce6052c30da59314c9c98075fd32bb77a81f34bea6190631b9d0a4351a764c14152ea217e6271647bf95b0df4c3d7cc00937bec01b65ad1b5209c976a4843e399f173f196a012c0876bc9afa3457d940d6ad7b9d50b3d496836d7342cf3aec75ac4785563e20574ddd2dab1cfb6b5da32508edf7186aa516b0451b221251652ee44353710cbe35928b79fff4293c5e8eff7ab371ce43595e2300305bda0108b911c3ef7d4d15c70d68686fddf28422d5fcbcdb967e84056e696e6a6100002e0001000151800113002b08010001518068a404d06892d340b5690081d888ee9bd744185f24bfbaaae70172bb03b6c0a899dcd6801c44b2e3e6acd5fe2192f4f06e5690ace176cb08557f2d5ceef5e9d9eb72f4f639dcf34650eebdef5cb91cd546fbdbd8a529d7ef9bb2168160ae800790d7a7266b531174d8d9be06cad2f1d0f062d9431f7de4beceb02f30ddc97bba44535a703e2d3cc01d2341bb48eb7b25d938f0ed2a7d4c53818e7cb883dc14ffce5899504265869fd3133953c96f48b99ff2055acd53b9f69d2eb8a911bb1f05e2fb8d1d0cc391e1b9ae19fc32b00727a9d8551e1a09319ba94da44cc317bb66e8f372385560cdf8455f858d4afd602307d982d996f729a16c263efa9b8cebe7862b7f9a88ac9fbaf445a6056e696e6a61000030000100000d2b00880100030803010001d28cb7e2bb163d5815838bedeca1006dde8551b379cb963c8a2cb42bc360127e3a5cf88ffc851a67414815b875f65d78c39b58d2fb29a1d4e76d50cb6b4a58a11fe2fb7c1b6db7bf7d72f5a1401e381c57fcc76f599cc73f05095d2bd14d9895e4fa1cff21bd760598a734b640102d11bc159c6b2ae73dbfd2741518142584d107626974636f696e056e696e6a6100002b000100000bf50024716c0d023f7ad5a303e9c1cd1474b8df2ae56f3f82da8637ca55db4d9a2bb85960ca698e00003000010002a30001080100030803010001b11b182a464c3adc6535aa59613bda7a61cac86945c20b773095941194f4b9f516e8bd924b1e50e3fe83918b51e54529d4e5a1e45303df8462241d5e05979979ae5bf9c6c598c08a496e17f3bd3732d5aebe62667b61db1bbe178f27ac99408165a230d6aee78348e6c67789541f845b2ada96667f8dd16ae44f9e260c4a138b3bb1015965ebe609434a06464bd7d29bac47c3017e83c0f89bca1a9e3bdd0813715f3484292df589bc632e27d37efc02837cb85d770d5bd53a36edc99a8294771aa93cf22406f5506c8cf850ed85c1a475dee5c2d3700b3f5631d903524b849995c20cb407ed411f70b428ae3d642716fe239335aa961a752e67fb6dca0bf7290b6d617474636f72616c6c6f03636f6d00003000010003d52200440101030dec7c1fa1752495c42d2224eace96ed74144e9cb811608dd91594974bdc723fdc5b38a37c3340f1deca68a7ec82248822954b2994de5ac99ff6e9db95fd42c94b00003000010002a30001080101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b507626974636f696e056e696e6a6100002e000100000bf50099002b080200000e1068a89268688cd4d892dc056e696e6a61004d88897d7d5f5d920ca436e81ee67b1bb22f1a96309693454ab9d0b06434794162cc42846a4b51a40475a5b44e940c04dd1ac2c902a190ca2251ae89184520b0f3f22c12c51403d0a6e1cd95792e8f6f5036cd2d50dbdfa5eba3b2ee70ff78d40dc2eba2cc899af26954a55e5b5d344d478cabd9423418495caee45c550b114403636f6d00002e000100000266005700300d0100015180689f3dfb688b764f4d0603636f6d00d87373f3d5d404f7cdc3aace633c96357bc606ced620792597e1308b1d6c5902668c4d3c1a37bab8486ba24485d57a9d98157fe706424b2043bfb40306d01484046d6174740475736572105f626974636f696e2d7061796d656e740b6d617474636f72616c6c6f03636f6d00002e000100000e10006300100d0500000e1068a57e5a6892f44226480b6d617474636f72616c6c6f03636f6d004515e7d3cdf4137c316d4d36972fab9273df457789a9fabb16c4689e1644ae9080c7505e06daebc136d3c43054d0c69d185ac5616afca8998edf828e63a68286206f3266653035326d646a61336638746c3563353667706668646661696661687007626974636f696e056e696e6a6100003200010000001e002201000000083c92990db9cddbc614c8e4a40e1317cc888750fad000dab671a24e1a3a056e696e6a61000030000100000d2b01080101030803010001c71e4c9dc49249a27b3ef42fcb8d56b4c3ac76715c7ad01c41d0d432590d15c3c62cee4b2d29ac35f2d72c9b32a70a0243cbd08aeebc9f6f1e0e63d9e1cdfe133c455a82435c0780b750012c942f7ed5b662eec8d9ae885a58993fa78d7561fedcd11d9e1c171acb02d0025837ba61a3c0a6756427414470c9ca0906b298168b5f4d9640e62e1b75dd06be664104ed32cfe447fa21f37401712c720a0dca4bb1bc20f3fa3103cad336bde20b16f73948e6b80dda0a528db536a958868c3870ecddcfb02dfb3cb4d22e2ad49a4b9f78c90ff6c7e10e301b3fb36fe859a94c30084660665741c14ff60d0535013fcf439840ecad82fc9278e4ace68ba95e7082490b6d617474636f72616c6c6f03636f6d00002b0001000151800024e2f50d02f0e161567d468087ff27b051abc94476178a7cb635da1aa705e05c77ca81de520b6d617474636f72616c6c6f03636f6d00002e0001000151800057002b0d0200015180689a991368914e2b504103636f6d0070ac13ac37043e66f191553c554ee9307a91a4cf27bd724949e52032a2b464cadb776cd362918159344d9685b84650436449914f25fc62cc6dd6b761f565828303636f6d00002b00010001518000244d060d028acbb0cd28f41250a80a491389424d341522d946b0da0c0291f2d3d771d7805a0b6d617474636f72616c6c6f03636f6d00002e00010003d522006300300d0200093a80689c35ca6889abb2e2f50b6d617474636f72616c6c6f03636f6d0016857529219dd561091a51c72a27e25d963094f8dcd93b11f0917d45466251acb1402bb6fa4529bd20b7db697df429c4ba830685fc290ee5a8a937c2d34530c007626974636f696e056e696e6a6100003000010002a54400440101030df65551925ce6321888e685981823d617fbc10f329bffe4081bf18c2372632a5548010bf62e6556a92722629275e0bd001e3d7837d325a353f6a851c5b9652596016113785f646f6d61696e5f636e616d655f77696c640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100002e00010000001e006100050d060000001e68a4c58868923b70d0e207626974636f696e056e696e6a6100849202c2306be651b9a5901331d9bf363e74ba758c16e993c4f93fe4c1a08e7bc46baa64b22e9540435b4b6b83fc4800c58d27bd9b2fe82d02ed6d6f9059cfa50b6d617474636f72616c6c6f03636f6d00003000010003d52200440100030dfd9dbc34cb5053a2c4a6b3d0dc60fc65d8a992dc1e080f6deeddba7fe6b25217730de64c9a1ce986b3f81f556881fe0e7b5b20c8ae381c4fefdbc311aa7d22ee206f3266653035326d646a61336638746c3563353667706668646661696661687007626974636f696e056e696e6a6100002e00010000001e006100320d030000003c68a5076a68927d52d0e207626974636f696e056e696e6a6100620532890060f3f82a90a05ab32afe628ef58a58fbed98df2fbb1d3d00064b05111503f67cbd0f485f6196f007ddb3e6ec087e31f94221bf2b388179d31373b203636f6d00003000010000026600440101030db71f0465101ddbe2bf0c9455d12fa16c1cda44f4bf1ba2553418ad1f3aa9b06973f21b84eb532cf4035ee8d4832ca26d89306a7d32560c0cb0129d450ac10835016113785f646f6d61696e5f636e616d655f77696c640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100000500010000001e002c046d6174740475736572105f626974636f696e2d7061796d656e740b6d617474636f72616c6c6f03636f6d0007626974636f696e056e696e6a6100002b000100000bf50024768a0d02ce46a9aff9a06e789c1bdfe250b0ef6ba8d39a53b2a3427c551f5ad375e059b60b6d617474636f72616c6c6f03636f6d00003000010003d52200440100030d8b1cf07c86f18c19c8c3146db093893648dcc1ab5fb79e99ccbab4aa06f98d52ac27b92e215d9da98d7535f3c2ce038fbb9d41b9c63d3845d444feffc1f71ed703636f6d00002e0001000151800113002b08010001518068a404d06892d340b5690024fbea2f86eb0e472114b9da41f1da69e4ef2d02ffcd6bdd987239f288795603d5f54308b238ef19f2747d6a1bc0e775782025561b0f14d1dd19be6bf36b495a3e2d538d5532c5c6e1056c06aa4e81de07f637313955a7761d313db0c6cd0b5c17b4ee22d530d6cdc0c4e195df85b354bbe32027537f1ca21f2815b2d0dbd154582124b3c4c27f1c3aea16f6bfe7e6f5c80aaccd61601bdd8f947ef5c30f004482617cf97629b8b89d8e7320719c979c6a9defdf79b743ecef08bdf2f90796da018fdc6be1e0629fe706044e0f8ad1b25927eca09074a502eb9136eefe5903ad3f97866ab014f1ec96e1f38e3aba66520a25ace386f4897e1ecfd774ce0a0f8a03636f6d00003000010000026600440100030df17b60fb56d522f8634153e785c0a978532ea76de39d34bb356d3d042e07f29f7b992176cc83acef7b78ea750425203b18f2b8228b3cdd2bc7eb13c3e3035a7e0b6d617474636f72616c6c6f03636f6d00002b00010001518000249f000d02594d2813e04a1d2660ff3c0afc5579b9ec0fe72cc206dc6f248bbe6dd652e19500002e00010002a3000113003008000002a30068a66180688ab2004f66007d114bf33e6d20e7588fdfde9a9e2a8ebd5593ce8bc06419e1d1a4afa8766abc1626504ea6243ca5fc9bce55a3f03c0e7eb488409690d84c3beb30f299da007ab69299d0e203c5b44b94328248768089a9b68982650e9ca2d37526307cbd9f06690e58c3c4a1703b1d1193ea0501417944b937b593294e339571eec42a3c700ce075d9c446e5d32bf979396c1c7935f69bd7df2826567fe582a3615d6095368be991b1e5dc39c0af3b0c39e0e353bbcb928e52e886193ac88da0cd8665ea992b642975aa5486f2e6514d0b5086c66ddd58fe8f7a27ecb128211e3ca1bdc4cad91f3cc9b63c526ebaea86075318e33bfc5a53c919e6f01262b24d178eb2cd04b100003000010002a30001080100030803010001b6aec4b48567e2925a2d9c4fa4c96e6dddf86215a9bd8dd579c38ccb1199ed1be89946a7f72fc2633909a2792d0eed1b5afb2ee4c78d865a76d6cd9369d999c96af6be0a2274b8f2e9e0a0065bd20257570f08bc14c16f5616426881a83dbce6926e391c138a2ec317efa7349264de2e791c9b7d4a6048ee6eedf27bf1ece398ff0d229f18377cb1f6b98d1228ef217b8146c0c73851b89a6fc37c621ca187e16428a743ffea0072e185ef93e39525cee3ad01e0c94d2e511c8c313322c29ab91631e1856049a36898684c3056e5997473816fb547acb0be6e660bdfa89a5cb28b3669d8625f3f018c7b3b8a4860e774ee8261811ce7f96c461bc162c1a374f3046d6174740475736572105f626974636f696e2d7061796d656e740b6d617474636f72616c6c6f03636f6d000010000100000e1001ecff626974636f696e3a626331717a7477793678656e337a647474377a3076726761706d6a74667a3861636a6b6670356670376c3f6c6e6f3d6c6e6f317a7235717975677167736b726b37306b716d7571377633646e7232666e6d68756b7073396e386875743438766b7170716e736b743273767371776a616b70376b36707968746b7578773779326b716d73786c777275687a7176307a736e686839713374397868783339737563367173723037656b6d3565736479756d307736366d6e783876647175777670376470356a70376a337635637036616a3077333239666e6b7171763630713936737a356e6b726335723935716666783030327135337471646beb3878396d32746d7438356a74706d63796376666e727078336c723435683267376e6133736563377867756374667a7a636d386a6a71746a3579613237746536306a303376707430767139746d326e3979786c32686e67666e6d79676573613235733475347a6c78657771707670393478743772757234726878756e776b74686b39766c79336c6d356868307071763461796d6371656a6c6773736e6c707a776c6767796b6b616a7037796a73356a76723261676b79797063646c6a323830637934366a70796e73657a72636a326b7761326c797238787664366c666b706834787278746b327863336c707100003000010002a30001080101030803010001af7a8deba49d995a792aefc80263e991efdbc86138a931deb2c65d5682eab5d3b03738e3dfdc89d96da64c86c0224d9ce02514d285da3068b19054e5e787b2969058e98e12566c8c808c40c0b769e1db1a24a1bd9b31e303184a31fc7bb56b85bbba8abc02cd5040a444a36d47695969849e16ad856bb58e8fac8855224400319bdab224d83fc0e66aab32ff74bfeaf0f91c454e6850a1295207bbd4cdde8f6ffb08faa9755c2e3284efa01f99393e18786cb132f1e66ebc6517318e1ce8a3b7337ebb54d035ab57d9706ecd9350d4afacd825e43c8668eece89819caf6817af62dc4fbd82f0e33f6647b2b6bda175f14607f59f4635451e6b27df282ef73d8707626974636f696e056e696e6a6100002e00010002a544006100300d0200093a806898c73468863d1c716c07626974636f696e056e696e6a610002fd1bf18c2ebb5ece5e28ca76bf30650695636c55633bccae8179c2d1ee7b97e78d188e08ffc869a8f67847bf557516ac12465ebea1acc281d6d636fdab6120056e696e6a61000030000100000d2b0088010003080301000197edb59d4f181e2761dd8d0465854339afc71fd89e47155981ddd175cdce79477552aeaf7b5a08fc4ac6025555f60582f2060e630edfb35b9c7cc30990fb9c3dc9f2fd036c962f67b94c9670d4ceaacd77973bca82ab7c9615f7e4320dda5b6d74dec673017c6fa448b5542a804e08ac873c509c1945ff734c320491e4b18e6d
The following is an *invalid* DNSSEC proof when included in the PSBT_OUT_DNSSEC_PROOF record of a PSBT.
The following encodes the on-chain address bc1qztwy6xen3zdtt7z0vrgapmjtfz8acjkfp5fp7l to invalid@dnssec_proof_tests.bitcoin.ninja but is '''invalid'''.
This proof contains two TXT records which start with, case insensitively, "bitcoin:". It is a valid DNSSEC proof but should fail BIP 353-specific validation.
28696e76616c696440646e737365635f70726f6f665f74657374732e626974636f696e2e6e696e6a6107696e76616c69640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100001000010000001e003736426954634f694e3a3f42433d626331717a7477793678656e337a647474377a3076726761706d6a74667a3861636a6b6670356670376c07696e76616c69640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100001000010000001e003736626974636f696e3a3f62633d626331717a7477793678656e337a647474377a3076726761706d6a74667a3861636a6b6670356670376c07696e76616c69640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100002e00010000001e006100100d060000001e68a70b256894810dd0e207626974636f696e056e696e6a6100a7ed29b28f64a885e6496f080befc724da98afe8879a985c1f82b15dc6f97cf595b8a3b62edc58870291448a7f4017fba8c3e8380ab32a0883439fba965773ac07626974636f696e056e696e6a610000300001000161f300440100030dff753a27b08c3e48a642b210d6fcc444ff9ed4faf9c1241103db4ed3c19a95c3afbb52c0c02eb392ee048cc9e28ac2d272b1053bdc052bc18d5de05d7710196c07626974636f696e056e696e6a610000300001000161f300440101030df65551925ce6321888e685981823d617fbc10f329bffe4081bf18c2372632a5548010bf62e6556a92722629275e0bd001e3d7837d325a353f6a851c5b965259607626974636f696e056e696e6a6100002e0001000161f3006100300d0200093a806898c73468863d1c716c07626974636f696e056e696e6a610002fd1bf18c2ebb5ece5e28ca76bf30650695636c55633bccae8179c2d1ee7b97e78d188e08ffc869a8f67847bf557516ac12465ebea1acc281d6d636fdab612007626974636f696e056e696e6a6100002b000100000daa0024716c0d023f7ad5a303e9c1cd1474b8df2ae56f3f82da8637ca55db4d9a2bb85960ca698e07626974636f696e056e696e6a6100002b000100000daa0024768a0d02ce46a9aff9a06e789c1bdfe250b0ef6ba8d39a53b2a3427c551f5ad375e059b607626974636f696e056e696e6a6100002e000100000daa0099002b080200000e1068a89268688cd4d892dc056e696e6a61004d88897d7d5f5d920ca436e81ee67b1bb22f1a96309693454ab9d0b06434794162cc42846a4b51a40475a5b44e940c04dd1ac2c902a190ca2251ae89184520b0f3f22c12c51403d0a6e1cd95792e8f6f5036cd2d50dbdfa5eba3b2ee70ff78d40dc2eba2cc899af26954a55e5b5d344d478cabd9423418495caee45c550b1144056e696e6a61000030000100000daa01080101030803010001c71e4c9dc49249a27b3ef42fcb8d56b4c3ac76715c7ad01c41d0d432590d15c3c62cee4b2d29ac35f2d72c9b32a70a0243cbd08aeebc9f6f1e0e63d9e1cdfe133c455a82435c0780b750012c942f7ed5b662eec8d9ae885a58993fa78d7561fedcd11d9e1c171acb02d0025837ba61a3c0a6756427414470c9ca0906b298168b5f4d9640e62e1b75dd06be664104ed32cfe447fa21f37401712c720a0dca4bb1bc20f3fa3103cad336bde20b16f73948e6b80dda0a528db536a958868c3870ecddcfb02dfb3cb4d22e2ad49a4b9f78c90ff6c7e10e301b3fb36fe859a94c30084660665741c14ff60d0535013fcf439840ecad82fc9278e4ace68ba95e708249056e696e6a61000030000100000daa0088010003080301000197edb59d4f181e2761dd8d0465854339afc71fd89e47155981ddd175cdce79477552aeaf7b5a08fc4ac6025555f60582f2060e630edfb35b9c7cc30990fb9c3dc9f2fd036c962f67b94c9670d4ceaacd77973bca82ab7c9615f7e4320dda5b6d74dec673017c6fa448b5542a804e08ac873c509c1945ff734c320491e4b18e6d056e696e6a61000030000100000daa00880100030803010001d28cb7e2bb163d5815838bedeca1006dde8551b379cb963c8a2cb42bc360127e3a5cf88ffc851a67414815b875f65d78c39b58d2fb29a1d4e76d50cb6b4a58a11fe2fb7c1b6db7bf7d72f5a1401e381c57fcc76f599cc73f05095d2bd14d9895e4fa1cff21bd760598a734b640102d11bc159c6b2ae73dbfd2741518142584d1056e696e6a6100002e000100000daa01190030080100000e1068a89268688cd4d8b402056e696e6a6100646e04cf5f76daa775ff98905ded3d2caad68d3198fc161340d558262c7ba7da28e7538a7f32d5a6485e4448037e8edf55759b7059fdc084f1017f790aa7c0d8f0e4af6c9af04e4afd16ce6052c30da59314c9c98075fd32bb77a81f34bea6190631b9d0a4351a764c14152ea217e6271647bf95b0df4c3d7cc00937bec01b65ad1b5209c976a4843e399f173f196a012c0876bc9afa3457d940d6ad7b9d50b3d496836d7342cf3aec75ac4785563e20574ddd2dab1cfb6b5da32508edf7186aa516b0451b221251652ee44353710cbe35928b79fff4293c5e8eff7ab371ce43595e2300305bda0108b911c3ef7d4d15c70d68686fddf28422d5fcbcdb967e84056e696e6a6100002b0001000151800024b4020802c8f816a7a575bdb2f997f682aab2653ba2cb5eddb69b036a30742a33befaf141056e696e6a6100002e0001000151800113002b08010001518068a55650689424c0b569007f4d7bbce2d77380e115f8469a3c6d1d4bd9be1145eeee843332f1d54da134a25f7d259ccfa36a2e833106139ba37bc28651b7717dabfc8c450e889c5d5d6d39d12f1004252fa08692794af4a7f29a94f6611f9b000ba899d90d6a32e91c54e63720811546b251fb265b7f62615391ab330f83a96841f0367347e67522112f63f3efda891ae0f7265ed5b89673f184027cdb9b5e94b16a9b1f99877cc8e078abf246cad1f76a48a34474977dbd89dd3b41f381df89a82e2939aeb06830f656253e4e347cd04ee6dba0c8377e818f919f80a7e6aefa0f8196d04845bc26b498b0115022ff75e363711e55337de505e50df69b840699160467516d15e8235aa4cf00003000010002a30001080101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b500003000010002a30001080100030803010001b6aec4b48567e2925a2d9c4fa4c96e6dddf86215a9bd8dd579c38ccb1199ed1be89946a7f72fc2633909a2792d0eed1b5afb2ee4c78d865a76d6cd9369d999c96af6be0a2274b8f2e9e0a0065bd20257570f08bc14c16f5616426881a83dbce6926e391c138a2ec317efa7349264de2e791c9b7d4a6048ee6eedf27bf1ece398ff0d229f18377cb1f6b98d1228ef217b8146c0c73851b89a6fc37c621ca187e16428a743ffea0072e185ef93e39525cee3ad01e0c94d2e511c8c313322c29ab91631e1856049a36898684c3056e5997473816fb547acb0be6e660bdfa89a5cb28b3669d8625f3f018c7b3b8a4860e774ee8261811ce7f96c461bc162c1a374f300003000010002a30001080100030803010001b11b182a464c3adc6535aa59613bda7a61cac86945c20b773095941194f4b9f516e8bd924b1e50e3fe83918b51e54529d4e5a1e45303df8462241d5e05979979ae5bf9c6c598c08a496e17f3bd3732d5aebe62667b61db1bbe178f27ac99408165a230d6aee78348e6c67789541f845b2ada96667f8dd16ae44f9e260c4a138b3bb1015965ebe609434a06464bd7d29bac47c3017e83c0f89bca1a9e3bdd0813715f3484292df589bc632e27d37efc02837cb85d770d5bd53a36edc99a8294771aa93cf22406f5506c8cf850ed85c1a475dee5c2d3700b3f5631d903524b849995c20cb407ed411f70b428ae3d642716fe239335aa961a752e67fb6dca0bf72900003000010002a30001080101030803010001af7a8deba49d995a792aefc80263e991efdbc86138a931deb2c65d5682eab5d3b03738e3dfdc89d96da64c86c0224d9ce02514d285da3068b19054e5e787b2969058e98e12566c8c808c40c0b769e1db1a24a1bd9b31e303184a31fc7bb56b85bbba8abc02cd5040a444a36d47695969849e16ad856bb58e8fac8855224400319bdab224d83fc0e66aab32ff74bfeaf0f91c454e6850a1295207bbd4cdde8f6ffb08faa9755c2e3284efa01f99393e18786cb132f1e66ebc6517318e1ce8a3b7337ebb54d035ab57d9706ecd9350d4afacd825e43c8668eece89819caf6817af62dc4fbd82f0e33f6647b2b6bda175f14607f59f4635451e6b27df282ef73d8700002e00010002a3000113003008000002a30068a66180688ab2004f66007d114bf33e6d20e7588fdfde9a9e2a8ebd5593ce8bc06419e1d1a4afa8766abc1626504ea6243ca5fc9bce55a3f03c0e7eb488409690d84c3beb30f299da007ab69299d0e203c5b44b94328248768089a9b68982650e9ca2d37526307cbd9f06690e58c3c4a1703b1d1193ea0501417944b937b593294e339571eec42a3c700ce075d9c446e5d32bf979396c1c7935f69bd7df2826567fe582a3615d6095368be991b1e5dc39c0af3b0c39e0e353bbcb928e52e886193ac88da0cd8665ea992b642975aa5486f2e6514d0b5086c66ddd58fe8f7a27ecb128211e3ca1bdc4cad91f3cc9b63c526ebaea86075318e33bfc5a53c919e6f01262b24d178eb2cd04b1
The following encodes both the on-chain address bc1qztwy6xen3zdtt7z0vrgapmjtfz8acjkfp5fp7l and the BOLT 12 offer lno1zr5qyugqgskrk70kqmuq7v3dnr2fnmhukps9n8hut48vkqpqnskt2svsqwjakp7k6pyhtkuxw7y2kqmsxlwruhzqv0zsnhh9q3t9xhx39suc6qsr07ekm5esdyum0w66mnx8vdquwvp7dp5jp7j3v5cp6aj0w329fnkqqv60q96sz5nkrc5r95qffx002q53tqdk8x9m2tmt85jtpmcycvfnrpx3lr45h2g7na3sec7xguctfzzcm8jjqtj5ya27te60j03vpt0vq9tm2n9yxl2hngfnmygesa25s4u4zlxewqpvp94xt7rur4rhxunwkthk9vly3lm5hh0pqv4aymcqejlgssnlpzwlggykkajp7yjs5jvr2agkyypcdlj280cy46jpynsezrcj2kwa2lyr8xvd6lfkph4xrxtk2xc3lpq to a.x_domain_cname_wild@dnssec_proof_tests.bitcoin.ninja but is '''invalid'''.
This proof is missing the required NSEC3 record to prove the lack of an override to the wildcard CNAME entry.
36612e785f646f6d61696e5f636e616d655f77696c6440646e737365635f70726f6f665f74657374732e626974636f696e2e6e696e6a61016113785f646f6d61696e5f636e616d655f77696c640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100000500010000001e002c046d6174740475736572105f626974636f696e2d7061796d656e740b6d617474636f72616c6c6f03636f6d00016113785f646f6d61696e5f636e616d655f77696c640475736572105f626974636f696e2d7061796d656e7412646e737365635f70726f6f665f746573747307626974636f696e056e696e6a6100002e00010000001e006100050d060000001e68a4c58868923b70d0e207626974636f696e056e696e6a6100849202c2306be651b9a5901331d9bf363e74ba758c16e993c4f93fe4c1a08e7bc46baa64b22e9540435b4b6b83fc4800c58d27bd9b2fe82d02ed6d6f9059cfa5046d6174740475736572105f626974636f696e2d7061796d656e740b6d617474636f72616c6c6f03636f6d000010000100000e1001ecff626974636f696e3a626331717a7477793678656e337a647474377a3076726761706d6a74667a3861636a6b6670356670376c3f6c6e6f3d6c6e6f317a7235717975677167736b726b37306b716d7571377633646e7232666e6d68756b7073396e386875743438766b7170716e736b743273767371776a616b70376b36707968746b7578773779326b716d73786c777275687a7176307a736e686839713374397868783339737563367173723037656b6d3565736479756d307736366d6e783876647175777670376470356a70376a337635637036616a3077333239666e6b7171763630713936737a356e6b726335723935716666783030327135337471646beb3878396d32746d7438356a74706d63796376666e727078336c723435683267376e6133736563377867756374667a7a636d386a6a71746a3579613237746536306a303376707430767139746d326e3979786c32686e67666e6d79676573613235733475347a6c78657771707670393478743772757234726878756e776b74686b39766c79336c6d356868307071763461796d6371656a6c6773736e6c707a776c6767796b6b616a7037796a73356a76723261676b79797063646c6a323830637934366a70796e73657a72636a326b7761326c797238787664366c666b706834787278746b327863336c7071046d6174740475736572105f626974636f696e2d7061796d656e740b6d617474636f72616c6c6f03636f6d00002e000100000e10006300100d0500000e1068a57e5a6892f44226480b6d617474636f72616c6c6f03636f6d004515e7d3cdf4137c316d4d36972fab9273df457789a9fabb16c4689e1644ae9080c7505e06daebc136d3c43054d0c69d185ac5616afca8998edf828e63a68286206f3266653035326d646a61336638746c3563353667706668646661696661687007626974636f696e056e696e6a6100002e00010000001e006100320d030000003c68a5076a68927d52d0e207626974636f696e056e696e6a6100620532890060f3f82a90a05ab32afe628ef58a58fbed98df2fbb1d3d00064b05111503f67cbd0f485f6196f007ddb3e6ec087e31f94221bf2b388179d31373b207626974636f696e056e696e6a6100003000010002a54400440100030dff753a27b08c3e48a642b210d6fcc444ff9ed4faf9c1241103db4ed3c19a95c3afbb52c0c02eb392ee048cc9e28ac2d272b1053bdc052bc18d5de05d7710196c07626974636f696e056e696e6a6100003000010002a54400440101030df65551925ce6321888e685981823d617fbc10f329bffe4081bf18c2372632a5548010bf62e6556a92722629275e0bd001e3d7837d325a353f6a851c5b965259607626974636f696e056e696e6a6100002e00010002a544006100300d0200093a806898c73468863d1c716c07626974636f696e056e696e6a610002fd1bf18c2ebb5ece5e28ca76bf30650695636c55633bccae8179c2d1ee7b97e78d188e08ffc869a8f67847bf557516ac12465ebea1acc281d6d636fdab612007626974636f696e056e696e6a6100002b000100000bf50024768a0d02ce46a9aff9a06e789c1bdfe250b0ef6ba8d39a53b2a3427c551f5ad375e059b607626974636f696e056e696e6a6100002b000100000bf50024716c0d023f7ad5a303e9c1cd1474b8df2ae56f3f82da8637ca55db4d9a2bb85960ca698e07626974636f696e056e696e6a6100002e000100000bf50099002b080200000e1068a89268688cd4d892dc056e696e6a61004d88897d7d5f5d920ca436e81ee67b1bb22f1a96309693454ab9d0b06434794162cc42846a4b51a40475a5b44e940c04dd1ac2c902a190ca2251ae89184520b0f3f22c12c51403d0a6e1cd95792e8f6f5036cd2d50dbdfa5eba3b2ee70ff78d40dc2eba2cc899af26954a55e5b5d344d478cabd9423418495caee45c550b11440b6d617474636f72616c6c6f03636f6d00003000010003d52200440100030d8b1cf07c86f18c19c8c3146db093893648dcc1ab5fb79e99ccbab4aa06f98d52ac27b92e215d9da98d7535f3c2ce038fbb9d41b9c63d3845d444feffc1f71ed70b6d617474636f72616c6c6f03636f6d00003000010003d52200440101030dec7c1fa1752495c42d2224eace96ed74144e9cb811608dd91594974bdc723fdc5b38a37c3340f1deca68a7ec82248822954b2994de5ac99ff6e9db95fd42c94b0b6d617474636f72616c6c6f03636f6d00003000010003d52200440100030dfd9dbc34cb5053a2c4a6b3d0dc60fc65d8a992dc1e080f6deeddba7fe6b25217730de64c9a1ce986b3f81f556881fe0e7b5b20c8ae381c4fefdbc311aa7d22ee0b6d617474636f72616c6c6f03636f6d00002e00010003d522006300300d0200093a80689c35ca6889abb2e2f50b6d617474636f72616c6c6f03636f6d0016857529219dd561091a51c72a27e25d963094f8dcd93b11f0917d45466251acb1402bb6fa4529bd20b7db697df429c4ba830685fc290ee5a8a937c2d34530c00b6d617474636f72616c6c6f03636f6d00002b00010001518000249f000d02594d2813e04a1d2660ff3c0afc5579b9ec0fe72cc206dc6f248bbe6dd652e1950b6d617474636f72616c6c6f03636f6d00002b0001000151800024e2f50d02f0e161567d468087ff27b051abc94476178a7cb635da1aa705e05c77ca81de520b6d617474636f72616c6c6f03636f6d00002e0001000151800057002b0d0200015180689a991368914e2b504103636f6d0070ac13ac37043e66f191553c554ee9307a91a4cf27bd724949e52032a2b464cadb776cd362918159344d9685b84650436449914f25fc62cc6dd6b761f5658283056e696e6a61000030000100000d2b00880100030803010001d28cb7e2bb163d5815838bedeca1006dde8551b379cb963c8a2cb42bc360127e3a5cf88ffc851a67414815b875f65d78c39b58d2fb29a1d4e76d50cb6b4a58a11fe2fb7c1b6db7bf7d72f5a1401e381c57fcc76f599cc73f05095d2bd14d9895e4fa1cff21bd760598a734b640102d11bc159c6b2ae73dbfd2741518142584d1056e696e6a61000030000100000d2b01080101030803010001c71e4c9dc49249a27b3ef42fcb8d56b4c3ac76715c7ad01c41d0d432590d15c3c62cee4b2d29ac35f2d72c9b32a70a0243cbd08aeebc9f6f1e0e63d9e1cdfe133c455a82435c0780b750012c942f7ed5b662eec8d9ae885a58993fa78d7561fedcd11d9e1c171acb02d0025837ba61a3c0a6756427414470c9ca0906b298168b5f4d9640e62e1b75dd06be664104ed32cfe447fa21f37401712c720a0dca4bb1bc20f3fa3103cad336bde20b16f73948e6b80dda0a528db536a958868c3870ecddcfb02dfb3cb4d22e2ad49a4b9f78c90ff6c7e10e301b3fb36fe859a94c30084660665741c14ff60d0535013fcf439840ecad82fc9278e4ace68ba95e708249056e696e6a61000030000100000d2b0088010003080301000197edb59d4f181e2761dd8d0465854339afc71fd89e47155981ddd175cdce79477552aeaf7b5a08fc4ac6025555f60582f2060e630edfb35b9c7cc30990fb9c3dc9f2fd036c962f67b94c9670d4ceaacd77973bca82ab7c9615f7e4320dda5b6d74dec673017c6fa448b5542a804e08ac873c509c1945ff734c320491e4b18e6d056e696e6a6100002e000100000d2b01190030080100000e1068a89268688cd4d8b402056e696e6a6100646e04cf5f76daa775ff98905ded3d2caad68d3198fc161340d558262c7ba7da28e7538a7f32d5a6485e4448037e8edf55759b7059fdc084f1017f790aa7c0d8f0e4af6c9af04e4afd16ce6052c30da59314c9c98075fd32bb77a81f34bea6190631b9d0a4351a764c14152ea217e6271647bf95b0df4c3d7cc00937bec01b65ad1b5209c976a4843e399f173f196a012c0876bc9afa3457d940d6ad7b9d50b3d496836d7342cf3aec75ac4785563e20574ddd2dab1cfb6b5da32508edf7186aa516b0451b221251652ee44353710cbe35928b79fff4293c5e8eff7ab371ce43595e2300305bda0108b911c3ef7d4d15c70d68686fddf28422d5fcbcdb967e84056e696e6a6100002b0001000151800024b4020802c8f816a7a575bdb2f997f682aab2653ba2cb5eddb69b036a30742a33befaf141056e696e6a6100002e0001000151800113002b08010001518068a404d06892d340b5690081d888ee9bd744185f24bfbaaae70172bb03b6c0a899dcd6801c44b2e3e6acd5fe2192f4f06e5690ace176cb08557f2d5ceef5e9d9eb72f4f639dcf34650eebdef5cb91cd546fbdbd8a529d7ef9bb2168160ae800790d7a7266b531174d8d9be06cad2f1d0f062d9431f7de4beceb02f30ddc97bba44535a703e2d3cc01d2341bb48eb7b25d938f0ed2a7d4c53818e7cb883dc14ffce5899504265869fd3133953c96f48b99ff2055acd53b9f69d2eb8a911bb1f05e2fb8d1d0cc391e1b9ae19fc32b00727a9d8551e1a09319ba94da44cc317bb66e8f372385560cdf8455f858d4afd602307d982d996f729a16c263efa9b8cebe7862b7f9a88ac9fbaf445a603636f6d00003000010000026600440100030df17b60fb56d522f8634153e785c0a978532ea76de39d34bb356d3d042e07f29f7b992176cc83acef7b78ea750425203b18f2b8228b3cdd2bc7eb13c3e3035a7e03636f6d00003000010000026600440101030db71f0465101ddbe2bf0c9455d12fa16c1cda44f4bf1ba2553418ad1f3aa9b06973f21b84eb532cf4035ee8d4832ca26d89306a7d32560c0cb0129d450ac1083503636f6d00002e000100000266005700300d0100015180689f3dfb688b764f4d0603636f6d00d87373f3d5d404f7cdc3aace633c96357bc606ced620792597e1308b1d6c5902668c4d3c1a37bab8486ba24485d57a9d98157fe706424b2043bfb40306d0148403636f6d00002b00010001518000244d060d028acbb0cd28f41250a80a491389424d341522d946b0da0c0291f2d3d771d7805a03636f6d00002e0001000151800113002b08010001518068a404d06892d340b5690024fbea2f86eb0e472114b9da41f1da69e4ef2d02ffcd6bdd987239f288795603d5f54308b238ef19f2747d6a1bc0e775782025561b0f14d1dd19be6bf36b495a3e2d538d5532c5c6e1056c06aa4e81de07f637313955a7761d313db0c6cd0b5c17b4ee22d530d6cdc0c4e195df85b354bbe32027537f1ca21f2815b2d0dbd154582124b3c4c27f1c3aea16f6bfe7e6f5c80aaccd61601bdd8f947ef5c30f004482617cf97629b8b89d8e7320719c979c6a9defdf79b743ecef08bdf2f90796da018fdc6be1e0629fe706044e0f8ad1b25927eca09074a502eb9136eefe5903ad3f97866ab014f1ec96e1f38e3aba66520a25ace386f4897e1ecfd774ce0a0f8a00003000010002a30001080101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b500003000010002a30001080101030803010001af7a8deba49d995a792aefc80263e991efdbc86138a931deb2c65d5682eab5d3b03738e3dfdc89d96da64c86c0224d9ce02514d285da3068b19054e5e787b2969058e98e12566c8c808c40c0b769e1db1a24a1bd9b31e303184a31fc7bb56b85bbba8abc02cd5040a444a36d47695969849e16ad856bb58e8fac8855224400319bdab224d83fc0e66aab32ff74bfeaf0f91c454e6850a1295207bbd4cdde8f6ffb08faa9755c2e3284efa01f99393e18786cb132f1e66ebc6517318e1ce8a3b7337ebb54d035ab57d9706ecd9350d4afacd825e43c8668eece89819caf6817af62dc4fbd82f0e33f6647b2b6bda175f14607f59f4635451e6b27df282ef73d8700003000010002a30001080100030803010001b11b182a464c3adc6535aa59613bda7a61cac86945c20b773095941194f4b9f516e8bd924b1e50e3fe83918b51e54529d4e5a1e45303df8462241d5e05979979ae5bf9c6c598c08a496e17f3bd3732d5aebe62667b61db1bbe178f27ac99408165a230d6aee78348e6c67789541f845b2ada96667f8dd16ae44f9e260c4a138b3bb1015965ebe609434a06464bd7d29bac47c3017e83c0f89bca1a9e3bdd0813715f3484292df589bc632e27d37efc02837cb85d770d5bd53a36edc99a8294771aa93cf22406f5506c8cf850ed85c1a475dee5c2d3700b3f5631d903524b849995c20cb407ed411f70b428ae3d642716fe239335aa961a752e67fb6dca0bf72900003000010002a30001080100030803010001b6aec4b48567e2925a2d9c4fa4c96e6dddf86215a9bd8dd579c38ccb1199ed1be89946a7f72fc2633909a2792d0eed1b5afb2ee4c78d865a76d6cd9369d999c96af6be0a2274b8f2e9e0a0065bd20257570f08bc14c16f5616426881a83dbce6926e391c138a2ec317efa7349264de2e791c9b7d4a6048ee6eedf27bf1ece398ff0d229f18377cb1f6b98d1228ef217b8146c0c73851b89a6fc37c621ca187e16428a743ffea0072e185ef93e39525cee3ad01e0c94d2e511c8c313322c29ab91631e1856049a36898684c3056e5997473816fb547acb0be6e660bdfa89a5cb28b3669d8625f3f018c7b3b8a4860e774ee8261811ce7f96c461bc162c1a374f300002e00010002a3000113003008000002a30068a66180688ab2004f66007d114bf33e6d20e7588fdfde9a9e2a8ebd5593ce8bc06419e1d1a4afa8766abc1626504ea6243ca5fc9bce55a3f03c0e7eb488409690d84c3beb30f299da007ab69299d0e203c5b44b94328248768089a9b68982650e9ca2d37526307cbd9f06690e58c3c4a1703b1d1193ea0501417944b937b593294e339571eec42a3c700ce075d9c446e5d32bf979396c1c7935f69bd7df2826567fe582a3615d6095368be991b1e5dc39c0af3b0c39e0e353bbcb928e52e886193ac88da0cd8665ea992b642975aa5486f2e6514d0b5086c66ddd58fe8f7a27ecb128211e3ca1bdc4cad91f3cc9b63c526ebaea86075318e33bfc5a53c919e6f01262b24d178eb2cd04b1
Further valid test cases can be generated by using https://satsto.me and selecting the "Look up using satsto.me's native proof server" option. This will cause lookups to be a single request to a server that returns a full DNSSEC proof (without the HRN prefix), which can be exracted using your browser's console.
Generated proofs can be tested against the below dnssec-prover implementation at https://satsto.me/prooftest.html
== Reference Implementations ==
* A DNSSEC proof generation and validation implementation can be found at https://git.bitcoin.ninja/index.cgi?p=dnssec-prover;a=summary
* A lightning-specific name to payment instruction resolver can be found at https://git.bitcoin.ninja/index.cgi?p=lightning-resolver;a=summary
* Reference implementations for parsing the URI contents can be found in [[bip-0321.mediawiki|BIP 321]].
== Footnotes ==
== Acknowledgements ==
Thanks to Rusty Russell for the concrete address rotation suggestion.
Thanks to the Bitcoin Design Community, and especially Christoph Ono for lots of discussion, analysis, and UX mockups in how human-readable payment instructions should be displayed.
Thanks to Andrew Kaizer for the suggestion to explicitly restrict cache lifetime to the relevant DNS TTLs.
================================================
FILE: bip-0360/ref-impl/.gitignore
================================================
rust-bitcoin
rust-miniscript
libbitcoinpqc
target
.btcdeb_history
*.swp
================================================
FILE: bip-0360/ref-impl/common/tests/data/p2mr_construction.json
================================================
{
"version": 1,
"test_vectors": [
{
"id": "p2tr_using_v2_witness_version_error",
"objective": "Tests that a P2TR v2 scriptPubKey fails with use of witness version 2",
"given": {
"internalPubkey": "d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d",
"scriptTree": null
},
"intermediary": {
"merkleRoot": null,
"tweak": "b86e7be8f39bab32a6f2c0443abbc210f0edac0e2c53d501b36b64437d9c6c70",
"tweakedPubkey": "53a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343"
},
"expected": {
"scriptPubKey": "522053a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
"error": "P2TR requires witness version of 1"
}
},
{
"id": "p2mr_missing_leaf_script_tree_error",
"objective": "Tests P2MR with missing leaf script tree",
"given": {
"script_tree": ""
},
"intermediary": {
},
"expected": {
"error": "P2MR requires a script tree with at least one leaf"
}
},
{
"id": "p2mr_single_leaf_script_tree",
"objective": "Tests P2MR with single leaf script tree",
"given": {
"scriptTree": {
"id": 0,
"script": "20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac",
"asm": "b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007 OP_CHECKSIG",
"leafVersion": 192
}
},
"intermediary": {
"leafHashes": [
"c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
],
"merkleRoot": "c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b"
},
"expected": {
"scriptPubKey": "5220c525714a7f49c28aedbbba78c005931a81c234b2f6c99a73e4d06082adc8bf2b",
"bip350Address": "bc1zc5jhzjnlf8pg4mdmhfuvqpvnr2quyd9j7mye5uly6psg9twghu4ssr0v9k",
"scriptPathControlBlocks": [
"c1"
]
}
},
{
"id": "p2mr_different_version_leaves",
"objective": "Tests P2MR with two script leaves of different versions. TO-DO: currently ignores given leaf version and over-rides. Probably better to throw error",
"given": {
"scriptTree": [
{
"id": 0,
"script": "20387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48ac",
"asm": "387671353e273264c495656e27e39ba899ea8fee3bb69fb2a680e22093447d48 OP_CHECKSIG",
"leafVersion": 192
},
{
"id": 1,
"script": "06424950333431",
"asm": "424950333431",
"description": "just pushes the string 'BIP341' onto the stack",
"leafVersion": 250
}
]
},
"intermediary": {
"leafHashes": [
"8ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7",
"f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
],
"merkleRoot": "6c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef"
},
"expected": {
"scriptPubKey": "52206c2dc106ab816b73f9d07e3cd1ef2c8c1256f519748e0813e4edd2405d277bef",
"bip350Address": "bc1zdskuzp4ts94h87ws0c7drmev3sf9dagewj8qsylyahfyqhf800hsam4d6e",
"scriptPathControlBlocks": [
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a",
"c18ad69ec7cf41c2a4001fd1f738bf1e505ce2277acdcaa63fe4765192497f47a7"
]
}
},
{
"id": "p2mr_simple_lightning_contract",
"objective": "Tests P2MR with two script leaves that simulate a simple lightning network contract. Reference: https://github.com/bitcoin-core/btcdeb/blob/master/doc/tapscript-example-with-tap.md",
"given": {
"scriptTree": [
{
"id": 0,
"script": "029000b275209997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803beac",
"asm": "144 OP_CHECKSEQUENCEVERIFY OP_DROP 9997a497d964fc1a62885b05a51166a65a90df00492c8d7cf61d6accf54803be OP_CHECKSIG",
"description": "Alice takes the money after waiting 1 day",
"leafVersion": 192
},
{
"id": 1,
"script": "a8206c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd533388204edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10ac",
"asm": "OP_SHA256 6c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd5333 OP_EQUALVERIFY 4edfcf9dfe6c0b5c83d1ab3f78d1b39a46ebac6798e08e19761f5ed89ec83c10 OP_CHECKSIG",
"description": "Bob takes the money whenever he wishes to by revealing the preimage_hash",
"leafVersion": 192
}
]
},
"intermediary": {
"leafHashes": [
"c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
"632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
],
"merkleRoot": "41646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b"
},
"expected": {
"scriptPubKey": "522041646f8c1fe2a96ddad7f5471bc4fee7da98794ef8c45a4f4fc6a559d60c9f6b",
"bip350Address": "bc1zg9jxlrqlu25kmkkh74r3h387uldfs72wlrz95n60c6j4n4svna4s4lhfhe",
"scriptPathControlBlocks": [
"c1c81451874bd9ebd4b6fd4bba1f84cdfb533c532365d22a0a702205ff658b17c9",
"c1632c8632b4f29c6291416e23135cf78ecb82e525788ea5ed6483e3c6ce943b42"
]
}
},
{
"id": "p2mr_two_leaf_same_version",
"objective": "Tests P2MR with two script leaves of same version",
"given": {
"scriptTree": [
{
"id": 0,
"script": "2044b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fdac",
"asm": "44b178d64c32c4a05cc4f4d1407268f764c940d20ce97abfd44db5c3592b72fd OP_CHECKSIG",
"leafVersion": 192
},
{
"id": 1,
"script": "07546170726f6f74",
"asm": "546170726f6f74",
"description": "pushes the string 'Taproot' onto the stack",
"leafVersion": 192
}
]
},
"intermediary": {
"leafHashes": [
"64512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89",
"2cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
],
"merkleRoot": "ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc"
},
"expected": {
"scriptPubKey": "5220ab179431c28d3b68fb798957faf5497d69c883c6fb1e1cd9f81483d87bac90cc",
"bip350Address": "bc1z4vtegvwz35ak37me39tl4a2f045u3q7xlv0pek0czjpas7avjrxqz20g2y",
"scriptPathControlBlocks": [
"c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb",
"c164512fecdb5afa04f98839b50e6f0cb7b1e539bf6f205f67934083cdcc3c8d89"
]
}
},
{
"id": "p2mr_three_leaf_complex",
"objective": "Tests P2MR with a complex three-leaf script tree structure, demonstrating nested script paths and multiple verification options",
"given": {
"internalPubkey": "e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f",
"scriptTree": [
{
"id": 0,
"script": "2072ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69ac",
"asm": "72ea6adcf1d371dea8fba1035a09f3d24ed5a059799bae114084130ee5898e69 OP_CHECKSIG",
"leafVersion": 192
},
[
{
"id": 1,
"script": "202352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8ac",
"asm": "2352d137f2f3ab38d1eaa976758873377fa5ebb817372c71e2c542313d4abda8 OP_CHECKSIG",
"leafVersion": 192
},
{
"id": 2,
"script": "207337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186aac",
"asm": "7337c0dd4253cb86f2c43a2351aadd82cccb12a172cd120452b9bb8324f2186a OP_CHECKSIG",
"leafVersion": 192
}
]
]
},
"intermediary": {
"leafHashes": [
"2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c",
"9e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf6"
],
"merkleRoot": "ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2"
},
"expected": {
"scriptPubKey": "5220ccbd66c6f7e8fdab47b3a486f59d28262be857f30d4773f2d5ea47f7761ce0e2",
"bip350Address": "bc1zej7kd3hhar76k3an5jr0t8fgyc47s4lnp4rh8uk4afrlwasuur3qzgewqq",
"scriptPathControlBlocks": [
"c1ffe578e9ea769027e4f5a3de40732f75a88a6353a09d767ddeb66accef85e553",
"c1ba982a91d4fc552163cb1c0da03676102d5b7a014304c01f0c77b2b8e888de1c2645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817",
"c19e31407bffa15fefbf5090b149d53959ecdf3f62b1246780238c24501d5ceaf62645a02e0aac1fe69d69755733a9b7621b694bb5b5cde2bbfc94066ed62b9817"
]
}
},
{
"id": "p2mr_three_leaf_alternative",
"objective": "Tests another variant of P2MR with three leaves arranged in a different tree structure, showing alternative script path spending options",
"given": {
"internalPubkey": "55adf4e8967fbd2e29f20ac896e60c3b0f1d5b0efa9d34941b5958c7b0a0312d",
"scriptTree": [
{
"id": 0,
"script": "2071981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2ac",
"asm": "71981521ad9fc9036687364118fb6ccd2035b96a423c59c5430e98310a11abe2 OP_CHECKSIG",
"leafVersion": 192
},
[
{
"id": 1,
"script": "20d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748ac",
"asm": "d5094d2dbe9b76e2c245a2b89b6006888952e2faa6a149ae318d69e520617748 OP_CHECKSIG",
"leafVersion": 192
},
{
"id": 2,
"script": "20c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4cac",
"asm": "c440b462ad48c7a77f94cd4532d8f2119dcebbd7c9764557e62726419b08ad4c OP_CHECKSIG",
"leafVersion": 192
}
]
]
},
"intermediary": {
"leafHashes": [
"f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711",
"d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7"
],
"merkleRoot": "2f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def"
},
"expected": {
"scriptPubKey": "52202f6b2c5397b6d68ca18e09a3f05161668ffe93a988582d55c6f07bd5b3329def",
"bip350Address": "bc1z9a4jc5uhkmtgegvwpx3lq5tpv68layaf3pvz64wx7paatvejnhhsv52lcv",
"scriptPathControlBlocks": [
"c13cd369a528b326bc9d2133cbd2ac21451acb31681a410434672c8e34fe757e91",
"c1737ed1fe30bc42b8022d717b44f0d93516617af64a64753b7a06bf16b26cd711f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d",
"c1d7485025fceb78b9ed667db36ed8b8dc7b1f0b307ac167fa516fe4352b9f4ef7f154e8e8e17c31d3462d7132589ed29353c6fafdb884c5a6e04ea938834f0d9d"
]
}
}
]
}
================================================
FILE: bip-0360/ref-impl/common/tests/data/p2mr_pqc_construction.json
================================================
{
"version": 1,
"test_vectors": [
{
"id": "p2mr_missing_leaf_script_tree_error",
"objective": "Tests P2MR with missing leaf script tree",
"given": {
"script_tree": ""
},
"intermediary": {
},
"expected": {
"error": "P2MR requires a script tree with at least one leaf"
}
},
{
"id": "p2mr_single_leaf_script_tree",
"objective": "Tests P2MR with single leaf script tree",
"given": {
"scriptTree": {
"id": 0,
"script": "201f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f247f",
"asm": "1f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f24 OP_SUBSTR",
"priv_key": "3f0213a51771f25c906cd82c656175e4b2a10e85958039d6e358352a2eb62b791f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f24",
"leafVersion": 192
}
},
"intermediary": {
"leafHashes": [
"3bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc"
],
"merkleRoot": "3bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc"
},
"expected": {
"scriptPubKey": "52203bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc",
"bip350Address": "bc1z8wcdhrr2mnv8xv9y4ry3hc87rv3a50q4rdhjld8jd9pfcsacmz7qg5szm8",
"scriptPathControlBlocks": [
"c1"
]
}
},
{
"id": "p2mr_different_version_leaves",
"objective": "Tests P2MR with two script leaves of different versions. TO-DO: currently ignores given leaf version and over-rides. Probably better to throw error",
"given": {
"scriptTree": [
{
"id": 0,
"script": "201f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f247f",
"asm": "1f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f24 OP_SUBSTR",
"priv_key": "3f0213a51771f25c906cd82c656175e4b2a10e85958039d6e358352a2eb62b791f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f24",
"leafVersion": 192
},
{
"id": 1,
"script": "06424950333431",
"asm": "424950333431",
"description": "just pushes the string 'BIP341' onto the stack",
"leafVersion": 250
}
]
},
"intermediary": {
"leafHashes": [
"3bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc",
"f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
],
"merkleRoot": "1619ce6d22a46dea045c4adf7f5f33d6810d00d0e9c8a4c7ba35db37b915c604"
},
"expected": {
"scriptPubKey": "52201619ce6d22a46dea045c4adf7f5f33d6810d00d0e9c8a4c7ba35db37b915c604",
"bip350Address": "bc1zzcvuumfz53k75pzuft0h7hen66qs6qxsa8y2f3a6xhdn0wg4cczq0h84sj",
"scriptPathControlBlocks": [
"c13bb0db8c6adcd87330a4a8c91be0fe1b23da3c151b6f2fb4f269429c43b8d8bc",
"c1f224a923cd0021ab202ab139cc56802ddb92dcfc172b9212261a539df79a112a"
]
}
},
{
"id": "p2mr_simple_lightning_contract",
"objective": "Tests P2MR with two script leaves that simulate a simple lightning network contract. Reference: https://github.com/bitcoin-core/btcdeb/blob/master/doc/tapscript-example-with-tap.md",
"given": {
"scriptTree": [
{
"id": 0,
"script": "029000b275201f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f247f",
"asm": "144 OP_CHECKSEQUENCEVERIFY OP_DROP 1f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f24 OP_SUBSTR",
"priv_key": "3f0213a51771f25c906cd82c656175e4b2a10e85958039d6e358352a2eb62b791f4b1febdc7dfa77c1efacc875b43317b46155e5a564decf475fc369124c5f24",
"description": "Alice takes the money after waiting 1 day",
"leafVersion": 192
},
{
"id": 1,
"script": "a8206c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd533388204c7f98ab73cc36abeb76d6eace6a9d8b0ff69dfe0f4a17e4f94f0898ec52fadd",
"asm": "OP_SHA256 6c60f404f8167a38fc70eaf8aa17ac351023bef86bcb9d1086a19afe95bd5333 OP_EQUALVERIFY 4c7f98ab73cc36abeb76d6eace6a9d8b0ff69dfe0f4a17e4f94f0898ec52fadd OP_SUBSTR",
"priv_key": "49a4214f386240d97ea68efb4268043fd5a55208dcdac18ce5bd3332b8e488944c7f98ab73cc36abeb76d6eace6a9d8b0ff69dfe0f4a17e4f94f0898ec52fadd",
"description": "Bob takes the money whenever he wishes to by revealing the preimage_hash",
"leafVersion": 192
}
]
},
"intermediary": {
"leafHashes": [
"cfd5fc07ac39947cba799e14f933f20e7c233dea72dc2792f5547c58cdce743e",
"a9745ac96d4f3702b78751f1e08f3040fbe6347e7b4f520d22d3f907730cbb7e"
],
"merkleRoot": "2794771cd51f215ba3a19fbcdf08c771edb7de782a0c34457e0e9be5d0e4008f"
},
"expected": {
"scriptPubKey": "52202794771cd51f215ba3a19fbcdf08c771edb7de782a0c34457e0e9be5d0e4008f",
"bip350Address": "bc1zy728w8x4rus4hgapn77d7zx8w8km0hnc9gxrg3t7p6d7t58yqz8sg0nccq",
"scriptPathControlBlocks": [
"c1cfd5fc07ac39947cba799e14f933f20e7c233dea72dc2792f5547c58cdce743e",
"c1a9745ac96d4f3702b78751f1e08f3040fbe6347e7b4f520d22d3f907730cbb7e"
]
}
},
{
"id": "p2mr_two_leaf_same_version",
"objective": "Tests P2MR with two script leaves of same version",
"given": {
"scriptTree": [
{
"id": 0,
"script": "20e6b3dad32fc04095a021f5356163cfc14e15f703831e332c56f6b499801f53447f",
"asm": "e6b3dad32fc04095a021f5356163cfc14e15f703831e332c56f6b499801f5344 OP_SUBSTR",
"priv_key": "a695d8a1351774d59ed1b980462c2ab8d58b3b7a48f55b114c6a39980dc1c13ee6b3dad32fc04095a021f5356163cfc14e15f703831e332c56f6b499801f5344",
"leafVersion": 192
},
{
"id": 1,
"script": "07546170726f6f74",
"asm": "546170726f6f74",
"description": "pushes the string 'Taproot' onto the stack",
"leafVersion": 192
}
]
},
"intermediary": {
"leafHashes": [
"9de7eeded7832c28c6f80de76904dd79f98fd302747823b5bc5be440186b0c6d",
"2cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
],
"merkleRoot": "5112b3edfd2c0b717491e9d4888ed2d5dfeaa25115143540e0a08516b68c008c"
},
"expected": {
"scriptPubKey": "52205112b3edfd2c0b717491e9d4888ed2d5dfeaa25115143540e0a08516b68c008c",
"bip350Address": "bc1z2yft8m0a9s9hzay3a82g3rkj6h074gj3z52r2s8q5zz3dd5vqzxqngpk2w",
"scriptPathControlBlocks": [
"c19de7eeded7832c28c6f80de76904dd79f98fd302747823b5bc5be440186b0c6d",
"c12cb2b90daa543b544161530c925f285b06196940d6085ca9474d41dc3822c5cb"
]
}
},
{
"id": "p2mr_three_leaf_complex",
"objective": "Tests P2MR with a complex three-leaf script tree structure, demonstrating nested script paths and multiple verification options",
"given": {
"scriptTree": [
{
"id": 0,
"script": "201d58016252d5a941f84574c4821b5f87e56778b2bbc3b610dfd801fc0250f6cc7f",
"asm": "1d58016252d5a941f84574c4821b5f87e56778b2bbc3b610dfd801fc0250f6cc OP_SUBSTR",
"priv_key": "2b339b5055fad695f0595d5581fa087455854f64c5443c03d5b4ca53549f12a41d58016252d5a941f84574c4821b5f87e56778b2bbc3b610dfd801fc0250f6cc",
"leafVersion": 192
},
[
{
"id": 1,
"script": "20a3b0dcac08f86306ba04f5fe2a3243ef3a0347c0e2a4529720a18d3cfdce90ad7f",
"asm": "a3b0dcac08f86306ba04f5fe2a3243ef3a0347c0e2a4529720a18d3cfdce90ad OP_SUBSTR",
"priv_key": "ec29d60c1be9263602906499b5e3c1de9e36cc88cec31154210191a578b92e9da3b0dcac08f86306ba04f5fe2a3243ef3a0347c0e2a4529720a18d3cfdce90ad",
"leafVersion": 192
},
{
"id": 2,
"script": "20e6ccf03593dbd07eba10403e33586c130889de6e8219da0a9ccbdd46a56a5f367f",
"asm": "e6ccf03593dbd07eba10403e33586c130889de6e8219da0a9ccbdd46a56a5f36 OP_SUBSTR",
"priv_key": "da04d13f706a6e0d22ac0db7c361f1aaa706a27043efca4edfecfed3125238e1e6ccf03593dbd07eba10403e33586c130889de6e8219da0a9ccbdd46a56a5f36",
"leafVersion": 192
}
]
]
},
"intermediary": {
"leafHashes": [
"0840c39e59eda6c9deee687a480cb169130c2f053ed2eb3134511ec1cfd8a2c7",
"837ef6677aeb0df2b0de47f45024684cc6ca03bda10fa30bb5bc05a94beb8dd1",
"b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a"
],
"merkleRoot": "eaf8f557fdb9673de7bb9bad7e7452da9f44a3e65133fdadf2849c55cfb3cf5b"
},
"expected": {
"scriptPubKey": "5220eaf8f557fdb9673de7bb9bad7e7452da9f44a3e65133fdadf2849c55cfb3cf5b",
"bip350Address": "bc1zatu024lah9nnmeamnwkhuazjm205fglx2yelmt0jsjw9tnaneadszq7wg7",
"scriptPathControlBlocks": [
"c1837ef6677aeb0df2b0de47f45024684cc6ca03bda10fa30bb5bc05a94beb8dd1b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a",
"c10840c39e59eda6c9deee687a480cb169130c2f053ed2eb3134511ec1cfd8a2c7b2a5304f678cc5a2ed51feb377dd0a609bd22ec979cc608bfcf884d0f8e6f93a",
"c118781f42f664d67acaf0ce7c6826437e5440eb1789f232af05e9a09fdf547903"
]
}
},
{
"id": "p2mr_three_leaf_alternative",
"objective": "Tests another variant of P2MR with three leaves arranged in a different tree structure, showing alternative script path spending options",
"given": {
"scriptTree": [
{
"id": 0,
"script": "20409f78ce0978519ff5d960c4ab595174c7efca11b1f89410a4e98b70cd423e1c7f",
"asm": "409f78ce0978519ff5d960c4ab595174c7efca11b1f89410a4e98b70cd423e1c OP_SUBSTR",
"priv_key": "c6ec3801b04afa40be6f77f3f7a7b3b7cb8cfe233b0263fb70e2f087b21397c1409f78ce0978519ff5d960c4ab595174c7efca11b1f89410a4e98b70cd423e1c",
"leafVersion": 192
},
[
{
"id": 1,
"script": "209f0955dc884a5c88d1732e017d30e27e8a445889bce5aa42611b7635c5c1073a7f",
"asm": "9f0955dc884a5c88d1732e017d30e27e8a445889bce5aa42611b7635c5c1073a OP_SUBSTR",
"priv_key": "7524bca170d54231f1246f30fb00f9da2208b1363ba5a7bbaf11fc3b0309e9519f0955dc884a5c88d1732e017d30e27e8a445889bce5aa42611b7635c5c1073a",
"leafVersion": 192
},
{
"id": 2,
"script": "20c60b10d57c0cdf27e5c751e131ea4301b37abe7384948059256c7f5f1f285a7f7f",
"asm": "c60b10d57c0cdf27e5c751e131ea4301b37abe7384948059256c7f5f1f285a7f OP_SUBSTR",
"priv_key": "d9d0f17d630b6a538e6a8a036373e7b9e5023a4c08f72dd8c3ef59288b98c079c60b10d57c0cdf27e5c751e131ea4301b37abe7384948059256c7f5f1f285a7f",
"leafVersion": 192
}
]
]
},
"intermediary": {
"leafHashes": [
"52e9326c2bf04d926b7e9f6c7645dd853f3f007b870201de9b814952750c9310",
"dcef3ce86cc8cea78c9e00f3d9ef58360cb6ed3cb90ec62efe00b9703854ba5c",
"ddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361"
],
"merkleRoot": "51e3c1151ba73d9efce801837773331bf9030977242f62dfeb6756795f482409"
},
"expected": {
"scriptPubKey": "522051e3c1151ba73d9efce801837773331bf9030977242f62dfeb6756795f482409",
"bip350Address": "bc1z283uz9gm5u7eal8gqxphwuenr0usxzthyshk9hltvat8jh6gysys28twnc",
"scriptPathControlBlocks": [
"c1dcef3ce86cc8cea78c9e00f3d9ef58360cb6ed3cb90ec62efe00b9703854ba5cddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361",
"c152e9326c2bf04d926b7e9f6c7645dd853f3f007b870201de9b814952750c9310ddb521a44e33ff4974e618d8b8b7794275b7dc754d847c537404f84330454361",
"c1b45680a7821e4b9450096ab38adbc3c99225af8f6c7ec121a0a5f1ae02893ba3"
]
}
}
]
}
================================================
FILE: bip-0360/ref-impl/common/utils/signet_miner_loop.sh
================================================
#!/bin/bash
# Invokes mining simulator a configurable number of times
if [ -z "${P2MR_ADDR}" ]; then
echo "Error: Environment variable P2MR_ADDR needs to be set"
exit 1
fi
BITCOIN_SOURCE_DIR=${BITCOIN_SOURCE_DIR:-$HOME/bitcoin}
# path to bitcoin.conf for signet
BITCOIN_CONF_FILE_PATH=${BITCOIN_CONF_FILE_PATH:-$HOME/anduro-360/configs/bitcoin.conf.signet}
# Set default LOOP_COUNT to 110 if not set
LOOP_COUNT=${LOOP_COUNT:-110}
# Validate LOOP_COUNT is a positive integer
if ! [[ "$LOOP_COUNT" =~ ^[0-9]+$ ]] || [ "$LOOP_COUNT" -le 0 ]; then
echo "Error: LOOP_COUNT must be a positive integer"
exit 1
fi
# Determine name of pool by querying mempool.space backend
# curl -X GET "http://localhost:8999/api/v1/mining/pool/marapool" | jq -r .pool.regexes
export POOL_ID=${POOL_ID:-"MARA Pool"}
echo -en "\nLoop_COUNT = $LOOP_COUNT\nBITCOIN_CONF_FILE_PATH=$BITCOIN_CONF_FILE_PATH\nBITCOIN_SOURCE_DIR=$BITCOIN_SOURCE_DIR\nPOOL_ID=$POOL_ID\n\n";
for ((i=1; i<=LOOP_COUNT; i++))
do
echo "Iteration $i of $LOOP_COUNT"
$BITCOIN_SOURCE_DIR/contrib/signet/miner --cli "bitcoin-cli -conf=$BITCOIN_CONF_FILE_PATH" generate \
--address $P2MR_ADDR \
--grind-cmd "$BITCOIN_SOURCE_DIR/build/bin/bitcoin-util grind" \
--poolid "$POOL_ID" \
--min-nbits --set-block-time $(date +%s)
done
================================================
FILE: bip-0360/ref-impl/common/utils/workshop/Dockerfile.bcli
================================================
# podman build -f Dockerfile.bcli -t quay.io/jbride2000/p2mr_bcli:0.1 .
# podman run -it --entrypoint /bin/bash quay.io/jbride200/p2mr_bcli:0.1
FROM rust:1-slim-bookworm AS builder
# Install build dependencies
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
autoconf \
automake \
libtool \
pkg-config \
zlib1g-dev \
libevent-dev \
libboost-dev \
libzmq3-dev \
bash \
python3 \
python3-pip \
libclang-dev \
clang \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /bitcoin
# Copy Bitcoin Core source (or clone)
# COPY . /bitcoin
RUN git clone --branch p2mr-pqc --single-branch https://github.com/jbride/bitcoin.git
# Environment variables for musl
ENV CC=gcc
ENV CXX=g++
# Build Bitcoin Core
WORKDIR bitcoin
RUN apt-get update && apt-get install -y libsqlite3-dev && rm -rf /var/lib/apt/lists/*
RUN mkdir build && cd build && \
cmake .. \
-DWITH_ZMQ=ON \
-DBUILD_BENCH=ON \
-DBUILD_DAEMON=ON && \
make -j$(nproc) bitcoin-cli
# Runtime stage with Debian Slim
FROM debian:bookworm-slim
# Install minimal runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
libevent-core-2.1-7 \
libevent-pthreads-2.1-7 \
libevent-extra-2.1-7 \
libboost-filesystem1.74.0 \
libboost-thread1.74.0 \
libzmq5 \
libsqlite3-0 \
telnet \
&& rm -rf /var/lib/apt/lists/*
# Copy bitcoin-cli from builder
COPY --from=builder /bitcoin/bitcoin/build/bin/bitcoin-cli /usr/local/bin/bitcoin-cli
# Create non-root user and set permissions
RUN groupadd --system bip360 && \
useradd --system --gid bip360 --shell /bin/bash --create-home bip360 && \
chmod +x /usr/local/bin/bitcoin-cli && \
ln -s /usr/local/bin/bitcoin-cli /usr/local/bin/b-cli && \
echo 'b-cli() { /usr/local/bin/bitcoin-cli -rpcconnect=${RPC_CONNECT:-192.168.122.1} -rpcport=${RPC_PORT:-18443} -rpcuser=${RPC_USER:-signet} -rpcpassword=${RPC_PASSWORD:-signet} "$@"; }' >> /home/bip360/.bashrc
# Set default environment variables (can be overridden at runtime)
ENV RPC_CONNECT=192.168.122.1 \
RPC_PORT=38332 \
RPC_USER=signet \
RPC_PASSWORD=signet
# Switch to non-root user
USER bip360
WORKDIR /home/bip360
ENTRYPOINT ["/usr/local/bin/bitcoin-cli"]
================================================
FILE: bip-0360/ref-impl/common/utils/workshop/Dockerfile.full
================================================
# podman build -f Dockerfile.full -t quay.io/jbride2000/p2mr_demo:0.1 .
# podman run -it --entrypoint /bin/bash quay.io/jbride2000/p2mr_demo:0.1
FROM rust:1-slim-bookworm AS builder
# Install build dependencies
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
autoconf \
automake \
libtool \
pkg-config \
zlib1g-dev \
libevent-dev \
libboost-dev \
libzmq3-dev \
bash \
python3 \
python3-pip \
libclang-dev \
clang \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /bitcoin
# Copy Bitcoin Core source (or clone)
# COPY . /bitcoin
RUN git clone --branch p2mr-pqc --single-branch https://github.com/jbride/bitcoin.git
# Environment variables for musl
ENV CC=gcc
ENV CXX=g++
# Build Bitcoin Core
WORKDIR bitcoin
RUN apt-get update && apt-get install -y libsqlite3-dev && rm -rf /var/lib/apt/lists/*
RUN mkdir build && cd build && \
cmake .. \
-DWITH_ZMQ=ON \
-DBUILD_BENCH=ON \
-DBUILD_DAEMON=ON && \
make -j$(nproc) bitcoin-cli
# Runtime stage with Debian Slim
FROM rust:1-slim-bookworm
# Install minimal runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
libevent-core-2.1-7 \
libevent-pthreads-2.1-7 \
libevent-extra-2.1-7 \
libboost-filesystem1.74.0 \
libboost-thread1.74.0 \
libzmq5 \
libsqlite3-0 \
&& rm -rf /var/lib/apt/lists/*
# Copy bitcoin-cli from builder
COPY --from=builder /bitcoin/bitcoin/build/bin/bitcoin-cli /usr/local/bin/bitcoin-cli
# Create non-root user and set permissions
RUN groupadd --system bip360 && \
useradd --system --gid bip360 --shell /bin/bash --create-home bip360 && \
chmod +x /usr/local/bin/bitcoin-cli && \
ln -s /usr/local/bin/bitcoin-cli /usr/local/bin/b-cli && \
echo 'b-cli() { /usr/local/bin/bitcoin-cli -rpcconnect=${RPC_CONNECT:-192.168.122.1} -rpcport=${RPC_PORT:-18443} -rpcuser=${RPC_USER:-signet} -rpcpassword=${RPC_PASSWORD:-signet} "$@"; }' >> /home/bip360/.bashrc
# Install additional tools needed for building Rust code (before switching to non-root user)
RUN apt-get update && apt-get install -y --no-install-recommends \
libclang-dev \
clang \
git \
curl \
cmake \
build-essential \
jq \
gawk \
telnet \
&& rm -rf /var/lib/apt/lists/*
# Set default environment variables (can be overridden at runtime)
ENV RPC_CONNECT=192.168.122.1 \
RPC_PORT=38332 \
RPC_USER=signet \
RPC_PASSWORD=signet
# Switch to non-root user
USER bip360
WORKDIR /home/bip360
RUN git clone --no-checkout --depth 1 --branch p2mr-pqc \
--single-branch https://github.com/jbride/bips.git bips && \
cd bips && \
git sparse-checkout init --cone && \
git sparse-checkout set bip-0360 && \
git checkout && \
cd bip-0360/ref-impl/rust && \
cargo build && \
rm -rf target
WORKDIR /home/bip360/bips/bip-0360/ref-impl/rust
ENV BITCOIN_NETWORK=signet \
USE_PQC=true
ENTRYPOINT ["/usr/local/bin/bitcoin-cli"]
================================================
FILE: bip-0360/ref-impl/common/utils/workshop/bip360-workshop.drawio
================================================
================================================
FILE: bip-0360/ref-impl/js/.gitignore
================================================
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Build outputs
dist/
build/
*.tsbuildinfo
# TypeScript
*.js.map
*.d.ts.map
# Environment variables
.env
.env.local
.env.*.local
# IDE / Editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# OS files
Thumbs.db
desktop.ini
# Testing
coverage/
.nyc_output/
*.lcov
# Logs
logs/
*.log
# Temporary files
*.tmp
*.temp
.cache/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# parcel-bundler cache
.parcel-cache
# Next.js (if ever used)
.next
out
# Vercel (if ever used)
.vercel
# Turbo (if ever used)
.turbo
================================================
FILE: bip-0360/ref-impl/js/README.adoc
================================================
= BIP 360 Javascript Reference Implementation
:numbered:
== procedure
-----
$ npm install
# compile Typecript
$ npx tsc
# run tests
$ node src/p2mr-example.ts
$ node src/test-npm-pqc-package.js
-----
================================================
FILE: bip-0360/ref-impl/js/package.json
================================================
{
"name": "js",
"version": "1.0.0",
"type": "module",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^24.10.0",
"typescript": "^5.9.3"
},
"dependencies": {
"@jbride/bitcoinjs-lib": "^7.0.0-rc.0-p2mr-0.0",
"@jbride/bitcoinpqc-wasm": "^0.1.1",
"ecpair": "^3.0.0",
"tiny-secp256k1": "^2.2.4"
}
}
================================================
FILE: bip-0360/ref-impl/js/src/p2mr-example.ts
================================================
// src/p2mr-example.ts
// Example demonstrating P2MR (Pay-to-Taproot-Script-Hash) address construction
import { payments } from '@jbride/bitcoinjs-lib';
import * as bitcoinCrypto from '@jbride/bitcoinjs-lib/src/crypto';
import * as bscript from '@jbride/bitcoinjs-lib/src/script';
import type { Taptree } from '@jbride/bitcoinjs-lib/src/types';
import ECPairFactory, { type ECPairInterface } from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import { randomBytes } from 'crypto';
const { p2mr } = payments;
// Initialize ECPair with the ECC library
const ECPair = ECPairFactory(ecc);
// Create a secure RNG function
const rng = (size: number) => randomBytes(size);
function signAndVerify(
keyPair: ECPairInterface,
xOnlyPubkey: Uint8Array,
message: Buffer,
) {
const hash = Buffer.from(bitcoinCrypto.hash256(message));
const schnorrSignature = Buffer.from(keyPair.signSchnorr(hash));
const signatureWithSighashDefault = Buffer.concat([schnorrSignature, Buffer.from([0x00])]);
const verified = keyPair.verifySchnorr(hash, schnorrSignature);
return {
message,
hash,
signature: schnorrSignature,
signatureWithSighashDefault,
verified,
};
}
/**
* Example 1: Construct a P2MR address from a script tree with a single leaf
* This is the simplest case - a script tree containing one script.
*/
function example1_simpleScriptTree() {
console.log('=== Example 1: P2MR from simple script tree ===');
// Generate a key pair
const keyPair = ECPair.makeRandom({ rng });
const pubkey = keyPair.publicKey;
const xOnlyPubkey = ecc.xOnlyPointFromPoint(pubkey);
// Compile the script: x-only pubkey OP_CHECKSIG (BIP342 Schnorr signature)
const script = bscript.compile([Buffer.from(xOnlyPubkey), bscript.OPS.OP_CHECKSIG]);
// Create a script tree with one leaf
const scriptTree = {
output: script,
};
// Construct the P2MR payment
const payment = p2mr({
scriptTree: scriptTree,
});
console.log('Generated compressed pubkey:', pubkey.toString('hex'));
console.log('X-only pubkey:', Buffer.from(xOnlyPubkey).toString('hex'));
console.log('Script tree:', { output: bscript.toASM(script) });
console.log('P2MR Address:', payment.address);
console.log('Output script:', bscript.toASM(payment.output!));
console.log('Merkle root hash:', payment.hash ? Buffer.from(payment.hash).toString('hex') : undefined);
const message = Buffer.from('P2MR demo - example 1', 'utf8');
const result = signAndVerify(keyPair, xOnlyPubkey, message);
console.log('Message:', result.message.toString('utf8'));
console.log('Hash256(message):', result.hash.toString('hex'));
console.log('Schnorr signature (64-byte):', result.signature.toString('hex'));
console.log('Signature + default sighash (65-byte witness element):', result.signatureWithSighashDefault.toString('hex'));
console.log('Signature valid:', result.verified);
console.log('Witness stack for spend:', [result.signatureWithSighashDefault.toString('hex'), bscript.toASM(script)]);
console.log();
}
/**
* Example 2: Construct a P2MR address from a script tree with multiple leaves
* This demonstrates a more complex script tree structure.
*/
function example2_multiLeafScriptTree() {
console.log('=== Example 2: P2MR from multi-leaf script tree ===');
// Generate two different key pairs for the leaves
const keyPair1 = ECPair.makeRandom({ rng });
const keyPair2 = ECPair.makeRandom({ rng });
const pubkey1 = keyPair1.publicKey;
const pubkey2 = keyPair2.publicKey;
const xOnlyPubkey1 = ecc.xOnlyPointFromPoint(pubkey1);
const xOnlyPubkey2 = ecc.xOnlyPointFromPoint(pubkey2);
const script1 = bscript.compile([Buffer.from(xOnlyPubkey1), bscript.OPS.OP_CHECKSIG]);
const script2 = bscript.compile([Buffer.from(xOnlyPubkey2), bscript.OPS.OP_CHECKSIG]);
// Create a script tree with two leaves (array of two leaf objects)
const scriptTree: Taptree = [
{ output: script1 },
{ output: script2 },
];
// Construct the P2MR payment
const payment = p2mr({
scriptTree: scriptTree,
});
console.log('Generated compressed public keys:');
console.log(' Pubkey 1:', pubkey1.toString('hex'));
console.log(' Pubkey 2:', pubkey2.toString('hex'));
console.log('X-only pubkeys:');
console.log(' X-only 1:', Buffer.from(xOnlyPubkey1).toString('hex'));
console.log(' X-only 2:', Buffer.from(xOnlyPubkey2).toString('hex'));
console.log('Script tree leaves:');
console.log(' Leaf 1:', bscript.toASM(script1));
console.log(' Leaf 2:', bscript.toASM(script2));
console.log('P2MR Address:', payment.address);
console.log('Output script:', bscript.toASM(payment.output!));
console.log('Merkle root hash:', payment.hash ? Buffer.from(payment.hash).toString('hex') : undefined);
const message1 = Buffer.from('P2MR demo - example 2 leaf 1', 'utf8');
const message2 = Buffer.from('P2MR demo - example 2 leaf 2', 'utf8');
const result1 = signAndVerify(keyPair1, xOnlyPubkey1, message1);
const result2 = signAndVerify(keyPair2, xOnlyPubkey2, message2);
console.log('Leaf 1 signature info:');
console.log(' Message:', result1.message.toString('utf8'));
console.log(' Hash256(message):', result1.hash.toString('hex'));
console.log(' Schnorr signature (64-byte):', result1.signature.toString('hex'));
console.log(' Signature + default sighash (65-byte):', result1.signatureWithSighashDefault.toString('hex'));
console.log(' Signature valid:', result1.verified);
console.log(' Witness stack:', [result1.signatureWithSighashDefault.toString('hex'), bscript.toASM(script1)]);
console.log('Leaf 2 signature info:');
console.log(' Message:', result2.message.toString('utf8'));
console.log(' Hash256(message):', result2.hash.toString('hex'));
console.log(' Schnorr signature (64-byte):', result2.signature.toString('hex'));
console.log(' Signature + default sighash (65-byte):', result2.signatureWithSighashDefault.toString('hex'));
console.log(' Signature valid:', result2.verified);
console.log(' Witness stack:', [result2.signatureWithSighashDefault.toString('hex'), bscript.toASM(script2)]);
console.log();
}
/**
* Example 4: Construct a P2MR address from a hash and redeem script
* This demonstrates creating a P2MR when you have the hash directly.
*/
function example3_fromHashAndRedeem() {
console.log('=== Example 3: P2MR from hash and redeem script ===');
// Generate a key pair
const keyPair = ECPair.makeRandom({ rng });
const pubkey = keyPair.publicKey;
const xOnlyPubkey = ecc.xOnlyPointFromPoint(pubkey);
const redeemScript = bscript.compile([Buffer.from(xOnlyPubkey), bscript.OPS.OP_CHECKSIG]);
// Use a known hash (from test fixtures)
const hash = Buffer.from(
'b424dea09f840b932a00373cdcdbd25650b8c3acfe54a9f4a641a286721b8d26',
'hex',
);
// Construct the P2MR payment
const payment = p2mr({
hash: hash,
redeem: {
output: redeemScript,
},
});
console.log('Generated compressed pubkey:', pubkey.toString('hex'));
console.log('X-only pubkey:', Buffer.from(xOnlyPubkey).toString('hex'));
console.log('Redeem script:', bscript.toASM(redeemScript));
console.log('Hash:', hash.toString('hex'));
console.log('P2MR Address:', payment.address);
console.log('Output script:', bscript.toASM(payment.output!));
const message = Buffer.from('P2MR demo - example 3', 'utf8');
const result = signAndVerify(keyPair, xOnlyPubkey, message);
console.log('Message:', result.message.toString('utf8'));
console.log('Hash256(message):', result.hash.toString('hex'));
console.log('Schnorr signature (64-byte):', result.signature.toString('hex'));
console.log('Signature + default sighash (65-byte):', result.signatureWithSighashDefault.toString('hex'));
console.log('Signature valid:', result.verified);
console.log('Witness stack:', [result.signatureWithSighashDefault.toString('hex'), bscript.toASM(redeemScript)]);
console.log();
}
// Run all examples
console.log('P2MR Address Construction Examples\n');
console.log('=====================================\n');
example1_simpleScriptTree();
example2_multiLeafScriptTree();
example3_fromHashAndRedeem();
console.log('=====================================');
console.log('All examples completed!');
================================================
FILE: bip-0360/ref-impl/js/src/test-npm-pqc-package.js
================================================
#!/usr/bin/env node
/**
* Node.js test script for Bitcoin PQC WASM module (High-Level API)
*
* Usage: node test-npm-package.js
*
* This script tests the high-level TypeScript wrapper API (index.js) from the
* command line, which provides a cleaner interface than the low-level API.
*/
import { randomBytes } from 'node:crypto';
// Load the high-level WASM module
let bitcoinpqc;
let Algorithm;
try {
const module = await import('@jbride/bitcoinpqc-wasm');
bitcoinpqc = module.bitcoinpqc || module.default;
Algorithm = module.Algorithm;
if (!bitcoinpqc || !Algorithm) {
throw new Error('Failed to import bitcoinpqc or Algorithm from @jbride/bitcoinpqc-wasm');
}
} catch (error) {
console.error('Failed to load WASM module:', error);
console.error('Make sure you have installed the @jbride/bitcoinpqc-wasm package before running this test.');
process.exit(1);
}
// Helper function to generate random bytes
function generateRandomBytes(length) {
const array = new Uint8Array(length);
const bytes = randomBytes(length);
array.set(bytes);
return array;
}
// Test function
async function testAlgorithm(algorithm, name) {
console.log(`\nTesting ${name} algorithm:`);
console.log('------------------------');
try {
// Get key and signature sizes
const pkSize = bitcoinpqc.publicKeySize(algorithm);
const skSize = bitcoinpqc.secretKeySize(algorithm);
const sigSize = bitcoinpqc.signatureSize(algorithm);
console.log(`Public key size: ${pkSize} bytes`);
console.log(`Secret key size: ${skSize} bytes`);
console.log(`Signature size: ${sigSize} bytes`);
// Generate random data for key generation
const randomData = generateRandomBytes(128);
// Generate a key pair
const keygenStart = Date.now();
const keypair = bitcoinpqc.generateKeypair(algorithm, randomData);
const keygenDuration = Date.now() - keygenStart;
console.log(`Key generation time: ${keygenDuration} ms`);
// Create a message to sign
const messageText = 'This is a test message for PQC signature verification';
const message = Buffer.from(messageText, 'utf8');
const messageUint8 = new Uint8Array(message);
console.log(`Message to sign: "${messageText}"`);
console.log(`Message length: ${message.length} bytes`);
// Sign the message
const signStart = Date.now();
let signature;
try {
signature = bitcoinpqc.sign(keypair.secretKey, messageUint8, algorithm);
const signDuration = Date.now() - signStart;
console.log(`Signing time: ${signDuration} ms`);
console.log(`Actual signature size: ${signature.size} bytes`);
} catch (error) {
const signDuration = Date.now() - signStart;
console.log(`Signing failed after ${signDuration} ms`);
console.log(`Error: ${error.message}`);
if (algorithm === Algorithm.SLH_DSA_SHAKE_128S) {
console.log('');
console.log('⚠️ NOTE: SLH-DSA-SHAKE-128s signing is currently experiencing');
console.log(' issues when compiled to WebAssembly. This appears to be a');
console.log(' bug in the SPHINCS+ reference implementation when compiled');
console.log(' to WASM. ML-DSA-44 (Dilithium) works correctly.');
console.log('');
console.log(' Key generation succeeded, but signing failed.');
console.log(' This is a known limitation of the browser/WASM build.');
}
throw error;
}
// Verify the signature
const verifyStart = Date.now();
const verifyResult = bitcoinpqc.verify(
keypair.publicKey,
messageUint8,
signature,
algorithm
);
const verifyDuration = Date.now() - verifyStart;
if (verifyResult) {
console.log('Signature verified successfully!');
} else {
console.log('ERROR: Signature verification failed!');
}
console.log(`Verification time: ${verifyDuration} ms`);
// Try to verify with a modified message
const modifiedMessageText = 'This is a MODIFIED message for PQC signature verification';
const modifiedMessage = Buffer.from(modifiedMessageText, 'utf8');
const modifiedMessageUint8 = new Uint8Array(modifiedMessage);
console.log(`Modified message: "${modifiedMessageText}"`);
const modifiedVerifyResult = bitcoinpqc.verify(
keypair.publicKey,
modifiedMessageUint8,
signature,
algorithm
);
if (modifiedVerifyResult) {
console.log('ERROR: Signature verified for modified message!');
} else {
console.log('Correctly rejected signature for modified message');
}
console.log('✓ Test passed!\n');
return true;
} catch (error) {
console.error(`❌ Error: ${error.message}`);
if (error.stack) {
console.error(error.stack);
}
return false;
}
}
async function runTests() {
console.log('Bitcoin PQC Library Example (Node.js - High-Level API)');
console.log('======================================================\n');
console.log('This example tests the post-quantum signature algorithms designed for BIP-360 and the Bitcoin QuBit soft fork.');
console.log('Using the high-level TypeScript wrapper API (index.js).\n');
// Initialize the module
try {
console.log('Initializing WASM module...');
await bitcoinpqc.init({
onRuntimeInitialized: () => {
console.log('✓ WASM module initialized successfully!\n');
},
print: (text) => {
// Enable WASM print output for debugging
console.log('WASM:', text);
},
printErr: (text) => {
console.error('WASM Error:', text);
},
// Node.js-specific: provide crypto.getRandomValues
getRandomValues: (arr) => {
const bytes = randomBytes(arr.length);
arr.set(bytes);
return arr;
}
});
} catch (error) {
console.error('Failed to initialize module:', error);
if (error.stack) {
console.error(error.stack);
}
process.exit(1);
}
const results = [];
// Test ML-DSA-44
results.push(await testAlgorithm(Algorithm.ML_DSA_44, 'ML-DSA-44'));
// Test SLH-DSA-Shake-128s
results.push(await testAlgorithm(Algorithm.SLH_DSA_SHAKE_128S, 'SLH-DSA-Shake-128s'));
// Summary
console.log('\n======================================================');
console.log('Test Summary:');
console.log(` ML-DSA-44: ${results[0] ? '✓ PASSED' : '✗ FAILED'}`);
console.log(` SLH-DSA-Shake-128s: ${results[1] ? '✓ PASSED' : '✗ FAILED'}`);
console.log('======================================================\n');
const exitCode = results.every(r => r) ? 0 : 1;
process.exit(exitCode);
}
// Start
runTests();
================================================
FILE: bip-0360/ref-impl/js/tsconfig.json
================================================
{
// Visit https://aka.ms/tsconfig to read more about this file
"include": [
"src/**/*"
],
"compilerOptions": {
// File Layout
"rootDir": "./src",
"outDir": "./dist",
// Environment Settings
// See also https://aka.ms/tsconfig/module
"module": "nodenext",
"target": "esnext",
"types": ["node"],
// For nodejs:
// "lib": ["esnext"],
// Other Outputs
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// Stricter Typechecking Options
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// Style Options
// "noImplicitReturns": true,
// "noImplicitOverride": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noFallthroughCasesInSwitch": true,
// "noPropertyAccessFromIndexSignature": true,
// Recommended Options
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
}
}
================================================
FILE: bip-0360/ref-impl/python/.gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
================================================
FILE: bip-0360/ref-impl/rust/.cargo/config.toml
================================================
[registries.kellnr-denver-space]
index = "sparse+https://crates.denver.space/api/v1/crates/"
================================================
FILE: bip-0360/ref-impl/rust/Cargo.toml
================================================
[package]
name = "p2mr-ref"
version = "0.1.0"
edition = "2024"
[dependencies]
# Dev version of miniscript crate re-exports bitcoin 0.32.6
# view configuration for "kellnr-denver-space":
# cat .cargo/config.toml
miniscript = { version="=13.0.0-p2mr-pqc-1.0", registry="kellnr-denver-space" }
bitcoin = { package = "bitcoin-p2mr-pqc", version="0.32.6-p2mr-pqc.1", features = ["rand-std", "serde", "base64"], registry = "kellnr-denver-space" }
bitcoinpqc = { version="0.3.0", features = ["serde"], registry="kellnr-denver-space" }
# BDK Wallet with P2MR support
#bdk_wallet = { version = "=3.0.0-alpha.0-pqc-0.1", registry = "kellnr-denver-space" }
env_logger = "0.11.5"
log = "0.4.22"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
once_cell = "1.19"
hex = "0.4.3"
anyhow = "1.0.98"
thiserror = "2.0.12"
rand = "0.9"
[patch.crates-io]
#bitcoin = { git = "https://github.com/jbride/rust-bitcoin.git", branch = "p2mr" }
# Verify:
# cargo update
# cargo tree -p bitcoin | more
# bitcoin = { path = "./rust-bitcoin/bitcoin" }
# cargo tree -p miniscript | more
#miniscript = { path = "./rust-miniscript" }
# bitcoinpqc = { path = "./libbitcoinpqc" }
================================================
FILE: bip-0360/ref-impl/rust/README.md
================================================
# p2mr test vectors
This rust project contains the test vectors for BIP-360
## Run Test Vectors
These test vectors are being developed in conjunction with forks of [rust-bitcoin](https://github.com/jbride/rust-bitcoin/tree/p2mr) and [rust-miniscript](https://github.com/jbride/rust-miniscript/tree/p2mr-pqc) customized with p2mr functionality.
1. environment variables
```
// Specify Bitcoin network used when generating bip350 (bech32m) address
// Options: regtest, testnet, signet
// Default: mainnet
$ export BITCOIN_NETWORK=
```
1. run a specific test:
```
$ cargo test test_p2mr_single_leaf_script_tree -- --nocapture
```
## Local Development
All P2MR/PQC enabled bitcoin crates are temporarily available in a custom crate registry at: `https://crates.denver.space`.
These crates will be made available in `crates.io` in the near future.
Subsequently, you will need to execute the following at the root of your rust workspace:
```bash
mkdir .cargo \
&& echo '[registries.kellnr-denver-space]
index = "sparse+https://crates.denver.space/api/v1/crates/"' > .cargo/config
```
Afterwards, for all P2MR/PQC enabled dependencies used in your project, include a "registry" similar to the following:
```bash
bitcoin = { version="0.32.6", registry = "kellnr-denver-space" }
```
================================================
FILE: bip-0360/ref-impl/rust/docs/development_notes.adoc
================================================
== bitcoin core
=== Two Different Size Limits:
* *MAX_SCRIPT_ELEMENT_SIZE* (in interpreter.cpp line 1882) - This is a consensus rule that limits individual stack elements to 520 bytes. This is what's currently blocking your SLH-DSA signature.
* *MAX_STANDARD_P2MR_STACK_ITEM_SIZE* (in policy.h) - This is a policy rule that limits P2MR stack items to 80 bytes (or 8000 bytes with your change) for standardness.
== P2MR changes to rust-bitcoin
# 1. p2mr module
The p2mr branch of rust-bitcoin includes a new module: `p2mr`.
Source code for this new module can be found [here](https://github.com/jbride/rust-bitcoin/blob/p2mr/bitcoin/src/p2mr/mod.rs).
Highlights of this _p2mr_ module as follows:
## 1.1. p2mrBuilder
This is struct inherits from the rust-bitcoin _TaprootBuilder_.
It has an important modification in that it disables keypath spend.
Similar to its Taproot parent, p2mrBuilder provides functionality to add leaves to a TapTree.
One its TapTree has been fully populated with all leaves, an instance of _p2mrSpendInfo_ can be retrieved from p2mrBuilder.
```
pub struct p2mrBuilder {
inner: TaprootBuilder
}
impl p2mrBuilder {
/// Creates a new p2mr builder.
pub fn new() -> Self {
Self {
inner: TaprootBuilder::new()
}
}
/// Adds a leaf to the p2mr builder.
pub fn add_leaf_with_ver(
self,
depth: u8,
script: ScriptBuf,
leaf_version: LeafVersion,
) -> Result {
match self.inner.add_leaf_with_ver(depth, script, leaf_version) {
Ok(builder) => Ok(Self { inner: builder }),
Err(_) => Err(p2mrError::LeafAdditionError)
}
}
/// Finalizes the p2mr builder.
pub fn finalize(self) -> Result {
let node_info: NodeInfo = self.inner.try_into_node_info().unwrap();
Ok(p2mrSpendInfo {
merkle_root: Some(node_info.node_hash()),
//script_map: self.inner.script_map().clone(),
})
}
/// Converts the p2mr builder into a Taproot builder.
pub fn into_inner(self) -> TaprootBuilder {
self.inner
}
}
```
## 1.2. p2mrSpendInfo
Provides merkle_root of a completed p2mr TapTree
```
/// A struct for p2mr spend information.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct p2mrSpendInfo {
/// The merkle root of the script path.
pub merkle_root: Option
}
```
## 1.3. p2mrScriptBuf
Allows for creation of a p2mr scriptPubKey UTXO using only the merkle root of a script tree only.
```
/// A wrapper around ScriptBuf for p2mr (Pay to Quantum Resistant Hash) scripts.
pub struct p2mrScriptBuf {
inner: ScriptBuf
}
impl p2mrScriptBuf {
/// Creates a new p2mr script from a ScriptBuf.
pub fn new(inner: ScriptBuf) -> Self {
Self { inner }
}
/// Generates p2mr scriptPubKey output
/// Only accepts the merkle_root (of type TapNodeHash)
/// since keypath spend is disabled in p2mr
pub fn new_p2mr(merkle_root: TapNodeHash) -> Self {
// https://github.com/cryptoquick/bips/blob/p2mr/bip-0360.mediawiki#scriptpubkey
let merkle_root_hash_bytes: [u8; 32] = merkle_root.to_byte_array();
let script = Builder::new()
.push_opcode(OP_PUSHNUM_3)
// automatically pre-fixes with OP_PUSHBYTES_32 (as per size of hash)
.push_slice(&merkle_root_hash_bytes)
.into_script();
p2mrScriptBuf::new(script)
}
/// Returns the script as a reference.
pub fn as_script(&self) -> &Script {
self.inner.as_script()
}
}
```
## 1.4. p2mr Control Block
Closely related to P2TR control block.
Difference being that _internal public key_ is not included.
```
/// A control block for p2mr (Pay to Quantum Resistant Hash) script path spending.
/// This is a simplified version of Taproot's control block that excludes key-related fields.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct p2mrControlBlock {
/// The version of the leaf.
pub leaf_version: LeafVersion,
/// The merkle branch of the leaf.
pub merkle_branch: TaprootMerkleBranch,
}
```
# 2. Witness Program
New p2mr related functions that allow for creation of a new V3 _witness program_ given a merkle_root only.
Found in bitcoin/src/blockdata/script/witness_program.rs
```
/// Creates a [`WitnessProgram`] from a 32 byte merkle root.
fn new_p2mr(program: [u8; 32]) -> Self {
WitnessProgram { version: WitnessVersion::V3, program: ArrayVec::from_slice(&program) }
}
/// Creates a pay to quantum resistant hash address from a merkle root.
pub fn p2mr(merkle_root: Option) -> Self {
let merkle_root = merkle_root.unwrap();
WitnessProgram::new_p2mr(merkle_root.to_byte_array())
}
```
# 3. Address
New _p2mr_ function that allows for creation of a new _p2mr_ Address given a merkle_root only.
Found in bitcoin/src/address/mod.rs
```
/// Creates a pay to quantum resistant hash address from a merkle root.
pub fn p2mr(merkle_root: Option, hrp: impl Into) -> Address {
let program = WitnessProgram::p2mr(merkle_root);
Address::from_witness_program(program, hrp)
}
```
================================================
FILE: bip-0360/ref-impl/rust/docs/p2mr-end-to-end.adoc
================================================
:scrollbar:
:data-uri:
:toc2:
:linkattrs:
= P2MR End-to-End Tutorial
:numbered:
This tutorial is inspired by the link:https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature[script-path-spend-signature] example of the _learnmeabitcoin_ tutorial.
It is customized to create, fund and spend from a P2MR UTXO to a P2WPKH address.
In addition, this tutorial allows for the (un)locking mechanism of the script to optionally use _Post Quantum Cryptography_ (PQC).
The purpose of this tutorial is to demonstrate construction and spending of a link:https://github.com/cryptoquick/bips/blob/p2qrh/bip-0360.mediawiki[bip-360] `p2mr` UTXO (optionally using _Post-Quantum Cryptography_).
The steps outlined in this tutorial are executed using a custom Bitcoin Core instance running either in `regtest` or `signet`.
== Pre-reqs
=== Bitcoin Core
If participating in a workshop, your instructor will provide a bitcoin environment.
Related: your instructor should also provide you with a wallet.
Otherwise, if running this tutorial on your own, follow the instructions in the appendix of this doc: <>.
=== Shell Environment
. *docker / podman*
+
NOTE: If you have built the custom `p2mr` enabled Bitcoin Core, you do not need docker (nor podman) installed. Skip this section.
+
This tutorial makes use of a `p2mr` enabled _bitcoin-cli_ utility.
This utility is made available as a docker (or podman) container.
Ensure your host machine has either docker or podman installed.
. *bitcoin-cli* command line utility:
+
NOTE: If you have built the custom `p2mr` enabled Bitcoin Core, you can simply use the `bitcoin-cli` utility found in the `build/bin/` directory. No need to use the _dockerized_ utility described below.
.. You will need a `bitcoin-cli` binary that is `p2mr` enabled.
For this purpose, a docker container with this `bitcoin-cli` utility is provided:
+
-----
docker pull quay.io/jbride2000/bitcoin-cli:p2mr-pqc-0.0.1
-----
.. Configure an alias to the `bitcoin-cli` command that connects to your customized bitcoin-core node.
+
-----
alias b-cli='docker run --rm --network host bitcoin-cli:p2mr-pqc-0.0.1 -rpcconnect=192.168.122.1 -rpcport=18443 -rpcuser=regtest -rpcpassword=regtest'
-----
. *jq*: ensure json parsing utility is link:https://jqlang.org/download/[installed] and available via your $PATH.
. *awk* : standard utility for all Linux distros (often packaged as `gawk`).
. *Rust* development environment with _cargo_ utility. Use link:https://rustup[Rustup] to install.
== Create & Fund P2MR UTXO
The purpose of this workshop is to demonstrate construction and spending of a link:https://github.com/cryptoquick/bips/blob/p2qrh/bip-0360.mediawiki[bip-360] _P2MR_ address (optionally using _Post-Quantum Cryptography_).
In this section of the workshop, you create and fund a P2MR address.
The following depicts the construction of a P2MR _TapTree_ and computation its _scriptPubKey_.
image::images/p2mr_construction.png[]
A P2MR address is created by adding locking scripts to leaves of a _TapTree_.
The locking scripts can use either _Schnorr_ (as per BIP-360) or _SLH-DSA_ (defined in a future BIP) cryptography.
. Set an environment variable specific to your Bitcoin network environment (regtest, signet, etc)
+
[source,bash]
-----
export BITCOIN_NETWORK=regtest
-----
+
Doing so influences the P2MR address that you'll create later in this tutorial.
. Define number of total leaves in tap tree :
+
[source,bash]
-----
export TOTAL_LEAF_COUNT=5
-----
. OPTIONAL: Indicate what type of cryptography to use in the locking scripts of your TapTree leaves.
Valid options are: `MIXED`, `SCHNORR_ONLY`, `SLH_DSA_ONLY`, and `CONCATENATED_SCHNORR_AND_SLH_DSA`.
Default is `MIXED`.
+
[source,bash]
-----
export TAP_TREE_LOCK_TYPE=MIXED
-----
.. If you set _TAP_TREE_LOCK_TYPE=SCHNORR_ONLY_, then the locking script of your TapTree leaves will utilize _Schnorr_ cryptography.
+
Schnorr is not quantum-resistant. However, its signature size is relatively small: 64 bytes.
A _SCHNORR_ONLY_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_schnorr_only.png[s,300]
.. If you set _TAP_TREE_LOCK_TYPE=SLH_DSA_ONLY_, then the locking script of your TapTree leaves will utilize _SLH-DSA_ cryptography.
A _SLH_DSA_ONLY_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_slh_dsa_only.png[l,300]
+
SLH_DSA is quantum-resistant. However, the trade-off is the much larger signature size 7,856 bytes when spending.
+
image::images/crypto_key_characteristics.png[]
+
NOTE: PQC cryptography is made available to this BIP-360 reference implementation via the link:https://crates.io/crates/bitcoinpqc[libbitcoinpqc Rust bindings].
.. If you set _MIXED_, then each leaf of the taptree will consist of *either* a Schnorr based locking script or a SLH-DSA based locking script.
A _MIXED_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_mixed.png[t,300]
+
NOTE: The benefit of constructing a taptree with a mixed set of cryptography used as locking scripts in the leaves is articulated nicely in link:https://www.bitmex.com/blog/Taproot%20Quantum%20Spend%20Paths[this article from BitMex].
.. If you set _TAP_TREE_LOCK_TYPE=CONCATENATED_SCHNORR_AND_SLH_DSA_, then the locking script of your TapTree leaves will be secured using both SCHNORR and SLH-DSA cryptography in a concatenated / serial manner.
Private keys for both SCHNORR and SLH-DSA will be needed when unlocking.
A _CONCATENATED_SCHNORR_AND_SLH_DSA_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_concatenated.png[p,300]
. Set the tap leaf index to later use as the unlocking script (when spending) For example, to later spend from the 5th leaf of the tap tree:
+
[source,bash]
-----
export LEAF_TO_SPEND_FROM=4
-----
. Generate a P2MR scripPubKey with multi-leaf taptree:
+
[source,bash]
-----
export BITCOIN_ADDRESS_INFO=$( cargo run --example p2mr_construction ) \
&& echo $BITCOIN_ADDRESS_INFO | jq -r .
-----
+
NOTE: In `regtest`, you can expect a P2MR address that starts with: `bcrt1z` .
+
[subs=+quotes]
++++
What just happened?
The Rust based reference implementation for BIP-0360 is leveraged to construct a transaction with a `p2mr` UTXO as follows:
A configurable number of leaves are generated each with their own locking script.
Each of these leaves are added to a Huffman tree that sorts the leaves by weight.
The merkle root of the tree is calculated and subsequently used to generate the p2mr witness program and BIP0350 address.
The source code for the above logic is found in this project: src/lib.rs
++++
. Only if you previously set `TAP_TREE_LOCK_TYPE=MIXED`, set the environment variable `SPENDING_LEAF_TYPE`.
Valid values are `SHNORR_ONLY` or `SLH_DSA_ONLY` based on the type of locking script that was used in the leaf you will spend from later in this lab. The logs from the previous step tell you the appropriate value to set. For instance:
+
-----
NOTE: TAP_TREE_LOCK_TYPE=MIXED requires setting SPENDING_LEAF_TYPE when spending (based on leaf_script_type in output above) as follows:
export SPENDING_LEAF_TYPE=SCHNORR_ONLY
-----
. Set some env vars (for use in later steps in this tutorial) based on previous result:
+
[source,bash]
-----
export MERKLE_ROOT=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.tree_root_hex' ) \
&& export LEAF_SCRIPT_PRIV_KEYS_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_priv_keys_hex' ) \
&& export LEAF_SCRIPT_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_hex' ) \
&& export CONTROL_BLOCK_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.control_block_hex' ) \
&& export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.script_pubkey_hex' ) \
&& export P2MR_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.bech32m_address' )
-----
. View tapscript used in target leaf of taptree:
+
[source,bash]
-----
b-cli decodescript $LEAF_SCRIPT_HEX | jq -r '.asm'
-----
+
NOTE: If not using PQC, notice that this script commits to a Schnorr 32-byte x-only public key.
If using PQC, this script commits to a Schnorr 32-byte SLH-DSA pub key and a OP_SUCCESS127 (represented as `OP_SUBSTR`) opcode.
. Fund this P2MR address with the coinbase reward of a newly generated block:
+
Choose from one of the following networks:
.. Regtest
+
If on `regtest` network, execute the following:
+
[source,bash]
-----
export COINBASE_REWARD_TX_ID=$( b-cli -named generatetoaddress nblocks=1 address="$P2MR_ADDR" maxtries=5 | jq -r '.[]' ) \
&& echo $COINBASE_REWARD_TX_ID
-----
+
NOTE: Sometimes Bitcoin Core may not hit a block (even on regtest). If so, just try the above command again.
.. Signet
+
If on `signet` network, then execute the following:
+
[source,bash]
-----
$BITCOIN_SOURCE_DIR/contrib/signet/miner --cli "bitcoin-cli -conf=$HOME/anduro-360/configs/bitcoin.conf.signet" generate \
--address $P2MR_ADDR \
--grind-cmd "$BITCOIN_SOURCE_DIR/build/bin/bitcoin-util grind" \
--min-nbits --set-block-time $(date +%s) \
--poolid "MARA Pool"
-----
. view summary of all txs that have funded P2MR address
+
[source,bash]
-----
export P2MR_DESC=$( b-cli getdescriptorinfo "addr($P2MR_ADDR)" | jq -r '.descriptor' ) \
&& echo $P2MR_DESC \
&& b-cli scantxoutset start '[{"desc": "'''$P2MR_DESC'''"}]'
-----
. grab txid of first tx with unspent funds:
+
[source,bash]
-----
export FUNDING_TX_ID=$( b-cli scantxoutset start '[{"desc": "'''$P2MR_DESC'''"}]' | jq -r '.unspents[0].txid' ) \
&& echo $FUNDING_TX_ID
-----
. Set FUNDING_UTXO_INDEX env var (used later to correctly identify funding UTXO when generating the spending tx)
+
[source,bash]
-----
export FUNDING_UTXO_INDEX=0
-----
. view details of funding UTXO to the P2MR address:
+
[source,bash]
-----
export FUNDING_UTXO=$( b-cli getrawtransaction $FUNDING_TX_ID 1 | jq -r '.vout['''$FUNDING_UTXO_INDEX''']' ) \
&& echo $FUNDING_UTXO | jq -r .
-----
+
NOTE: the above only works when Bitcoin Core is started with the following arg: -txindex
== Spend P2MR UTXO
In the previous section, you created and funded a P2MR UTXO.
That UTXO includes a leaf script locked with a key-pair (optionally based on PQC) known to you.
In this section, you spend from that P2MR UTXO.
Specifically, you will generate an appropriate _SigHash_ and sign it (to create a signature) using the known private key that unlocks the known leaf script of the P2MR UTXO.
For the purpose of this tutorial, you will spend funds to a new P2WPKH utxo. (there is nothing novel about this P2WPKH utxo).
. Determine value (in sats) of the funding P2MR utxo:
+
[source,bash]
-----
export FUNDING_UTXO_AMOUNT_SATS=$(echo $FUNDING_UTXO | jq -r '.value' | awk '{printf "%.0f", $1 * 100000000}') \
&& echo $FUNDING_UTXO_AMOUNT_SATS
-----
. Generate additional blocks.
+
This is necessary if you have only previously generated less than 100 blocks.
+
Otherwise, you may see an error from bitcoin core such as the following when attempting to spend:
+
_bad-txns-premature-spend-of-coinbase, tried to spend coinbase at depth 1_
.. regtest
+
[source,bash]
-----
b-cli -generate 110
-----
.. signet
+
This will involve having the signet miner generate about 110 blocks .... which can take about 10 minutes.
+
The `common/utils` directory of this project provides a script called: link:../../common/utils/signet_miner_loop.sh[signet_miner_loop.sh].
. Referencing the funding tx (via $FUNDING_TX_ID and $FUNDING_UTXO_INDEX), create the spending tx:
+
[source,bash]
-----
export SPEND_DETAILS=$( cargo run --example p2mr_spend )
-----
+
[subs=+quotes]
++++
What just happened?
The Rust based reference implementation for BIP-0360 is leveraged to construct a transaction that spends from the `p2mr` UTXO as follows:
Create a transaction template (aka: SigHash) that serves as the message to be signed.
Using the known private key and the SigHash, create a signature that is capable of unlocking one of the leaf scripts of the P2MR tree.
Add this signature to the witness section of the transaction.
The source code for the above logic is found in this project: src/lib.rs
++++
. Set environment variables passed to _bitcoin-cli_ when spending:
+
[source,bash]
-----
export RAW_P2MR_SPEND_TX=$( echo $SPEND_DETAILS | jq -r '.tx_hex' ) \
&& echo "RAW_P2MR_SPEND_TX = $RAW_P2MR_SPEND_TX" \
&& export SIG_HASH=$( echo $SPEND_DETAILS | jq -r '.sighash' ) \
&& echo "SIG_HASH = $SIG_HASH" \
&& export SIG_BYTES=$( echo $SPEND_DETAILS | jq -r '.sig_bytes' ) \
&& echo "SIG_BYTES = $SIG_BYTES"
-----
. Inspect the spending tx:
+
[source,bash]
-----
b-cli decoderawtransaction $RAW_P2MR_SPEND_TX
-----
+
Pay particular attention to the `vin.txinwitness` field.
Do the three elements (script input, script and control block) of the witness stack for this script path spend make sense ?
What do you observe as the first byte of the `control block` element ?
. Test standardness of the spending tx by sending to local mempool of p2mr enabled Bitcoin Core:
+
[source,bash]
-----
b-cli testmempoolaccept '["'''$RAW_P2MR_SPEND_TX'''"]'
-----
. Submit tx:
+
[source,bash]
-----
export P2MR_SPENDING_TX_ID=$( b-cli sendrawtransaction $RAW_P2MR_SPEND_TX ) \
&& echo $P2MR_SPENDING_TX_ID
-----
+
NOTE: Should return same tx id as was included in $RAW_P2MR_SPEND_TX
== Mine P2MR Spend TX
. View tx in mempool:
+
[source,bash]
-----
b-cli getrawtransaction $P2MR_SPENDING_TX_ID 1
-----
+
NOTE: There will not yet be a field `blockhash` in the response.
. Mine 1 block:
.. regtest:
+
[source,bash]
-----
b-cli -generate 1
-----
.. signet:
+
If on `signet` network, then execute the following:
+
[source,bash]
-----
$BITCOIN_SOURCE_DIR/contrib/signet/miner --cli "bitcoin-cli -conf=$HOME/anduro-360/configs/bitcoin.conf.signet" generate \
--address $P2MR_ADDR \
--grind-cmd "$BITCOIN_SOURCE_DIR/build/bin/bitcoin-util grind" \
--min-nbits --set-block-time $(date +%s) \
--poolid "MARA Pool"
-----
. Obtain `blockhash` field of mined tx:
+
[source,bash]
-----
export BLOCK_HASH=$( b-cli getrawtransaction $P2MR_SPENDING_TX_ID 1 | jq -r '.blockhash' ) \
&& echo $BLOCK_HASH
-----
. View tx in block:
+
[source,bash]
-----
b-cli getblock $BLOCK_HASH | jq -r .tx
-----
== Appendix
[[build_p2mr]]
=== Build P2MR / PQC Enabled Bitcoin Core
The link:https://github.com/jbride/bitcoin/tree/p2mr[p2mr branch] of bitcoin core is needed.
Build instructions for the `p2mr` branch are the same as `master` and is documented link:https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md[here].
As such, the following is an example series of steps (on a Fedora 42 host) to compile and run the `p2mr` branch of bitcoin core:
. Set BITCOIN_SOURCE_DIR
+
-----
export BITCOIN_SOURCE_DIR=/path/to/root/dir/of/cloned/bitcoin/source
-----
. build
+
-----
cmake -B build \
-DWITH_ZMQ=ON \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_BENCH=ON \
-DBUILD_DAEMON=ON \
-DSANITIZERS=address,undefined
cmake --build build -j$(nproc)
-----
. run in either `regtest` or `signet` mode:
.. regtest:
+
-----
./build/bin/bitcoind -daemon=0 -regtest=1 -txindex -prune=0
-----
.. signet:
+
-----
./build/bin/bitcoind -daemon=0 -signet=1 -txindex -prune=0
-----
+
NOTE: If running in `signet`, your bitcoin core will need to be configured with the `signetchallenge` property.
link:https://edil.com.br/blog/creating-a-custom-bitcoin-signet[This tutorial] provides a nice overview of the topic.
=== libbitcoinpqc build
The `p2mr-pqc` branch of this project includes a dependency on the link:https://crates.io/crates/libbitcoinpqc[libbitcoinpqc crate].
libbitcoinpqc contains native code (C/C++/ASM) and is made available to Rust projects via Rust bindings.
This C/C++/ASM code is provided in the libbitcoinpqc crate as source code (not prebuilt binaries).
Subsequently, the `Cargo` utility needs to build this libbitcoinpqc C native code on your local machine.
You will need to have C development related libraries installed on your local machine.
Every developer or CI machine building `p2mr-ref` must have cmake and a C toolchain installed locally.
==== Linux
. Debian / Ubuntu
+
-----
sudo apt update
sudo apt install cmake build-essential clang libclang-dev
-----
. Fedora / RHEL
+
-----
sudo dnf5 update
sudo dnf5 install cmake make gcc gcc-c++ clang clang-libs llvm-devel
-----
==== OSX
[[bitcoin_core_wallet]]
=== Bitcoin Core Wallet
This tutorial assumes that a bitcoin core wallet is available.
. For example, the following would be sufficient:
+
-----
export W_NAME=anduro
b-cli -named createwallet \
wallet_name=$W_NAME \
descriptors=true \
load_on_startup=true
-----
=== Schnorr + SLH-DSA
-----
OP_CHECKSIG OP_SUBSTR OP_BOOLAND OP_VERIFY
-----
The logic flow is:
. OP_CHECKSIG: Verify Schnorr signature against Schnorr pubkey
. OP_SUBSTR: Verify SLH-DSA signature against SLH-DSA pubkey (using OP_SUBSTR for the SLH-DSA verification)
. OP_BOOLAND: Ensure both signature verifications succeeded
. OP_VERIFY: Final verification that the script execution succeeded
. This creates a "both signatures required" locking condition, which is exactly what you want for SCHNORR_AND_SLH_DSA scripts.
===== Sighash bytes
Sighash bytes are appended to each signature, instead of being separate witness elements:
. SlhDsaOnly: SLH-DSA signature + sighash byte appended
. SchnorrOnly: Schnorr signature + sighash byte appended
. SchnorrAndSlhDsa: Schnorr signature (no sighash) + SLH-DSA signature + sighash byte appended to the last signature
================================================
FILE: bip-0360/ref-impl/rust/docs/p2mr-signet-workshop.adoc
================================================
:scrollbar:
:data-uri:
:toc2:
:linkattrs:
= P2MR End-to-End workshop
:numbered:
Welcome to the BIP-360 / _Pay-To-Tap-Script-Hash_ (P2MR) workshop !
In this workshop, you will interact with a custom Signet environment to create, fund and spend from a _P2MR_ address.
_P2MR_ is a new Bitcoin address type defined in link:https://bip360.org/bip360.html[bip-360].
In addition, this workshop allows for the (un)locking mechanism of the leaf scripts of your P2MR address to optionally use _Post Quantum Cryptography_ (PQC).
The use of PQC is alluded to in BIP-360 and will be further defined in future BIPs.
The steps outlined in this workshop are executed using a P2MR/PQC enabled Bitcoin Core instance running on a signet environment.
*The target audience of the workshop is Bitcoin developers and ops personnel.
As such, the workshop makes heavy use of the _bitcoin-cli_ at the command line.*
== Pre-reqs
=== *docker / podman*
This workshop environment is provided as a _docker_ container.
Subsequently, ensure your host machine has either link:https://docs.docker.com/desktop/[docker] or link:https://podman.io/docs/installation[podman] installed.
=== *p2mr_demo* docker container
==== Obtain container
Once docker or podman is installed on your machine, you can obtain the workshop docker container via any of the following:
. Pull from _quay.io_ :
+
[source,bash]
-----
sudo docker pull quay.io/jbride2000/p2mr_demo:0.1
-----
+
NOTE: The container image is 1.76GB in size. This approach may be slow depending on network bandwidth.
. Download container image archive file from local HTTP server:
+
*TO_DO*
. Obtain container image archive file from instructor:
.. Workshop instructors have the container image available via USB thumb drives.
If you feel comfortable with this approach, ask an instructor for a thumb drive.
... Mount the USB thumb drive and copy for the file called: _p2mr_demo-image.tar_.
... Load the container image into your docker environment as per the following:
+
[source,bash]
-----
docker load -i /path/to/p2mr_demo-image.tar
-----
==== Start container
You will need to start the workshop container using the docker infrastructure on your machine.
. If working at the command line, the following is an example to run the container and obtain a command prompt:
+
[source,bash]
-----
sudo docker run -it --rm --entrypoint /bin/bash --network host \
-e RPC_CONNECT=10.21.3.194 \
quay.io/jbride2000/p2mr_demo:0.1
-----
. You should see a _bash_ shell command prompt similar to the following:
+
-----
bip360@0aa9edf3d201:~/bips/bip-0360/ref-impl/rust$ ls
Cargo.lock Cargo.toml README.md docs examples src tests
-----
+
As per the `ls` command seen above, your command prompt path defaults to the link:https://github.com/jbride/bips/tree/p2mr/bip-0360/ref-impl/rust[Rust based reference implementation] for BIP-360.
==== Container contents
Your docker environment already includes a P2MR/PQC enabled `bitcoin-cli` utility.
In addition, an alias to this custom bitcoin-cli utility configured for the signet workshop environment has also been provided.
. You can view this alias as follows (execute all commands within workshop container image):
+
[source,bash]
-----
declare -f b-cli
-----
+
You should see a response similar to the following:
+
-----
b-cli ()
{
/usr/local/bin/bitcoin-cli -rpcconnect=${RPC_CONNECT:-192.168.122.1} -rpcport=${RPC_PORT:-18443} -rpcuser=${RPC_USER:-signet} -rpcpassword=${RPC_PASSWORD:-signet} "$@"
}
-----
. Test interaction between your _b-cli_ utility and the workshop's signet node via the following:
+
[source,bash]
-----
b-cli getnetworkinfo
-----
+
[source,bash]
-----
b-cli getblockcount
-----
. In addition, your docker environment also comes pre-installed with the following utilities needed for this workshop:
. *jq*: json parsing utility
. *awk*
. *Rust* development environment with _cargo_ utility
== Bitcoin Environment
Your workshop instructors have provided you with a _P2MR/PQC_ enabled Bitcoin environment running in _signet_.
You will send RPC commands to this custom Bitcoin node via the _b-cli_of your docker container.
image::images/workshop_deployment_arch.png[]
Via your browser, you will interact with the P2MR enabled _mempool.space_ for the workshop at: link:http://signet.bip360.org[signet.bip360.org].
== Create & Fund P2MR Address
The purpose of this workshop is to demonstrate construction and spending of a link:https://github.com/cryptoquick/bips/blob/p2qrh/bip-0360.mediawiki[bip-360] _P2MR_ address (optionally using _Post-Quantum Cryptography_).
In this section of the workshop, you create and fund a P2MR address.
The following depicts the construction of a P2MR _TapTree_ and computation its _scriptPubKey_.
image::images/p2mr_construction.png[]
A P2MR address is created by adding locking scripts to leaves of a _TapTree_.
The locking scripts can use either _Schnorr_ (as per BIP-360) or _SLH-DSA_ (defined in a future BIP) cryptography.
. Define number of total leaves in tap tree :
+
[source,bash]
-----
export TOTAL_LEAF_COUNT=5
-----
. In your container image, indicate what type of cryptography to use in the locking scripts of your TapTree leaves.
Valid options are: `MIXED`, `SLH_DSA_ONLY`, `SCHNORR_ONLY`, `CONCATENATED_SCHNORR_AND_SLH_DSA`.
Default is `MIXED`.
+
[source,bash]
-----
export TAP_TREE_LOCK_TYPE=MIXED
-----
.. If you set _TAP_TREE_LOCK_TYPE=SCHNORR_ONLY_, then the locking script of your TapTree leaves will utilize _Schnorr_ cryptography.
+
Schnorr is not quantum-resistant. However, its signature size is relatively small: 64 bytes.
A _SCHNORR_ONLY_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_schnorr_only.png[s,300]
.. If you set _TAP_TREE_LOCK_TYPE=SLH_DSA_ONLY_, then the locking script of your TapTree leaves will utilize _SLH-DSA_ cryptography.
A _SLH_DSA_ONLY_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_slh_dsa_only.png[l,300]
+
SLH_DSA is quantum-resistant. However, the trade-off is the much larger signature size 7,856 bytes when spending.
+
image::images/crypto_key_characteristics.png[]
+
NOTE: PQC cryptography is made available to this BIP-360 reference implementation via the link:https://crates.io/crates/bitcoinpqc[libbitcoinpqc Rust bindings].
.. If you set _MIXED_, then each leaf of the taptree will consist of *either* a Schnorr based locking script or a SLH-DSA based locking script.
A _MIXED_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_mixed.png[t,300]
+
NOTE: The benefit of constructing a taptree with a mixed set of cryptography used as locking scripts in the leaves is articulated nicely in link:https://www.bitmex.com/blog/Taproot%20Quantum%20Spend%20Paths[this article from BitMex].
.. If you set _TAP_TREE_LOCK_TYPE=CONCATENATED_SCHNORR_AND_SLH_DSA_, then the locking script of your TapTree leaves will be secured using both SCHNORR and SLH-DSA cryptography in a concatenated / serial manner.
Private keys for both SCHNORR and SLH-DSA will be needed when unlocking.
A _CONCATENATED_SCHNORR_AND_SLH_DSA_ tap tree with 5 leaves (aka: TOTAL_LEAF_COUNT) could be represented as follows:
+
image::images/tap_tree_concatenated.png[p,300]
. Set the tap leaf index to later use as the unlocking script (when spending) For example, to later spend from the 5th leaf of the tap tree:
+
[source,bash]
-----
export LEAF_TO_SPEND_FROM=4
-----
. Generate a P2MR scripPubKey with multi-leaf taptree:
+
[source,bash]
-----
export BITCOIN_ADDRESS_INFO=$( cargo run --example p2mr_construction ) \
&& echo $BITCOIN_ADDRESS_INFO | jq -r .
-----
+
NOTE: In signet, you can expect a P2MR address that starts with the following prefix: `tb1z` .
+
[subs=+quotes]
++++
What just happened?
The Rust based reference implementation for BIP-0360 is leveraged to construct a transaction with a P2MR UTXO as follows:
A configurable number of leaves are generated each with their own locking script.
Each of these leaves are added to a Huffman tree that sorts the leaves by weight.
The merkle root of the tree is calculated and subsequently used to generate the P2MR witness program and BIP0350 address.
++++
+
The source code for the above logic is found in this project's source file: link:../src/lib.rs[src/lib.rs]
. Only if you previously set `TAP_TREE_LOCK_TYPE=MIXED`, set the environment variable `SPENDING_LEAF_TYPE`. Valid values are `SHNORR_ONLY` or `SLH_DSA_ONLY` based on the type of locking script that was used in the leaf you will spend from later in this lab. The logs from the previous step tell you the appropriate value to set. For instance:
+
-----
NOTE: TAP_TREE_LOCK_TYPE=MIXED requires setting SPENDING_LEAF_TYPE when spending (based on leaf_script_type in output above) as follows:
export SPENDING_LEAF_TYPE=SCHNORR_ONLY
-----
. Fund this P2MR address using workshop's signet faucet
.. In a browser tab, navigate to: link:http://faucet.bip360.org/[faucet.bip360.org].
.. Copy-n-paste the value of `bech32m_address` (found in the json response from the previous step)
+
image::images/faucet_1.png[]
+
Press the `Request` button.
.. The faucet should allocate bitcoin to your address.
+
image::images/faucet_2.png[]
.. Click on the link of your transaction id.
This will take you a detailed view of the transaction.
Scroll down to the the _Inputs & Outputs_ section of the transaction and identify the _vout_ index of funds sent to your _P2MR_ address.
+
image::images/funding_utxo_id.png[]
.. Return back to your terminal and set a _FUNDING_UTXO_INDEX_ environment variable (used later to correctly identify funding UTXO when generating the spending tx)
+
[source,bash]
-----
export FUNDING_UTXO_INDEX=
-----
.. Return back to your browser tab at navigate to: link:https://signet.bip360.org[signet.bip360.org] and wait until a new block mines the transaction from the faucet that funded your P2MR address.
+
image::images/mempool_next_block.png[]
. Set some env vars (for use in later steps in this workshop) based on previous json result:
+
[source,bash]
-----
export MERKLE_ROOT=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.tree_root_hex' ) \
&& export LEAF_SCRIPT_PRIV_KEYS_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_priv_keys_hex' ) \
&& export LEAF_SCRIPT_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_hex' ) \
&& export CONTROL_BLOCK_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.control_block_hex' ) \
&& export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.script_pubkey_hex' ) \
&& export P2MR_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.bech32m_address' )
-----
. View tapscript used in target leaf of taptree:
+
[source,bash]
-----
b-cli decodescript $LEAF_SCRIPT_HEX | jq -r '.asm'
-----
+
NOTE: If not using Schnorr crypto, this script commits to a Schnorr 32-byte x-only public key.
If using SLH_DSA, this script commits to a 32-byte SLH-DSA pub key and a OP_SUCCESS127 (represented as `OP_SUBSTR`) opcode.,
If using SCHNORR + SLH_DSA, then you should see a locking script in the leaf similar to the following:
+
-----
886fc1edb7a8a364da65aef57343de451c1449d8a6c5b766fe150667d50d3e80 OP_CHECKSIG 479f93fbd251863c3e3e72da6e26ea82f87313da13090de10e57eca1f8b5e0f3 OP_SUBSTR OP_BOOLAND OP_VERIFY
-----
. view summary of all txs that have funded P2MR address
+
[source,bash]
-----
export P2MR_DESC=$( b-cli getdescriptorinfo "addr($P2MR_ADDR)" | jq -r '.descriptor' ) \
&& echo $P2MR_DESC \
&& b-cli scantxoutset start '[{"desc": "'''$P2MR_DESC'''"}]'
-----
+
NOTE: You will likely have to wait a few minutes until a new block (containing the tx that funds your P2MR address) is mined.
. grab txid of first tx with unspent funds:
+
[source,bash]
-----
export FUNDING_TX_ID=$( b-cli scantxoutset start '[{"desc": "'''$P2MR_DESC'''"}]' | jq -r '.unspents[0].txid' ) \
&& echo $FUNDING_TX_ID
-----
. view details of funding UTXO to the P2MR address:
+
[source,bash]
-----
export FUNDING_UTXO=$( b-cli getrawtransaction $FUNDING_TX_ID 1 | jq -r '.vout['''$FUNDING_UTXO_INDEX''']' ) \
&& echo $FUNDING_UTXO | jq -r .
-----
== Spend P2MR UTXO
In the previous section, you created and funded a P2MR UTXO.
That UTXO includes a leaf script locked with a key-pair (optionally based on PQC) known to you.
In this section, you spend from that P2MR UTXO.
Specifically, you will generate an appropriate _SigHash_ and sign it (to create a signature) using the known private key that unlocks the known leaf script of the P2MR UTXO.
The target address type that you send funds to is: P2WPKH.
. Determine value (in sats) of the funding P2MR utxo:
+
[source,bash]
-----
export FUNDING_UTXO_AMOUNT_SATS=$(echo $FUNDING_UTXO | jq -r '.value' | awk '{printf "%.0f", $1 * 100000000}') \
&& echo $FUNDING_UTXO_AMOUNT_SATS
-----
. Referencing the funding tx (via $FUNDING_TX_ID and $FUNDING_UTXO_INDEX), create the spending tx:
+
[source,bash]
-----
export SPEND_DETAILS=$( cargo run --example p2mr_spend )
-----
+
[subs=+quotes]
++++
What just happened?
The Rust based reference implementation for BIP-0360 is leveraged to construct a transaction that spends from the P2MR UTXO as follows:
Create a transaction template (aka: SigHash) that serves as the message to be signed.
Using the known private key and the SigHash, create a signature that is capable of unlocking one of the leaf scripts of the P2MR tree.
Add this signature to the witness section of the transaction.
++++
+
The source code for the above logic is found in this project's source file: link:../src/lib.rs[src/lib.rs]
. Set environment variables passed to _bitcoin-cli_ when spending:
+
[source,bash]
-----
export RAW_P2MR_SPEND_TX=$( echo $SPEND_DETAILS | jq -r '.tx_hex' ) \
&& echo "RAW_P2MR_SPEND_TX = $RAW_P2MR_SPEND_TX" \
&& export SIG_HASH=$( echo $SPEND_DETAILS | jq -r '.sighash' ) \
&& echo "SIG_HASH = $SIG_HASH" \
&& export SIG_BYTES=$( echo $SPEND_DETAILS | jq -r '.sig_bytes' ) \
&& echo "SIG_BYTES = $SIG_BYTES"
-----
. Inspect the spending tx:
+
[source,bash]
-----
b-cli decoderawtransaction $RAW_P2MR_SPEND_TX
-----
+
Pay particular attention to the `vin.txinwitness` field.
The following depicts the elements of a P2MR witness stack.
+
image::images/p2mr_witness.png[]
+
Do the three elements (script input, script and control block) of the witness stack for this _script path spend_ correspond ?
What do you observe as the first byte of the `control block` element ?
. Test standardness of the spending tx by sending to local mempool of P2MR enabled Bitcoin Core:
+
[source,bash]
-----
b-cli testmempoolaccept '["'''$RAW_P2MR_SPEND_TX'''"]'
-----
. Submit tx:
+
[source,bash]
-----
export P2MR_SPENDING_TX_ID=$( b-cli sendrawtransaction $RAW_P2MR_SPEND_TX ) \
&& echo $P2MR_SPENDING_TX_ID
-----
+
NOTE: Should return same tx id as was included in $RAW_P2MR_SPEND_TX
== Mine P2MR Spend TX
. View tx in mempool:
+
[source,bash]
-----
b-cli getrawtransaction $P2MR_SPENDING_TX_ID 1
-----
+
NOTE: There will not yet be a field `blockhash` in the response.
. Monitor the mempool.space instance at link:http://signet.bip360.org[signet.bip360.org] until a new block is mined.
. While still in the mempool.space instance at link:http://signet.bip360.org[signet.bip360.org], lookup your tx (denoted by: $P2MR_SPENDING_TX_ID ) in the top-right search bar:
+
image::images/mempool_spending_tx_1.png[]
+
Click on the `Details` button at the top-right of the `Inputs & Outputs` section.
.. Study the elements of the `Witness. Approximately how large is each element of the witness stack?
.. View the values of the `Previous output script` and `Previous output type` fields:
+
image::images/mempool_spending_tx_2.png[]
. Obtain `blockhash` field of mined tx:
+
[source,bash]
-----
export BLOCK_HASH=$( b-cli getrawtransaction $P2MR_SPENDING_TX_ID 1 | jq -r '.blockhash' ) \
&& echo $BLOCK_HASH
-----
. View txs in block:
+
[source,bash]
-----
b-cli getblock $BLOCK_HASH | jq -r .tx
-----
+
You should see your tx (as per $P2MR_SPENDING_TX_ID) in the list.
+
Congratulations!! You have created, funded and spent from a P2MR address.
== Appendix
[[build_p2mr]]
=== Build P2MR / PQC Enabled Bitcoin Core
*FOR THE PURPOSE OF THE WORKSHOP, YOU CAN IGNORE THIS SECTION*
The link:https://github.com/jbride/bitcoin/tree/p2mr[p2mr branch] of bitcoin core is needed.
Build instructions for the `p2mr` branch are the same as `master` and is documented link:https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md[here].
As such, the following is an example series of steps (on a Fedora 42 host) to compile and run the `p2mr` branch of bitcoin core:
. Set BITCOIN_SOURCE_DIR
+
-----
export BITCOIN_SOURCE_DIR=/path/to/root/dir/of/cloned/bitcoin/source
-----
. build
+
-----
cmake -B build \
-DWITH_ZMQ=ON \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_BENCH=ON \
-DBUILD_DAEMON=ON \
-DSANITIZERS=address,undefined
cmake --build build -j$(nproc)
-----
. run bitcoind in signet mode:
+
-----
./build/bin/bitcoind -daemon=0 -signet=1 -txindex -prune=0
-----
+
NOTE: If running in `signet`, your bitcoin core will need to be configured with the `signetchallenge` property.
link:https://edil.com.br/blog/creating-a-custom-bitcoin-signet[This workshop] provides a nice overview of the topic.
=== libbitcoinpqc Rust bindings
*FOR THE PURPOSE OF THE WORKSHOP, YOU CAN IGNORE THIS SECTION*
The `p2mr-pqc` branch of this project includes a dependency on the link:https://crates.io/crates/libbitcoinpqc[libbitcoinpqc crate].
libbitcoinpqc contains native code (C/C++/ASM) and is made available to Rust projects via Rust bindings.
This C/C++/ASM code is provided in the libbitcoinpqc crate as source code (not prebuilt binaries).
Subsequently, the `Cargo` utility needs to build this libbitcoinpqc C native code on your local machine.
You will need to have C development related libraries installed on your local machine.
Every developer or CI machine building `p2mr-ref` must have cmake and a C toolchain installed locally.
==== Linux
. Debian / Ubuntu
+
-----
sudo apt update
sudo apt install cmake build-essential clang libclang-dev
-----
. Fedora / RHEL
+
-----
sudo dnf5 update
sudo dnf5 install cmake make gcc gcc-c++ clang clang-libs llvm-devel
-----
================================================
FILE: bip-0360/ref-impl/rust/docs/p2tr-end-to-end.adoc
================================================
:scrollbar:
:data-uri:
:toc2:
:linkattrs:
= P2TR End-to-End Tutorial
:numbered:
This tutorial is inspired from the link:https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature[script-path-spend-signature] example of the _learnmeabitcoin_ tutorial.
It is customized to create, fund and spend from a P2TR UTXO to a P2WPKH address.
Execute in Bitcoin Core `regtest` mode.
== Pre-reqs
=== Bitcoin Core
The link:https://github.com/jbride/bitcoin/tree/p2mr-pqc[p2mr branch] of bitcoin core is needed.
Build instructions for the `p2mr` branch are the same as `master` and is documented link:https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md[here].
As such, the following is an example series of steps (on a Fedora 42 host) to compile and run the `p2mr` branch of bitcoin core:
. build
+
-----
$ cmake -B build \
-DWITH_ZMQ=ON \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_BENCH=ON \
-DSANITIZERS=address,undefined
$ cmake --build build -j$(nproc)
-----
. run in `regtest` mode
+
-----
$ ./build/bin/bitcoind -daemon=0 -regtest=1 -txindex
-----
=== Shell Environment
. *b-reg* command line alias:
+
Configure an alias to the `bitcoin-cli` command that connects to your customized bitcoin-core node running in `regtest` mode.
. *jq*: ensure json parsing utility is installed and available via your $PATH.
. *awk* : standard utility for all Linux distros (often packaged as `gawk`).
=== Bitcoin Core Wallet
This tutorial assumes that a bitcoin core wallet is available.
For example, the following would be sufficient:
-----
$ export W_NAME=regtest \
&& export WPASS=regtest
$ b-reg -named createwallet \
wallet_name=$W_NAME \
descriptors=true \
passphrase="$WPASS" \
load_on_startup=true
-----
== Fund P2TR UTXO
. OPTIONAL: Define number of leaves in tap tree as well as the tap leaf to later use as the unlocking script:
+
-----
$ export TOTAL_LEAF_COUNT=5 \
&& export LEAF_TO_SPEND_FROM=4
-----
+
NOTE: Defaults are 4 leaves with the first leaf (leaf 0 ) as the script to later use as the unlocking script.
. Generate a P2TR scripPubKey with multi-leaf taptree:
+
-----
$ export BITCOIN_NETWORK=regtest \
&& export BITCOIN_ADDRESS_INFO=$( cargo run --example p2tr_construction ) \
&& echo $BITCOIN_ADDRESS_INFO | jq -r .
-----
+
NOTE: In `regtest`, you can expect a P2TR address that starts with: `bcrt1q` .
+
NOTE: In the context of P2TR, the _tree_root_hex_ from the response is in reference to the _merkle_root_ used in this tutorial.
. Set some env vars (for use in later steps in this tutorial) based on previous result:
+
-----
$ export MERKLE_ROOT=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.tree_root_hex' ) \
&& export LEAF_SCRIPT_PRIV_KEYS_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_priv_keys_hex' ) \
&& export LEAF_SCRIPT_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_hex' ) \
&& export CONTROL_BLOCK_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.control_block_hex' ) \
&& export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.script_pubkey_hex' ) \
&& export P2TR_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.bech32m_address' )
-----
. View tapscript used in target leaf of taptree:
+
-----
$ b-reg decodescript $LEAF_SCRIPT_HEX | jq -r '.asm'
-----
+
NOTE: Notice that this script commits to a Schnorr 32-byte x-only public key.
. fund this P2TR address with the coinbase reward of a newly generated block:
+
-----
$ export COINBASE_REWARD_TX_ID=$( b-reg -named generatetoaddress 1 $P2TR_ADDR 5 | jq -r '.[]' ) \
&& echo $COINBASE_REWARD_TX_ID
-----
+
NOTE: Sometimes Bitcoin Core may not hit a block (even on regtest). If so, just try the above command again.
. view summary of all txs that have funded P2TR address
+
-----
$ export P2TR_DESC=$( b-reg getdescriptorinfo "addr($P2TR_ADDR)" | jq -r '.descriptor' ) \
&& echo $P2TR_DESC \
&& b-reg scantxoutset start '[{"desc": "'''$P2TR_DESC'''"}]'
-----
. grab txid of first tx with unspent funds:
+
-----
$ export FUNDING_TX_ID=$( b-reg scantxoutset start '[{"desc": "'''$P2TR_DESC'''"}]' | jq -r '.unspents[0].txid' ) \
&& echo $FUNDING_TX_ID
-----
. Set FUNDING_UTXO_INDEX env var (used later to correctly identify funding UTXO when generating the spending tx)
+
-----
$ export FUNDING_UTXO_INDEX=0
-----
. view details of funding UTXO to the P2TR address:
+
-----
$ export FUNDING_UTXO=$( b-reg getrawtransaction $FUNDING_TX_ID 1 | jq -r '.vout['''$FUNDING_UTXO_INDEX''']' ) \
&& echo $FUNDING_UTXO | jq -r .
-----
+
NOTE: the above only works when Bitcoin Core is started with the following arg: -txindex
== Spend P2TR UTXO
. Determine value (in sats) of funding utxo:
+
-----
$ export FUNDING_UTXO_AMOUNT_SATS=$(echo $FUNDING_UTXO | jq -r '.value' | awk '{printf "%.0f", $1 * 100000000}') \
&& echo $FUNDING_UTXO_AMOUNT_SATS
-----
. Generate additional blocks.
+
This is necessary if you have only previously generated less than 100 blocks.
+
-----
$ b-reg -generate 110
-----
+
Otherwise, you may see an error from bitcoin core such as the following when attempting to spend:
+
_bad-txns-premature-spend-of-coinbase, tried to spend coinbase at depth 1_
. Referencing the funding tx (via $FUNDING_TX_ID and $FUNDING_UTXO_INDEX), create the spending tx:
+
-----
$ export SPEND_DETAILS=$( cargo run --example p2tr_spend )
$ export RAW_P2TR_SPEND_TX=$( echo $SPEND_DETAILS | jq -r '.tx_hex' ) \
&& echo "RAW_P2TR_SPEND_TX = $RAW_P2TR_SPEND_TX" \
&& export SIG_HASH=$( echo $SPEND_DETAILS | jq -r '.sighash' ) \
&& echo "SIG_HASH = $SIG_HASH" \
&& export SIG_BYTES=$( echo $SPEND_DETAILS | jq -r '.sig_bytes' ) \
&& echo "SIG_BYTES = $SIG_BYTES"
-----
. Inspect the spending tx:
+
-----
$ b-reg decoderawtransaction $RAW_P2TR_SPEND_TX
-----
. Test standardness of the spending tx by sending to local mempool of p2tr enabled Bitcoin Core:
-----
$ b-reg testmempoolaccept '["'''$RAW_P2TR_SPEND_TX'''"]'
-----
. Submit tx:
+
-----
$ export P2TR_SPENDING_TX_ID=$( b-reg sendrawtransaction $RAW_P2TR_SPEND_TX ) \
&& echo $P2TR_SPENDING_TX_ID
-----
+
NOTE: Should return same tx id as was included in $RAW_P2TR_SPEND_TX
== Mine P2TR Spend TX
. View tx in mempool:
+
-----
$ b-reg getrawtransaction $P2TR_SPENDING_TX_ID 1
-----
+
NOTE: There will not yet be a field `blockhash` in the response.
. Mine 1 block:
+
-----
$ b-reg -generate 1
-----
. Obtain `blockhash` field of mined tx:
+
-----
$ export BLOCK_HASH=$( b-reg getrawtransaction $P2TR_SPENDING_TX_ID 1 | jq -r '.blockhash' ) \
&& echo $BLOCK_HASH
-----
. View tx in block:
+
-----
$ b-reg getblock $BLOCK_HASH | jq -r .tx
-----
== TO-DO
================================================
FILE: bip-0360/ref-impl/rust/docs/quantum_root_tap_tree.txt
================================================
┌───────────────────────┐
│ tapleaf Merkle root │
│ │
└───────────────────────┘
|
┌───────────────────────┐
│ 5 tagged_hash │
│ QuantumRoot │
└───────────|───────────┘
┌───────────|───────────┐
┌───────────────────────────────►│ 4 tagged_hash ◄─────────────────────┐
│ │ TapBranch │ │
│ └───────────────────────┘ │
│ │
│ │
│ │
│ │
│ │
│ ┌─────────────┼───────────┐
│ │ 3 tagged_hash │
│ ┌──►│ TapBranch ◄───────┐
│ │ └─────────────────────────┘ │
│ │ │
│ │ │
┌───────────┼────────────┐ ┌───────┼────────┐ │
┌─────►│ 2 tagged_hash ◄────┐ ┌─────►│ 2 tagged_hash ◄────┐ │
│ │ TapBranch │ │ │ │ TapBranch │ │ │
│ └────────────────────────┘ │ │ └────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────┼────────┐ ┌───────|───-─┐ ┌──────┴──────┐
┌───┼──────────┐ ┌──────────┼──┐ │ 1 tagged_hash│ │1 tagged_hash│ │1 tagged_hash│
│1 tagged_hash │ │1 tagged_hash│ │ Tapleaf │ │ Tapleaf │ │ Tapleaf │
│ Tapleaf │ │ Tapleaf │ └──────────────┘ └─────────────┘ └─────────────┘
└──▲───────────┘ └──────▲──────┘ ▲ ▲ ▲
│ │ │ │ │
version | A script version | B script version | C script version | D script version|E script
================================================
FILE: bip-0360/ref-impl/rust/docs/stack_element_size_performance_tests.adoc
================================================
:scrollbar:
:data-uri:
:toc2:
:linkattrs:
= Stack Element Size Performance Tests
:numbered:
== Overview
BIP-0360 proposes an increase in stack element size from current 520 bytes (v0.29) to 8kb.
Subsequently, there is a need to determine the performance and stability related consequences of doing so.
== Regression Tests
The following regression tests failed with `MAX_SCRIPT_ELEMENT_SIZE` set to 8000 .
[cols="1,1,2"]
|===
|feature_taproot.py | line 1338 | Missing error message 'Push value size limit exceeded' from block response 'mandatory-script-verify-flag-failed (Stack size must be exactly one after execution)'
|p2p_filter.py | lines 130-132 | Check that too large data element to add to the filter is rejected
|p2p_segwit.py | lines 1047-1049 | mandatory-script-verify-flag-failed (Push value size limit exceeded)
|rpc_createmultisig.py | lines 75-75 | No exception raised: redeemScript exceeds size limit: 684 > 520"
|===
**Analysis**
These 4 tests explicitly test for a stack element size of 520 and are expected to fail with a stack element size of 8Kb.
Subsequently, no further action needed.
== Performance Tests
=== OP_SHA256
The following Bitcoin script is used to conduct this performance test:
-----
OP_SHA256 OP_DROP OP_1
-----
When executed, this script adds the pre-image array of arbitrary data to the stack.
Immediately after, a SHA256 hash function pops the pre-image array off the stack, executes a hash and adds the result to the top of the stack.
The `OP_DROP` operation removes the hash result from the stack.
==== Results Summary
[cols="3,1,1,1,1,1,1,1,1,1", options="header"]
|===
| Stack Element Size (Bytes) | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op |miss% | total
| 1 | 637.28 | 1,569,165.30 | 0.3% | 8,736.00 | 1,338.55 | 6.526 | 832.00 | 0.0% | 5.53
| 64 | 794.85 | 1,258,098.46 | 0.4% | 11,107.00 | 1,666.92 | 6.663 | 827.00 | 0.0% | 5.61
| 65 | 831.95 | 1,201,996.30 | 0.5% | 11,144.00 | 1,698.26 | 6.562 | 841.00 | 0.0% | 5.53
| 100 | 794.82 | 1,258,139.86 | 0.2% | 11,139.00 | 1,673.89 | 6.655 | 837.00 | 0.0% | 5.50
| 520 | 1,946.67 | 513,697.88 | 0.2% | 27,681.00 | 4,095.57 | 6.759 | 885.00 | 0.0% | 5.50
| 8000 | 20,958.63 | 47,713.05 | 2.7% | 304,137.02 | 43,789.86 | 6.945 | 1,689.02 | 0.4% | 5.63
|===
**Analysis**
The following observations are made from the performance test:
. **Performance Scaling**: The increase from 520 bytes to 8000 bytes (15.4x size increase) results in approximately 9.8x performance degradation (19,173 ns/op vs 1,947 ns/op).
This represents sub-linear scaling, which suggests the implementation handles large data efficiently.
. **Instruction Count Scaling**: Instructions per operation increase from 27,681 to 285,220 (10.3x increase), closely matching the performance degradation, indicating the bottleneck is primarily computational rather than memory bandwidth.
. **Throughput Impact**: Operations per second decrease from 513,698 op/s to 52,158 op/s, representing a 9.8x reduction in throughput.
. **Cache Efficiency**: The IPC (Instructions Per Cycle) remains relatively stable (6.759 to 7.094), suggesting good CPU pipeline utilization despite the increased data size.
. **Memory Access Patterns**: The branch mis-prediction rate increases slightly (0.0% to 0.4%), indicating minimal impact on branch prediction accuracy.
**key**
[cols="1,6", options="header"]
|===
| Metric | Description
| ns/op | Nanoseconds per operation - average time it takes to complete one benchmark iteration
| op/s | Operations per second - throughput rate showing how many benchmark iterations can be completed per second
| err% | Error percentage - statistical margin of error in the measurement, indicating the reliability of the benchmark results
| ins/op | Instructions per operation - the number of CPU instructions executed for each benchmark iteration
| cyc/op | CPU cycles per operation - the number of CPU clock cycles consumed for each benchmark iteration
| IPC | Instructions per cycle - the ratio of instructions executed per CPU cycle, indicating CPU efficiency and pipeline utilization
| bra/op | Branches per operation - the number of conditional branch instructions executed for each benchmark iteration
| miss% | Branch misprediction percentage - the rate at which the CPU incorrectly predicts branch outcomes, causing pipeline stalls
| total | Total benchmark time - the total wall-clock time spent running the entire benchmark in seconds
|===
==== Detailed Results
===== Stack Element Size = 1 Byte
[cols="2,1,1,1,1,1,1,1,1", options="header"]
|===
|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op |miss% |total
|637.28 |1,569,165.30 |0.3% |8,736.00 |1,338.55 |6.526 |832.00 |0.0% |5.53
|===
===== Stack Element Size = 64 Bytes
[cols="2,1,1,1,1,1,1,1,1", options="header"]
|===
| ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total
| 794.85 | 1,258,098.46 | 0.4% | 11,107.00 | 1,666.92 | 6.663 | 827.00 | 0.0% | 5.61
|===
====== Explanation
Even though 64 bytes doesn't require padding (it's exactly one SHA256 block), the ins/op still increases from 8,736 to 11,107 instructions. Here's why:
. Data Movement Overhead
* 1 byte: Minimal data to copy into the SHA256 processing buffer
* 64 bytes: 64x more data to move from the witness stack into the SHA256 input buffer
* Memory copying operations add instructions
. SHA256 State Initialization
* 1 byte: The 1-byte input gets padded to 64 bytes internally, but the padding is mostly zeros
* 64 bytes: All 64 bytes are actual data that needs to be processed
* The SHA256 algorithm may have different code paths for handling "real" data vs padded data
. Memory Access Patterns
* 1 byte: Single byte access, likely cache-friendly
* 64 bytes: Sequential access to 64 bytes, potentially different memory access patterns
* May trigger different CPU optimizations or cache behavior
. Bit Length Processing
* 1 byte: The SHA256 algorithm needs to set the bit length field (8 bits)
* 64 bytes: The bit length field is 512 bits
* Different bit length values may cause different code paths in the SHA256 implementation
. Loop Unrolling and Optimization
* 1 byte: Compiler might optimize the single-block case differently
* 64 bytes: May use different loop structures or optimization strategies
* The SHA256 implementation might have specialized code paths for different input sizes
. Witness Stack Operations
* 1 byte: Small witness element, minimal stack manipulation
* 64 bytes: Larger witness element, more complex stack operations
* The Bitcoin script interpreter has to handle larger data on the stack
The increase from 8,736 to 11,107 instructions (~27% increase) suggests that even without padding overhead, the additional data movement and processing of "real" data vs padded data adds significant instruction count.
This is a good example of how seemingly small changes in input size can affect the underlying implementation's code paths and optimization strategies.
===== Stack Element Size = 65 Bytes
1 byte more than the SHA256 _block_ size
[cols="2,1,1,1,1,1,1,1,1", options="header"]
|===
|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op | miss% | total
| 831.95 | 1,201,996.30 |0.5% |11,144.00 |1,698.26 | 6.562 |841.00 | 0.0% | 5.53
|===
===== Stack Element Size = 100 Bytes
[cols="2,1,1,1,1,1,1,1,1", options="header"]
|===
|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op | miss% | total
| 794.82 | 1,258,139.86 | 0.2% | 11,139.00 | 1,673.89 | 6.655 | 837.00 | 0.0% | 5.50
|===
===== Stack Element Size = 520 Bytes
[cols="2,1,1,1,1,1,1,1,1", options="header"]
|===
|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op | miss% | total
| 1,946.67 | 513,697.88 | 0.2% | 27,681.00 | 4,095.57 | 6.759 | 885.00 | 0.0% | 5.50
|===
===== Stack Element Size = 8000 Bytes
[cols="2,1,1,1,1,1,1,1,1", options="header"]
|===
|ns/op |op/s |err% |ins/op |cyc/op |IPC |bra/op | miss% | total
| 20,958.63 | 47,713.05 | 2.7% | 304,137.02 | 43,789.86 | 6.945 | 1,689.02 | 0.4% | 5.63
|===
=== OP_DUP OP_SHA256
NOTE: This test is likely irrelevant as per latest BIP-0360: _To prevent OP_DUP from creating an 8 MB stack by duplicating stack elements larger than 520 bytes we define OP_DUP to fail on stack elements larger than 520 bytes_.
This test builds off the previous (involving the hashing of large stack element data) by duplicating that stack element data.
The following Bitcoin script is used to conduct this performance test:
-----
OP_DUP OP_SHA256 OP_DROP OP_1
-----
When executed, this script adds the pre-image array of arbitrary data to the stack.
Immediately after, a `OP_DUP` operation duplicates the pre-image array on the stack.
Then, a SHA256 hash function pops the pre-image array off the stack, executes a hash and adds the result to the top of the stack.
The `OP_DROP` operation removes the hash result from the stack.
==== Results Summary
[cols="3,1,1,1,1,1,1,1,1,1", options="header"]
|===
| Stack Element Size (Bytes) | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op |miss% | total
| 1 | 714.83 | 1,398,937.33 | 0.7% | 9,548.00 | 1,488.22 | 6.416 | 1,012.00 | 0.0% | 5.57
| 64 | 858.44 | 1,164,905.19 | 0.4% | 11,911.00 | 1,800.87 | 6.614 | 999.00 | 0.0% | 5.11
| 65 | 868.40 | 1,151,539.31 | 0.8% | 11,968.00 | 1,814.31 | 6.596 | 1,019.00 | 0.0% | 5.56
| 100 | 864.33 | 1,156,966.91 | 0.4% | 11,963.00 | 1,809.16 | 6.612 | 1,015.00 | 0.0% | 5.49
| 520 | 2,036.64 | 491,005.94 | 0.7% | 28,615.00 | 4,266.27 | 6.707 | 1,073.00 | 0.0% | 5.52
| 8000 | 20,883.10 | 47,885.61 | 0.2% | 306,887.04 | 43,782.35 | 7.009 | 2,089.02 | 0.3% | 5.53
|===
==== Analysis
The following observations are made from the performance test (in comparison to the `OP_SHA256` test):
. OP_DUP Overhead: The OP_DUP operation adds overhead by duplicating the stack element, which requires:
* Memory allocation for the duplicate
* Data copying from the original to the duplicate
* Additional stack manipulation
. Size-Dependent Impact on ns/op:
* For small elements (1-100 bytes): Significant overhead (4.4% to 12.2%)
* For medium elements (520 bytes): Moderate overhead (4.6%)
* For large elements (8000 bytes): Negligible difference (-0.4%)
. Instruction Count Impact:
* 8000 bytes: 304,137 → 306,887 instructions (+2,750 instructions)
* The additional instructions for OP_DUP are relatively small compared to the SHA256 computation
. Memory Operations:
+
The OP_DUP operation primarily affects memory operations rather than computational complexity.
This explains why the impact diminishes with larger data sizes where SHA256 computation dominates the performance.
This analysis shows that the OP_DUP operation has a measurable but manageable performance impact, especially for larger stack elements where the computational overhead of SHA256 dominates the overall execution time.
=== Procedure
* Testing is done using functionality found in the link:https://github.com/jbride/bitcoin/tree/p2mr-pqc[p2mr branch] of Bitcoin Core.
* Compilation of Bitcoin Core is done using the following `cmake` flags:
+
-----
$ cmake \
-B build \
-DWITH_ZMQ=ON \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DBUILD_BENCH=ON
$ cmake --build build -j$(nproc)
-----
* Bench tests are conducted similar to the following :
+
-----
$ export PREIMAGE_SIZE_BYTES=8000
$ ./build/bin/bench_bitcoin --filter=VerifySHA256Bench -min-time=5000
-----
== Failure Analysis
Goals:
* Measure stack memory usage to detect overflows or excessive stack growth.
* Monitor heap memory usage to identify increased allocations or leaks caused by larger elements.
* Detect memory errors (e.g., invalid reads/writes, use-after-free) that might arise from modified stack handling.
* Assess performance impacts (e.g., memory allocation overhead) in critical paths like transaction validation.
=== Memory Errors
AddressSanitizer is a fast, compiler-based tool (available in GCC/Clang) for detecting memory errors with lower overhead than Valgrind.
==== Results
No memory errors or leaks were revealed by AddressSanitizer when running the `OP_SHA256` bench test for 30 minutes.
==== Procedure
AddressSanitizer is included with Clang/LLVM
. Compilation of Bitcoin Core is done using the following `cmake` flags:
+
-----
$ cmake -B build \
-DWITH_ZMQ=ON \
-DBUILD_BENCH=ON \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DSANITIZERS=address,undefined
$ cmake --build build -j$(nproc)
-----
. Check that ASan is statically linked to the _bench_bitcoin_ executable:
+
-----
$ nm build/bin/bench_bitcoin | grep asan | more
0000000000148240 T __asan_address_is_poisoned
00000000000a2fe6 t __asan_check_load_add_16_R13
...
000000000316c828 b _ZZN6__asanL18GlobalsByIndicatorEmE20globals_by_indicator
0000000003170ccc b _ZZN6__asanL7AsanDieEvE9num_calls
-----
. Set the following environment variable:
+
-----
$ export ASAN_OPTIONS="halt_on_error=0:detect_leaks=1:log_path=/tmp/asan_logs/asan"
-----
+
Doing so ensures that _address sanitizer_ :
.. avoids halting on the first error
.. is enable memory leak detection
.. writes ASAN related logs to a specified directory
== Test Environment
* Fedora 42
* 8 cores (Intel(R) Core(TM) i7-8665U CPU @ 1.90GHz)
* 32 GB RAM
* OS settings:
+
-----
$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 126896
max locked memory (kbytes, -l) 8192
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 126896
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
-----
== Notes
. test with different thread stack sizes (ie: ulimit -s xxxx )
================================================
FILE: bip-0360/ref-impl/rust/examples/p2mr-end-to-end.sh
================================================
export BITCOIN_SOURCE_DIR=$HOME/bitcoin
export W_NAME=anduro
export USE_PQC=false
export TOTAL_LEAF_COUNT=5
export LEAF_TO_SPEND_FROM=4
b-cli -named createwallet \
wallet_name=$W_NAME \
descriptors=true \
load_on_startup=true
export BITCOIN_ADDRESS_INFO=$( cargo run --example p2mr_construction ) \
&& echo $BITCOIN_ADDRESS_INFO | jq -r .
export QUANTUM_ROOT=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.tree_root_hex' ) \
&& export LEAF_SCRIPT_PRIV_KEY_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_priv_key_hex' ) \
&& export LEAF_SCRIPT_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.leaf_script_hex' ) \
&& export CONTROL_BLOCK_HEX=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.taptree_return.control_block_hex' ) \
&& export FUNDING_SCRIPT_PUBKEY=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.script_pubkey_hex' ) \
&& export P2MR_ADDR=$( echo $BITCOIN_ADDRESS_INFO | jq -r '.utxo_return.bech32m_address' )
b-cli decodescript $LEAF_SCRIPT_HEX | jq -r '.asm'
export COINBASE_REWARD_TX_ID=$( b-cli -named generatetoaddress 1 $P2MR_ADDR 5 | jq -r '.[]' ) \
&& echo $COINBASE_REWARD_TX_ID
export P2MR_DESC=$( b-cli getdescriptorinfo "addr($P2MR_ADDR)" | jq -r '.descriptor' ) \
&& echo $P2MR_DESC \
&& b-cli scantxoutset start '[{"desc": "'''$P2MR_DESC'''"}]'
================================================
FILE: bip-0360/ref-impl/rust/examples/p2mr_construction.rs
================================================
use p2mr_ref::{create_p2mr_utxo, create_p2mr_multi_leaf_taptree, tap_tree_lock_type};
use p2mr_ref::data_structures::{UtxoReturn, TaptreeReturn, ConstructionReturn, LeafScriptType};
use std::env;
use log::{info, error};
// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
fn main() -> ConstructionReturn {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let tap_tree_lock_type = tap_tree_lock_type();
info!("tap_tree_lock_type: {:?}", tap_tree_lock_type);
let taptree_return: TaptreeReturn = create_p2mr_multi_leaf_taptree();
let p2mr_utxo_return: UtxoReturn = create_p2mr_utxo(taptree_return.clone().tree_root_hex);
// Alert user about SPENDING_LEAF_TYPE requirement when using MIXED mode
if tap_tree_lock_type == LeafScriptType::Mixed {
info!("NOTE: TAP_TREE_LOCK_TYPE=MIXED requires setting SPENDING_LEAF_TYPE when spending (based on leaf_script_type in output above) as follows:");
info!(" export SPENDING_LEAF_TYPE={}", taptree_return.leaf_script_type);
}
return ConstructionReturn {
taptree_return: taptree_return,
utxo_return: p2mr_utxo_return,
};
}
================================================
FILE: bip-0360/ref-impl/rust/examples/p2mr_spend.rs
================================================
use p2mr_ref::{ pay_to_p2wpkh_tx, verify_schnorr_signature_via_bytes, verify_slh_dsa_via_bytes, tap_tree_lock_type };
use p2mr_ref::data_structures::{SpendDetails, LeafScriptType};
use std::env;
use log::{info, error};
// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
fn main() -> SpendDetails {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
// FUNDING_TX_ID environment variable is required
let funding_tx_id: String = env::var("FUNDING_TX_ID")
.unwrap_or_else(|_| {
error!("FUNDING_TX_ID environment variable is required but not set");
std::process::exit(1);
});
let funding_tx_id_bytes: Vec = hex::decode(funding_tx_id.clone()).unwrap();
// FUNDING_UTXO_AMOUNT_SATS environment variable is required
let funding_utxo_amount_sats: u64 = env::var("FUNDING_UTXO_AMOUNT_SATS")
.unwrap_or_else(|_| {
error!("FUNDING_UTXO_AMOUNT_SATS environment variable is required but not set");
std::process::exit(1);
})
.parse::()
.unwrap_or_else(|_| {
error!("FUNDING_UTXO_AMOUNT_SATS must be a valid u64 integer");
std::process::exit(1);
});
// The input index of the funding tx
// Allow override via FUNDING_UTXO_INDEX environment variable
let funding_utxo_index: u32 = env::var("FUNDING_UTXO_INDEX")
.ok()
.and_then(|s| s.parse::().ok())
.unwrap_or(0);
info!("Funding tx id: {}, utxo index: {}", funding_tx_id, funding_utxo_index);
// FUNDING_SCRIPT_PUBKEY environment variable is required
let funding_script_pubkey_bytes: Vec = env::var("FUNDING_SCRIPT_PUBKEY")
.map(|s| hex::decode(s).unwrap())
.unwrap_or_else(|_| {
error!("FUNDING_SCRIPT_PUBKEY environment variable is required but not set");
std::process::exit(1);
});
let control_block_bytes: Vec = env::var("CONTROL_BLOCK_HEX")
.map(|s| hex::decode(s).unwrap())
.unwrap_or_else(|_| {
error!("CONTROL_BLOCK_HEX environment variable is required but not set");
std::process::exit(1);
});
info!("P2MR control block size: {}", control_block_bytes.len());
// TAP_TREE_LOCK_TYPE environment variable is required to determine key structure
let leaf_script_type: LeafScriptType = tap_tree_lock_type();
info!("leaf_script_type: {:?}", leaf_script_type);
// For Mixed trees, we need to determine the actual leaf type via SPENDING_LEAF_TYPE
let effective_leaf_type: LeafScriptType = if leaf_script_type == LeafScriptType::Mixed {
match env::var("SPENDING_LEAF_TYPE") {
Ok(value) => match value.as_str() {
"SCHNORR_ONLY" => {
info!("SPENDING_LEAF_TYPE: SCHNORR_ONLY");
LeafScriptType::SchnorrOnly
},
"SLH_DSA_ONLY" => {
info!("SPENDING_LEAF_TYPE: SLH_DSA_ONLY");
LeafScriptType::SlhDsaOnly
},
_ => {
error!("Invalid SPENDING_LEAF_TYPE '{}'. Must be SCHNORR_ONLY or SLH_DSA_ONLY", value);
std::process::exit(1);
}
},
Err(_) => {
error!("SPENDING_LEAF_TYPE environment variable is required when TAP_TREE_LOCK_TYPE=MIXED");
error!("Set SPENDING_LEAF_TYPE to the actual type of the leaf being spent (SCHNORR_ONLY or SLH_DSA_ONLY).");
error!("The leaf type is returned in the 'leaf_script_type' field of the tree construction output.");
std::process::exit(1);
}
}
} else {
leaf_script_type
};
// Parse private keys based on effective script type
let leaf_script_priv_keys_bytes: Vec> = match effective_leaf_type {
LeafScriptType::SlhDsaOnly => {
let priv_keys_hex_array = env::var("LEAF_SCRIPT_PRIV_KEYS_HEX")
.unwrap_or_else(|_| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX environment variable is required for SLH_DSA_ONLY");
std::process::exit(1);
});
// Parse JSON array and extract the first (and only) hex string
let priv_keys_hex: String = serde_json::from_str::>(&priv_keys_hex_array)
.unwrap_or_else(|_| {
error!("Failed to parse LEAF_SCRIPT_PRIV_KEYS_HEX as JSON array");
std::process::exit(1);
})
.into_iter()
.next()
.unwrap_or_else(|| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX array is empty");
std::process::exit(1);
});
let priv_keys_bytes = hex::decode(priv_keys_hex).unwrap();
if priv_keys_bytes.len() != 64 {
error!("SLH-DSA private key must be 64 bytes, got {}", priv_keys_bytes.len());
std::process::exit(1);
}
vec![priv_keys_bytes]
},
LeafScriptType::SchnorrOnly => {
let priv_keys_hex_array = env::var("LEAF_SCRIPT_PRIV_KEYS_HEX")
.unwrap_or_else(|_| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX environment variable is required for SCHNORR_ONLY");
std::process::exit(1);
});
// Parse JSON array and extract the first (and only) hex string
let priv_keys_hex: String = serde_json::from_str::>(&priv_keys_hex_array)
.unwrap_or_else(|_| {
error!("Failed to parse LEAF_SCRIPT_PRIV_KEYS_HEX as JSON array");
std::process::exit(1);
})
.into_iter()
.next()
.unwrap_or_else(|| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX array is empty");
std::process::exit(1);
});
let priv_keys_bytes = hex::decode(priv_keys_hex).unwrap();
if priv_keys_bytes.len() != 32 {
error!("Schnorr private key must be 32 bytes, got {}", priv_keys_bytes.len());
std::process::exit(1);
}
vec![priv_keys_bytes]
},
LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf => {
let priv_keys_hex_array = env::var("LEAF_SCRIPT_PRIV_KEYS_HEX")
.unwrap_or_else(|_| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX environment variable is required for SCHNORR_AND_SLH_DSA");
std::process::exit(1);
});
// Parse JSON array and extract the hex strings
let priv_keys_hex_vec: Vec = serde_json::from_str(&priv_keys_hex_array)
.unwrap_or_else(|_| {
error!("Failed to parse LEAF_SCRIPT_PRIV_KEYS_HEX as JSON array");
std::process::exit(1);
});
if priv_keys_hex_vec.len() != 2 {
error!("For SCHNORR_AND_SLH_DSA, LEAF_SCRIPT_PRIV_KEYS_HEX must contain exactly 2 hex strings, got {}", priv_keys_hex_vec.len());
std::process::exit(1);
}
let schnorr_priv_key_hex = &priv_keys_hex_vec[0];
let slh_dsa_priv_key_hex = &priv_keys_hex_vec[1];
let schnorr_priv_key_bytes = hex::decode(schnorr_priv_key_hex).unwrap();
let slh_dsa_priv_key_bytes = hex::decode(slh_dsa_priv_key_hex).unwrap();
if schnorr_priv_key_bytes.len() != 32 {
error!("Schnorr private key must be 32 bytes, got {}", schnorr_priv_key_bytes.len());
std::process::exit(1);
}
if slh_dsa_priv_key_bytes.len() != 64 {
error!("SLH-DSA private key must be 64 bytes, got {}", slh_dsa_priv_key_bytes.len());
std::process::exit(1);
}
vec![schnorr_priv_key_bytes, slh_dsa_priv_key_bytes]
},
LeafScriptType::Mixed => {
// This case should never be reached because Mixed is resolved to effective_leaf_type above
unreachable!("Mixed should have been resolved to effective_leaf_type");
},
LeafScriptType::NotApplicable => {
panic!("LeafScriptType::NotApplicable is not applicable");
}
};
// ie: OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG
let leaf_script_bytes: Vec = env::var("LEAF_SCRIPT_HEX")
.map(|s| hex::decode(s).unwrap())
.unwrap_or_else(|_| {
error!("LEAF_SCRIPT_HEX environment variable is required but not set");
std::process::exit(1);
});
// https://learnmeabitcoin.com/explorer/tx/797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2#outputs
let spend_output_pubkey_hash_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap();
// OUTPUT_AMOUNT_SATS env var is optional. Default is FUNDING_UTXO_AMOUNT_SATS - 5000 sats
let spend_output_amount_sats: u64 = env::var("OUTPUT_AMOUNT_SATS")
.ok()
.and_then(|s| s.parse::().ok())
.unwrap_or(funding_utxo_amount_sats.saturating_sub(5000));
let result: SpendDetails = pay_to_p2wpkh_tx(
funding_tx_id_bytes,
funding_utxo_index,
funding_utxo_amount_sats,
funding_script_pubkey_bytes,
control_block_bytes,
leaf_script_bytes.clone(),
leaf_script_priv_keys_bytes, // Now passing Vec> instead of Vec
spend_output_pubkey_hash_bytes,
spend_output_amount_sats,
effective_leaf_type // Use effective type (resolved from SPENDING_LEAF_TYPE if Mixed)
);
// Remove first and last byte from leaf_script_bytes to get tapleaf_pubkey_bytes
let tapleaf_pubkey_bytes: Vec = leaf_script_bytes[1..leaf_script_bytes.len()-1].to_vec();
match effective_leaf_type {
LeafScriptType::SlhDsaOnly => {
let is_valid: bool = verify_slh_dsa_via_bytes(&result.sig_bytes, &result.sighash, &tapleaf_pubkey_bytes);
info!("is_valid: {}", is_valid);
},
LeafScriptType::SchnorrOnly => {
let is_valid: bool = verify_schnorr_signature_via_bytes(
&result.sig_bytes,
&result.sighash,
&tapleaf_pubkey_bytes);
info!("is_valid: {}", is_valid);
},
LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf => {
// For combined scripts, we need to separate the signatures
// The sig_bytes contains: [schnorr_sig (64 bytes), slh_dsa_sig (7856 bytes)] (raw signatures without sighash)
let schnorr_sig_len = 64; // Schnorr signature is 64 bytes
let slh_dsa_sig_len = 7856; // SLH-DSA signature is 7856 bytes
let expected_min_len = schnorr_sig_len + slh_dsa_sig_len;
if result.sig_bytes.len() < expected_min_len {
error!("Combined signature length is too short: expected at least {}, got {}",
expected_min_len, result.sig_bytes.len());
return result;
}
// Extract Schnorr signature (first 64 bytes)
let schnorr_sig = &result.sig_bytes[..schnorr_sig_len];
// Extract SLH-DSA signature (next 7856 bytes)
let slh_dsa_sig = &result.sig_bytes[schnorr_sig_len..schnorr_sig_len + slh_dsa_sig_len];
// For SCHNORR_AND_SLH_DSA scripts, we need to extract the individual public keys
// The script structure is: OP_PUSHBYTES_32 OP_CHECKSIG OP_PUSHBYTES_32 OP_SUBSTR OP_BOOLAND OP_VERIFY
// So we need to extract the Schnorr pubkey (first 32 bytes after OP_PUSHBYTES_32)
let schnorr_pubkey_bytes = &leaf_script_bytes[1..33]; // Skip OP_PUSHBYTES_32 (0x20), get next 32 bytes
let slh_dsa_pubkey_bytes = &leaf_script_bytes[35..67]; // Skip OP_CHECKSIG (0xac), OP_PUSHBYTES_32 (0x20), get next 32 bytes
// Verify Schnorr signature
let schnorr_is_valid: bool = verify_schnorr_signature_via_bytes(
schnorr_sig,
&result.sighash,
schnorr_pubkey_bytes);
info!("Schnorr signature is_valid: {}", schnorr_is_valid);
// Verify SLH-DSA signature
let slh_dsa_is_valid: bool = verify_slh_dsa_via_bytes(
slh_dsa_sig,
&result.sighash,
slh_dsa_pubkey_bytes);
info!("SLH-DSA signature is_valid: {}", slh_dsa_is_valid);
let both_valid = schnorr_is_valid && slh_dsa_is_valid;
info!("Both signatures valid: {}", both_valid);
}
LeafScriptType::Mixed => {
// This case should never be reached because Mixed is resolved to effective_leaf_type above
unreachable!("Mixed should have been resolved to effective_leaf_type");
}
LeafScriptType::NotApplicable => {
panic!("LeafScriptType::NotApplicable is not applicable");
}
}
return result;
}
================================================
FILE: bip-0360/ref-impl/rust/examples/p2tr_construction.rs
================================================
use p2mr_ref::{create_p2tr_utxo, create_p2tr_multi_leaf_taptree};
use p2mr_ref::data_structures::{UtxoReturn, TaptreeReturn, ConstructionReturn};
// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
fn main() -> ConstructionReturn {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let internal_pubkey_hex = "924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329".to_string();
let taptree_return: TaptreeReturn = create_p2tr_multi_leaf_taptree(internal_pubkey_hex.clone());
let utxo_return: UtxoReturn = create_p2tr_utxo(taptree_return.clone().tree_root_hex, internal_pubkey_hex);
return ConstructionReturn {
taptree_return: taptree_return,
utxo_return: utxo_return,
};
}
================================================
FILE: bip-0360/ref-impl/rust/examples/p2tr_spend.rs
================================================
use p2mr_ref::{ pay_to_p2wpkh_tx , verify_schnorr_signature_via_bytes};
use p2mr_ref::data_structures::{SpendDetails, LeafScriptType};
use std::env;
use log::{info, error};
// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
fn main() -> SpendDetails {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
// FUNDING_TX_ID environment variable is required
let funding_tx_id: String = env::var("FUNDING_TX_ID")
.unwrap_or_else(|_| {
error!("FUNDING_TX_ID environment variable is required but not set");
std::process::exit(1);
});
let funding_tx_id_bytes: Vec = hex::decode(funding_tx_id.clone()).unwrap();
// FUNDING_UTXO_AMOUNT_SATS environment variable is required
let funding_utxo_amount_sats: u64 = env::var("FUNDING_UTXO_AMOUNT_SATS")
.unwrap_or_else(|_| {
error!("FUNDING_UTXO_AMOUNT_SATS environment variable is required but not set");
std::process::exit(1);
})
.parse::()
.unwrap_or_else(|_| {
error!("FUNDING_UTXO_AMOUNT_SATS must be a valid u64 integer");
std::process::exit(1);
});
// The input index of the funding tx
// Allow override via FUNDING_UTXO_INDEX environment variable
let funding_utxo_index: u32 = env::var("FUNDING_UTXO_INDEX")
.ok()
.and_then(|s| s.parse::().ok())
.unwrap_or(0);
info!("Funding tx id: {}, utxo index: {}", funding_tx_id, funding_utxo_index);
// FUNDING_SCRIPT_PUBKEY environment variable is required
let funding_script_pubkey_bytes: Vec = env::var("FUNDING_SCRIPT_PUBKEY")
.map(|s| hex::decode(s).unwrap())
.unwrap_or_else(|_| {
error!("FUNDING_SCRIPT_PUBKEY environment variable is required but not set");
std::process::exit(1);
});
let control_block_bytes: Vec = env::var("CONTROL_BLOCK_HEX")
.map(|s| hex::decode(s).unwrap())
.unwrap_or_else(|_| {
error!("CONTROL_BLOCK_HEX environment variable is required but not set");
std::process::exit(1);
});
info!("P2TR control block size: {}", control_block_bytes.len());
// P2TR only supports Schnorr signatures, so we only need one private key
let leaf_script_priv_key_bytes: Vec = {
let priv_keys_hex_array = env::var("LEAF_SCRIPT_PRIV_KEYS_HEX")
.unwrap_or_else(|_| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX environment variable is required but not set");
std::process::exit(1);
});
// Parse JSON array and extract the first (and only) hex string
let priv_keys_hex: String = serde_json::from_str::>(&priv_keys_hex_array)
.unwrap_or_else(|_| {
error!("Failed to parse LEAF_SCRIPT_PRIV_KEYS_HEX as JSON array");
std::process::exit(1);
})
.into_iter()
.next()
.unwrap_or_else(|| {
error!("LEAF_SCRIPT_PRIV_KEYS_HEX array is empty");
std::process::exit(1);
});
hex::decode(priv_keys_hex).unwrap()
};
// Validate that the private key is 32 bytes (Schnorr key size)
if leaf_script_priv_key_bytes.len() != 32 {
error!("P2TR private key must be 32 bytes (Schnorr), got {}", leaf_script_priv_key_bytes.len());
std::process::exit(1);
}
// Convert to Vec> format expected by the function
let leaf_script_priv_keys_bytes: Vec> = vec![leaf_script_priv_key_bytes];
// ie: OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG
let leaf_script_bytes: Vec = env::var("LEAF_SCRIPT_HEX")
.map(|s| hex::decode(s).unwrap())
.unwrap_or_else(|_| {
error!("LEAF_SCRIPT_HEX environment variable is required but not set");
std::process::exit(1);
});
// https://learnmeabitcoin.com/explorer/tx/797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2#outputs
let spend_output_pubkey_hash_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap();
// OUTPUT_AMOUNT_SATS env var is optional. Default is FUNDING_UTXO_AMOUNT_SATS - 5000 sats
let spend_output_amount_sats: u64 = env::var("OUTPUT_AMOUNT_SATS")
.ok()
.and_then(|s| s.parse::().ok())
.unwrap_or(funding_utxo_amount_sats.saturating_sub(5000));
let result: SpendDetails = pay_to_p2wpkh_tx(
funding_tx_id_bytes,
funding_utxo_index,
funding_utxo_amount_sats,
funding_script_pubkey_bytes,
control_block_bytes,
leaf_script_bytes.clone(),
leaf_script_priv_keys_bytes, // Now passing Vec> format
spend_output_pubkey_hash_bytes.clone(),
spend_output_amount_sats,
LeafScriptType::SchnorrOnly
);
// Remove first and last byte from leaf_script_bytes to get tapleaf_pubkey_bytes
let tapleaf_pubkey_bytes: Vec = leaf_script_bytes[1..leaf_script_bytes.len()-1].to_vec();
let is_valid: bool = verify_schnorr_signature_via_bytes(
&result.sig_bytes,
&result.sighash,
&tapleaf_pubkey_bytes);
info!("is_valid: {}", is_valid);
return result;
}
================================================
FILE: bip-0360/ref-impl/rust/examples/schnorr_example.rs
================================================
use std::env;
use log::info;
use once_cell::sync::Lazy;
use bitcoin::key::{Secp256k1};
use bitcoin::hashes::{sha256::Hash, Hash as HashTrait};
use bitcoin::secp256k1::{Message};
use p2mr_ref::{ acquire_schnorr_keypair, verify_schnorr_signature };
/* Secp256k1 implements the Signing trait when it's initialized in signing mode.
It's important to note that Secp256k1 has different capabilities depending on how it's constructed:
* Secp256k1::new() creates a context capable of both signing and verification
* Secp256k1::signing_only() creates a context that can only sign
* Secp256k1::verification_only() creates a context that can only verify
*/
static SECP: Lazy> = Lazy::new(Secp256k1::new);
fn main() {
let _ = env_logger::try_init();
// acquire a schnorr keypair (leveraging OS provided random number generator)
let keypair = acquire_schnorr_keypair();
let (secret_key, public_key) = keypair.as_schnorr().unwrap();
let message_bytes = b"hello";
// secp256k1 operates on a 256-bit (32-byte) field, so inputs must be exactly this size
// subsequently, Schnorr signatures on secp256k1 require exactly a 32-byte input (the curve's scalar field size)
let message_hash: Hash = Hash::hash(message_bytes);
let message: Message = Message::from_digest_slice(&message_hash.to_byte_array()).unwrap();
/* The secp256k1 library internally generates a random scalar value (aka: nonce or k-value) for each signature
* Every signature is unique - even if you sign the same message with the same private key multiple times
* The randomness is handled automatically by the secp256k1 implementation
* You get different signatures each time for the same inputs
* The nonce is only needed during signing, not during verification
Schnorr signatures require randomness for security reasons:
* Prevents private key recovery - If the same nonce is used twice, an attacker could potentially derive your private key
* Ensures signature uniqueness - Each signature should be cryptographically distinct
* Protects against replay attacks - Different signatures for the same data
*/
let signature: bitcoin::secp256k1::schnorr::Signature = SECP.sign_schnorr(&message, &secret_key.keypair(&SECP));
info!("Signature created successfully, size: {}", signature.serialize().len());
//let pubkey = public_key;
/*
* The nonce provides security during signing (prevents private key recovery)
* The nonce is mathematically eliminated during verification
* The verifier only needs public information (signature, message, public key)
*/
let schnorr_valid = verify_schnorr_signature(signature, message, *public_key);
info!("schnorr_valid: {}", schnorr_valid);
let aux_rand = [0u8; 32]; // 32 zero bytes; fine for testing
let signature_aux_rand: bitcoin::secp256k1::schnorr::Signature = SECP.sign_schnorr_with_aux_rand(
&message,
&secret_key.keypair(&SECP),
&aux_rand
);
info!("aux_rand signature created successfully, size: {}", signature_aux_rand.serialize().len());
let schnorr_valid_aux_rand = verify_schnorr_signature(signature_aux_rand, message, *public_key);
info!("schnorr_valid_aux_rand: {}", schnorr_valid_aux_rand);
}
================================================
FILE: bip-0360/ref-impl/rust/examples/slh_dsa_verification_example.rs
================================================
use std::env;
use log::info;
use once_cell::sync::Lazy;
use bitcoin::hashes::{sha256::Hash, Hash as HashTrait};
use rand::{rng, RngCore};
use bitcoinpqc::{
generate_keypair, public_key_size, secret_key_size, sign, signature_size, verify, Algorithm, KeyPair,
};
fn main() {
let _ = env_logger::try_init();
/*
In SPHINCS+ (underlying algorithm of SLH-DSA), the random data is used to:
* Initialize hash function parameters within the key generation
* Seed the Merkle tree construction that forms the public key
* Generate the secret key components that enable signing
*/
let random_data = get_random_bytes(128);
println!("Generated random data of size {}", random_data.len());
let keypair: KeyPair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data)
.expect("Failed to generate SLH-DSA-128S keypair");
let message_bytes = b"SLH-DSA-128S Test Message";
println!("Message to sign: {message_bytes:?}");
/* No need to hash the message
1. Variable Input Size: SPHINCS+ can handle messages of arbitrary length directly
2. Internal Hashing: The SPHINCS+ algorithm internally handles message processing and hashing as part of its design
3. Hash-Based Design: SPHINCS+ is built on hash functions and Merkle trees, so it's designed to work with variable-length inputs
4. No Curve Constraints: Unlike elliptic curve schemes, SPHINCS+ doesn't have fixed field size requirements
SLH-DSA doesn't use nonces like Schnorr does.
With SLH-DSA, randomness is built into the key generation process only ( and not the signing process; ie: SECP256K1)
Thus, no need for aux_rand data fed to the signature function.
The signing algorithm is deterministic and doesn't require random input during signing.
*/
let signature = sign(&keypair.secret_key, message_bytes).expect("Failed to sign with SLH-DSA-128S");
println!(
"Signature created successfully, size: {}",
signature.bytes.len()
);
println!(
"Signature prefix: {:02x?}",
&signature.bytes[..8.min(signature.bytes.len())]
);
// Verify the signature
println!("Verifying signature...");
let result = verify(&keypair.public_key, message_bytes, &signature);
println!("Verification result: {result:?}");
assert!(result.is_ok(), "SLH-DSA-128S signature verification failed");
// Try to verify with a modified message - should fail
let modified_message = b"SLH-DSA-128S Modified Message";
println!("Modified message: {modified_message:?}");
let result = verify(&keypair.public_key, modified_message, &signature);
println!("Verification with modified message result: {result:?}");
assert!(
result.is_err(),
"SLH-DSA-128S verification should fail with modified message"
);
}
fn get_random_bytes(size: usize) -> Vec {
let mut bytes = vec![0u8; size];
rng().fill_bytes(&mut bytes);
bytes
}
================================================
FILE: bip-0360/ref-impl/rust/src/bin/slh_dsa_key_gen.rs
================================================
use std::env;
use log::info;
use rand::{rng, RngCore};
use bitcoinpqc::{
generate_keypair, public_key_size, secret_key_size, Algorithm, KeyPair,
};
fn main() {
let _ = env_logger::try_init();
/*
In SPHINCS+ (underlying algorithm of SLH-DSA), the random data is used to:
* Initialize hash function parameters within the key generation
* Seed the Merkle tree construction that forms the public key
* Generate the secret key components that enable signing
*/
let random_data = get_random_bytes(128);
println!("Generated random data of size {}", random_data.len());
let keypair: KeyPair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data)
.expect("Failed to generate SLH-DSA-128S keypair");
info!("public key size / value = {}, {}", public_key_size(Algorithm::SLH_DSA_128S), hex::encode(&keypair.public_key.bytes));
info!("private key size / value = {}, {}", secret_key_size(Algorithm::SLH_DSA_128S), hex::encode(&keypair.secret_key.bytes));
}
fn get_random_bytes(size: usize) -> Vec {
let mut bytes = vec![0u8; size];
rng().fill_bytes(&mut bytes);
bytes
}
================================================
FILE: bip-0360/ref-impl/rust/src/data_structures.rs
================================================
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use log::debug;
// Add imports for the unified keypair
use bitcoin::secp256k1::{SecretKey, XOnlyPublicKey};
use bitcoinpqc::{KeyPair, Algorithm};
/// Enum representing the type of leaf script to create
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LeafScriptType {
/// Script requires only SLH-DSA signature
SlhDsaOnly,
/// Script requires only Schnorr signature
SchnorrOnly,
/// Script requires both Schnorr and SLH-DSA signatures (in that order)
ConcatenatedSchnorrAndSlhDsaSameLeaf,
/// Leaves of TapTree are mixed. Some leaves are locked using Schnorr and others are locked using SLH-DSA
Mixed,
/// Script type is not applicable
NotApplicable,
}
impl LeafScriptType {
/// Check if this script type uses SLH-DSA
pub fn uses_slh_dsa(&self) -> bool {
matches!(self, LeafScriptType::SlhDsaOnly | LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf)
}
/// Check if this script type uses Schnorr
pub fn uses_schnorr(&self) -> bool {
matches!(self, LeafScriptType::SchnorrOnly | LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf)
}
/// Check if this script type requires both signature types
pub fn requires_both(&self) -> bool {
matches!(self, LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf)
}
/// Check if TapTree uses Schnorr for some leaves and SLH-DSA for others
pub fn uses_mixed(&self) -> bool {
matches!(self, LeafScriptType::Mixed)
}
/// Check if this script type is not applicable
pub fn is_not_applicable(&self) -> bool {
matches!(self, LeafScriptType::NotApplicable)
}
/// Convert to string representation for serialization
pub fn to_string(&self) -> String {
match self {
LeafScriptType::SlhDsaOnly => "SLH_DSA_ONLY".to_string(),
LeafScriptType::SchnorrOnly => "SCHNORR_ONLY".to_string(),
LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf => "CONCATENATED_SCHNORR_AND_SLH_DSA".to_string(),
LeafScriptType::Mixed => "MIXED".to_string(),
LeafScriptType::NotApplicable => "NOT_APPLICABLE".to_string(),
}
}
/// Parse from string representation
pub fn from_string(s: &str) -> Self {
match s {
"SLH_DSA_ONLY" => LeafScriptType::SlhDsaOnly,
"SCHNORR_ONLY" => LeafScriptType::SchnorrOnly,
"CONCATENATED_SCHNORR_AND_SLH_DSA" => LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf,
"MIXED" => LeafScriptType::Mixed,
_ => LeafScriptType::NotApplicable,
}
}
}
#[derive(Debug, Serialize)]
pub struct TestVectors {
pub version: u32,
#[serde(rename = "test_vectors")]
pub test_vectors: Vec,
#[serde(skip, default = "HashMap::new")]
pub test_vector_map: HashMap,
}
impl<'de> Deserialize<'de> for TestVectors {
fn deserialize(deserializer: D) -> Result
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct Helper {
version: u32,
#[serde(rename = "test_vectors")]
test_vectors: Vec,
}
let helper = Helper::deserialize(deserializer)?;
let mut test_vector_map = HashMap::new();
for test in helper.test_vectors.iter() {
test_vector_map.insert(test.id.clone(), test.clone());
}
Ok(TestVectors {
version: helper.version,
test_vectors: helper.test_vectors,
test_vector_map,
})
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TestVector {
pub id: String,
pub objective: String,
pub given: TestVectorGiven,
pub intermediary: TestVectorIntermediary,
pub expected: TestVectorExpected,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TestVectorGiven {
#[serde(rename = "internalPubkey")]
pub internal_pubkey: Option,
#[serde(rename = "scriptTree")]
pub script_tree: Option,
#[serde(rename = "scriptInputs")]
pub script_inputs: Option>,
#[serde(rename = "scriptHex")]
pub script_hex: Option,
#[serde(rename = "controlBlock")]
pub control_block: Option,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TestVectorIntermediary {
#[serde(default)]
#[serde(rename = "leafHashes")]
pub leaf_hashes: Vec,
#[serde(rename = "merkleRoot")]
pub merkle_root: Option
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TestVectorExpected {
#[serde(rename = "scriptPubKey")]
pub script_pubkey: Option,
#[serde(rename = "bip350Address")]
pub bip350_address: Option,
#[serde(default)]
#[serde(rename = "scriptPathControlBlocks")]
pub script_path_control_blocks: Option>,
#[serde(rename = "error")]
pub error: Option,
#[serde(rename = "address")]
pub address: Option,
#[serde(default)]
pub witness: Option
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TVScriptLeaf {
pub id: u8,
pub script: String,
#[serde(rename = "leafVersion")]
pub leaf_version: u8,
}
// Taproot script trees are binary trees, so each branch should have exactly two children.
#[derive(Debug, Serialize, Clone)]
pub enum TVScriptTree {
Leaf(TVScriptLeaf),
Branch {
// Box is used because Rust needs to know the exact size of types at compile time.
// Without it, we'd have an infinitely size recursive type.
// The enum itself is on the stack, but the Box fields within the Branch variant store pointers to heap-allocated ScriptTree values.
left: Box,
right: Box,
},
}
// Add custom deserialize implementation
impl<'de> Deserialize<'de> for TVScriptTree {
fn deserialize(deserializer: D) -> Result
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum Helper {
Leaf(TVScriptLeaf),
Branch(Vec),
}
match Helper::deserialize(deserializer)? {
Helper::Leaf(leaf) => Ok(TVScriptTree::Leaf(leaf)),
Helper::Branch(v) => {
assert!(v.len() == 2, "Branch must have exactly two children");
let mut iter = v.into_iter();
Ok(TVScriptTree::Branch {
left: Box::new(iter.next().unwrap()),
right: Box::new(iter.next().unwrap()),
})
}
}
}
}
// Add this enum before the TVScriptTree implementation
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
Left,
Right,
Root,
}
impl TVScriptTree {
/// Implements a "post-order" traversal as follows: left, right, branch
pub fn traverse_with_depth(&self, depth: u8, direction: Direction, f: &mut F) {
match self {
TVScriptTree::Branch { left, right } => {
right.traverse_with_depth(depth, Direction::Right, f); // Pass Right for right subtree
left.traverse_with_depth(depth, Direction::Left, f); // Pass Left for left subtree
f(self, depth, direction); // Pass the current node's direction
}
TVScriptTree::Leaf { .. } => {
f(self, depth, direction);
}
}
}
/// Traverses the tree visiting right subtree leaves first, then left subtree leaves.
/// Depth increases by 1 at each branch level.
/*
root (depth 0)
/ \
L0 (depth 1) (subtree) (depth 1)
/ \
L1 (depth 2) L2 (depth 2)
The new traversal will visit:
L1 at depth 2 -> L2 at depth 2 -> L0 at depth 1
*/
pub fn traverse_with_right_subtree_first(&self, depth: u8, direction: Direction, f: &mut F) {
match self {
TVScriptTree::Branch { left, right } => {
let next_depth = depth + 1;
// Visit right subtree first
right.traverse_with_right_subtree_first(next_depth, Direction::Right, f);
// Then visit left subtree
left.traverse_with_right_subtree_first(next_depth, Direction::Left, f);
}
TVScriptTree::Leaf { .. } => {
f(self, depth, direction);
}
}
}
}
impl std::fmt::Display for Direction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Direction::Left => write!(f, "L"),
Direction::Right => write!(f, "R"),
Direction::Root => write!(f, "Root"),
}
}
}
pub struct ScriptTreeHashCache {
pub leaf_hashes: HashMap,
pub branch_hashes: HashMap,
}
impl ScriptTreeHashCache {
pub fn new() -> Self {
Self {
leaf_hashes: HashMap::new(),
branch_hashes: HashMap::new(),
}
}
pub fn set_leaf_hash(&mut self, branch_id: u8, direction: Direction, hash: String) {
let key = format!("{branch_id}_{direction}");
debug!("set_leaf_hash: key: {}, hash: {}", key, hash);
self.leaf_hashes.insert(key, hash);
}
pub fn set_branch_hash(&mut self, branch_id: u8, hash: String) {
self.branch_hashes.insert(branch_id, hash);
}
}
fn serialize_hex(bytes: &Vec, s: S) -> Result
where
S: serde::Serializer,
{
s.serialize_str(&hex::encode(bytes))
}
fn deserialize_hex<'de, D>(d: D) -> Result, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(d)?;
hex::decode(s).map_err(serde::de::Error::custom)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpendDetails {
pub tx_hex: String,
#[serde(serialize_with = "serialize_hex")]
#[serde(deserialize_with = "deserialize_hex")]
pub sighash: Vec,
#[serde(serialize_with = "serialize_hex")]
#[serde(deserialize_with = "deserialize_hex")]
pub sig_bytes: Vec,
#[serde(serialize_with = "serialize_hex")]
#[serde(deserialize_with = "deserialize_hex")]
pub derived_witness_vec: Vec,
}
impl std::process::Termination for SpendDetails {
fn report(self) -> std::process::ExitCode {
if let Ok(json) = serde_json::to_string_pretty(&self) {
println!("{}", json);
} else {
println!("{:?}", self);
}
std::process::ExitCode::SUCCESS
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UtxoReturn {
pub script_pubkey_hex: String,
pub bech32m_address: String,
pub bitcoin_network: bitcoin::Network,
}
impl std::process::Termination for UtxoReturn {
fn report(self) -> std::process::ExitCode {
if let Ok(json) = serde_json::to_string_pretty(&self) {
println!("{}", json);
} else {
println!("{:?}", self);
}
std::process::ExitCode::SUCCESS
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaptreeReturn {
pub leaf_script_priv_keys_hex: Vec, // Changed to support multiple private keys
pub leaf_script_hex: String,
pub tree_root_hex: String,
pub control_block_hex: String,
/// The script type of the leaf being returned (needed for spending)
pub leaf_script_type: String,
}
impl std::process::Termination for TaptreeReturn {
fn report(self) -> std::process::ExitCode {
if let Ok(json) = serde_json::to_string_pretty(&self) {
println!("{}", json);
} else {
println!("{:?}", self);
}
std::process::ExitCode::SUCCESS
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstructionReturn {
pub taptree_return: TaptreeReturn,
pub utxo_return: UtxoReturn,
}
impl std::process::Termination for ConstructionReturn {
fn report(self) -> std::process::ExitCode {
if let Ok(json) = serde_json::to_string_pretty(&self) {
println!("{}", json);
} else {
println!("{:?}", self);
}
std::process::ExitCode::SUCCESS
}
}
/// A unified keypair that can contain either a Schnorr keypair or an SLH-DSA keypair
#[derive(Debug, Clone)]
pub enum UnifiedKeypair {
Schnorr(SecretKey, XOnlyPublicKey),
SlhDsa(KeyPair),
}
/// A container for multiple keypairs that can be used in a single leaf script
#[derive(Debug, Clone)]
pub struct MultiKeypair {
pub schnorr_keypair: Option,
pub slh_dsa_keypair: Option,
}
impl MultiKeypair {
/// Create a new MultiKeypair with only a Schnorr keypair
pub fn new_schnorr_only(schnorr_keypair: UnifiedKeypair) -> Self {
Self {
schnorr_keypair: Some(schnorr_keypair),
slh_dsa_keypair: None,
}
}
/// Create a new MultiKeypair with only an SLH-DSA keypair
pub fn new_slh_dsa_only(slh_dsa_keypair: UnifiedKeypair) -> Self {
Self {
schnorr_keypair: None,
slh_dsa_keypair: Some(slh_dsa_keypair),
}
}
/// Create a new MultiKeypair with both keypairs
pub fn new_combined(schnorr_keypair: UnifiedKeypair, slh_dsa_keypair: UnifiedKeypair) -> Self {
Self {
schnorr_keypair: Some(schnorr_keypair),
slh_dsa_keypair: Some(slh_dsa_keypair),
}
}
/// Get all secret key bytes for serialization (in order: schnorr, then slh_dsa if present)
pub fn secret_key_bytes(&self) -> Vec> {
let mut result = Vec::new();
if let Some(ref schnorr) = self.schnorr_keypair {
result.push(schnorr.secret_key_bytes());
}
if let Some(ref slh_dsa) = self.slh_dsa_keypair {
result.push(slh_dsa.secret_key_bytes());
}
result
}
/// Get all public key bytes for script construction (in order: schnorr, then slh_dsa if present)
pub fn public_key_bytes(&self) -> Vec> {
let mut result = Vec::new();
if let Some(ref schnorr) = self.schnorr_keypair {
result.push(schnorr.public_key_bytes());
}
if let Some(ref slh_dsa) = self.slh_dsa_keypair {
result.push(slh_dsa.public_key_bytes());
}
result
}
/// Check if this contains a Schnorr keypair
pub fn has_schnorr(&self) -> bool {
self.schnorr_keypair.is_some()
}
/// Check if this contains an SLH-DSA keypair
pub fn has_slh_dsa(&self) -> bool {
self.slh_dsa_keypair.is_some()
}
/// Get the Schnorr keypair if present
pub fn schnorr_keypair(&self) -> Option<&UnifiedKeypair> {
self.schnorr_keypair.as_ref()
}
/// Get the SLH-DSA keypair if present
pub fn slh_dsa_keypair(&self) -> Option<&UnifiedKeypair> {
self.slh_dsa_keypair.as_ref()
}
}
/// Information about a single leaf in a mixed-type tree
/// Used when different leaves in the same tree use different algorithms
#[derive(Debug, Clone)]
pub struct MixedLeafInfo {
/// The leaf index in the tree
pub leaf_index: u32,
/// The script type for this specific leaf
pub leaf_script_type: LeafScriptType,
/// The keypairs for this leaf
pub keypairs: MultiKeypair,
/// The script for this leaf
pub script: Vec,
}
impl MixedLeafInfo {
/// Create a new MixedLeafInfo for a Schnorr-only leaf
pub fn new_schnorr(leaf_index: u32, keypairs: MultiKeypair, script: Vec) -> Self {
Self {
leaf_index,
leaf_script_type: LeafScriptType::SchnorrOnly,
keypairs,
script,
}
}
/// Create a new MixedLeafInfo for an SLH-DSA-only leaf
pub fn new_slh_dsa(leaf_index: u32, keypairs: MultiKeypair, script: Vec) -> Self {
Self {
leaf_index,
leaf_script_type: LeafScriptType::SlhDsaOnly,
keypairs,
script,
}
}
/// Create a new MixedLeafInfo for a combined Schnorr+SLH-DSA leaf
pub fn new_combined(leaf_index: u32, keypairs: MultiKeypair, script: Vec) -> Self {
Self {
leaf_index,
leaf_script_type: LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf,
keypairs,
script,
}
}
/// Get the secret key bytes for this leaf
pub fn secret_key_bytes(&self) -> Vec> {
self.keypairs.secret_key_bytes()
}
/// Get the public key bytes for this leaf
pub fn public_key_bytes(&self) -> Vec> {
self.keypairs.public_key_bytes()
}
}
impl UnifiedKeypair {
/// Create a new Schnorr keypair
pub fn new_schnorr(secret_key: SecretKey, public_key: XOnlyPublicKey) -> Self {
UnifiedKeypair::Schnorr(secret_key, public_key)
}
/// Create a new SLH-DSA keypair
pub fn new_slh_dsa(keypair: KeyPair) -> Self {
UnifiedKeypair::SlhDsa(keypair)
}
/// Get the secret key bytes for serialization
pub fn secret_key_bytes(&self) -> Vec {
match self {
UnifiedKeypair::Schnorr(secret_key, _) => secret_key.secret_bytes().to_vec(),
UnifiedKeypair::SlhDsa(keypair) => keypair.secret_key.bytes.clone(),
}
}
/// Get the public key bytes for script construction
pub fn public_key_bytes(&self) -> Vec {
match self {
UnifiedKeypair::Schnorr(_, public_key) => public_key.serialize().to_vec(),
UnifiedKeypair::SlhDsa(keypair) => keypair.public_key.bytes.clone(),
}
}
/// Get the algorithm type
pub fn algorithm(&self) -> &'static str {
match self {
UnifiedKeypair::Schnorr(_, _) => "Schnorr",
UnifiedKeypair::SlhDsa(_) => "SLH-DSA",
}
}
/// Check if this is a Schnorr keypair
pub fn is_schnorr(&self) -> bool {
matches!(self, UnifiedKeypair::Schnorr(_, _))
}
/// Check if this is an SLH-DSA keypair
pub fn is_slh_dsa(&self) -> bool {
matches!(self, UnifiedKeypair::SlhDsa(_))
}
/// Get the underlying Schnorr keypair if this is a Schnorr keypair
pub fn as_schnorr(&self) -> Option<(&SecretKey, &XOnlyPublicKey)> {
match self {
UnifiedKeypair::Schnorr(secret_key, public_key) => Some((secret_key, public_key)),
_ => None,
}
}
/// Get the underlying SLH-DSA keypair if this is an SLH-DSA keypair
pub fn as_slh_dsa(&self) -> Option<&KeyPair> {
match self {
UnifiedKeypair::SlhDsa(keypair) => Some(keypair),
_ => None,
}
}
}
================================================
FILE: bip-0360/ref-impl/rust/src/error.rs
================================================
use thiserror::Error;
#[derive(Error, Debug)]
pub enum P2MRError {
#[error("P2TR requires witness version of 1")]
P2trRequiresWitnessVersion1,
#[error("P2MR requires a script tree with at least one leaf")]
MissingScriptTreeLeaf,
// We can add more specific error variants here as needed
#[error("Invalid script tree structure: {0}")]
InvalidScriptTree(String),
}
================================================
FILE: bip-0360/ref-impl/rust/src/lib.rs
================================================
pub mod data_structures;
pub mod error;
use log::{debug, info, error};
use std::env;
use std::io::Write;
use rand::{rng, RngCore};
use once_cell::sync::Lazy;
use bitcoin::hashes::{sha256, Hash};
use bitcoin::key::{Secp256k1, Parity};
use bitcoin::secp256k1::{Message, SecretKey, Keypair, rand::rngs::OsRng, rand::thread_rng, rand::Rng, schnorr::Signature};
use bitcoin::{ Amount, TxOut, WPubkeyHash,
Address, Network, OutPoint,
blockdata::witness::Witness,
Script, ScriptBuf, XOnlyPublicKey, PublicKey,
sighash::{SighashCache, TapSighashType, Prevouts, TapSighash},
taproot::{LeafVersion, NodeInfo, TapLeafHash, TapNodeHash, TapTree, ScriptLeaves, TaprootMerkleBranch, TaprootBuilder, TaprootSpendInfo, ControlBlock},
transaction::{Transaction, Sequence}
};
use bitcoin::p2mr::{P2mrScriptBuf, P2mrBuilder, P2mrSpendInfo, P2mrControlBlock, P2MR_LEAF_VERSION};
use bitcoinpqc::{
generate_keypair, public_key_size, secret_key_size, Algorithm, KeyPair, sign, verify,
};
use data_structures::{SpendDetails, UtxoReturn, TaptreeReturn, UnifiedKeypair, MultiKeypair, LeafScriptType, MixedLeafInfo};
/* Secp256k1 implements the Signing trait when it's initialized in signing mode.
It's important to note that Secp256k1 has different capabilities depending on how it's constructed:
* Secp256k1::new() creates a context capable of both signing and verification
* Secp256k1::signing_only() creates a context that can only sign
* Secp256k1::verification_only() creates a context that can only verify
*/
static SECP: Lazy> = Lazy::new(Secp256k1::new);
/// Creates a Huffman tree with leaves of the specified script type.
///
/// For Mixed type, leaves alternate between Schnorr (even indices) and SLH-DSA (odd indices).
/// The LEAF_TO_SPEND_FROM_TYPE env var can override the type for the leaf of interest.
///
/// Returns: (huffman_entries, keypairs_of_interest, script_buf_of_interest, actual_leaf_type)
fn create_huffman_tree(leaf_script_type: LeafScriptType) -> (Vec<(u32, ScriptBuf)>, MultiKeypair, ScriptBuf, LeafScriptType) {
let mut total_leaf_count: u32 = 1;
if let Ok(env_value) = env::var("TOTAL_LEAF_COUNT") {
if let Ok(parsed_value) = env_value.parse::() {
total_leaf_count = parsed_value;
}
}
let mut leaf_to_spend_from: u32 = 0;
if let Ok(env_value) = env::var("LEAF_TO_SPEND_FROM") {
if let Ok(parsed_value) = env_value.parse::() {
leaf_to_spend_from = parsed_value;
}
}
// For Mixed mode, allow overriding the type of the leaf of interest
let leaf_to_spend_from_type: Option = if leaf_script_type == LeafScriptType::Mixed {
env::var("LEAF_TO_SPEND_FROM_TYPE").ok().map(|s| LeafScriptType::from_string(&s))
} else {
None
};
if total_leaf_count < 1 {
panic!("total_leaf_count must be greater than 0");
}
if leaf_to_spend_from >= total_leaf_count {
panic!("leaf_to_spend_from must be less than total_leaf_count and greater than 0");
}
debug!("Creating multi-leaf taptree with total_leaf_count: {}, leaf_to_spend_from: {}", total_leaf_count, leaf_to_spend_from);
let mut huffman_entries: Vec<(u32, ScriptBuf)> = vec![];
let mut keypairs_of_interest: Option = None;
let mut script_buf_of_interest: Option = None;
let mut actual_leaf_type_of_interest: LeafScriptType = leaf_script_type;
for leaf_index in 0..total_leaf_count {
let keypairs: MultiKeypair;
let script_buf: ScriptBuf;
// Determine the effective script type for this leaf
let effective_script_type = if leaf_script_type == LeafScriptType::Mixed {
// For Mixed mode, check if this is the leaf of interest with an override
if leaf_index == leaf_to_spend_from && leaf_to_spend_from_type.is_some() {
leaf_to_spend_from_type.unwrap()
} else {
// Default pattern: even indices use Schnorr, odd indices use SLH-DSA
if leaf_index % 2 == 0 {
LeafScriptType::SchnorrOnly
} else {
LeafScriptType::SlhDsaOnly
}
}
} else {
leaf_script_type
};
match effective_script_type {
LeafScriptType::SchnorrOnly => {
let schnorr_keypair = acquire_schnorr_keypair();
keypairs = MultiKeypair::new_schnorr_only(schnorr_keypair);
let pubkey_bytes = keypairs.schnorr_keypair().unwrap().public_key_bytes();
// OP_PUSHBYTES_32 <32-byte xonly pubkey> OP_CHECKSIG
let mut script_buf_bytes = vec![0x20];
script_buf_bytes.extend_from_slice(&pubkey_bytes);
script_buf_bytes.push(0xac); // OP_CHECKSIG
script_buf = ScriptBuf::from_bytes(script_buf_bytes);
},
LeafScriptType::SlhDsaOnly => {
let slh_dsa_keypair = acquire_slh_dsa_keypair();
keypairs = MultiKeypair::new_slh_dsa_only(slh_dsa_keypair);
let pubkey_bytes = keypairs.slh_dsa_keypair().unwrap().public_key_bytes();
// OP_PUSHBYTES_32 <32-byte pubkey> OP_SUBSTR
let mut script_buf_bytes = vec![0x20];
script_buf_bytes.extend_from_slice(&pubkey_bytes);
script_buf_bytes.push(0x7f); // OP_SUBSTR
script_buf = ScriptBuf::from_bytes(script_buf_bytes);
},
LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf => {
// For combined scripts, we need both keypairs
let schnorr_keypair = acquire_schnorr_keypair();
let slh_dsa_keypair = acquire_slh_dsa_keypair();
keypairs = MultiKeypair::new_combined(schnorr_keypair, slh_dsa_keypair);
let schnorr_pubkey = keypairs.schnorr_keypair().unwrap().public_key_bytes();
let slh_dsa_pubkey = keypairs.slh_dsa_keypair().unwrap().public_key_bytes();
// Debug: Print the private key used for script construction
info!("SLH-DSA DEBUG: Script construction using private key: {}", hex::encode(keypairs.slh_dsa_keypair().unwrap().secret_key_bytes()));
info!("SLH-DSA DEBUG: Script construction using public key: {}", hex::encode(&slh_dsa_pubkey));
// Combined script: OP_CHECKSIG OP_SUBSTR OP_BOOLAND OP_VERIFY
let mut script_buf_bytes = vec![0x20]; // OP_PUSHBYTES_32
script_buf_bytes.extend_from_slice(&schnorr_pubkey);
script_buf_bytes.push(0xac); // OP_CHECKSIG
script_buf_bytes.push(0x20); // OP_PUSHBYTES_32
script_buf_bytes.extend_from_slice(&slh_dsa_pubkey);
script_buf_bytes.push(0x7f); // OP_SUBSTR
script_buf_bytes.push(0x9a); // OP_BOOLAND
script_buf_bytes.push(0x69); // OP_VERIFY
script_buf = ScriptBuf::from_bytes(script_buf_bytes);
}
LeafScriptType::Mixed => {
// This shouldn't happen as Mixed is resolved to a specific type above
panic!("LeafScriptType::Mixed should have been resolved to a specific type");
}
LeafScriptType::NotApplicable => {
panic!("LeafScriptType::NotApplicable is not applicable");
}
}
let random_weight = thread_rng().gen_range(0..total_leaf_count);
let huffman_entry = (random_weight, script_buf.clone());
huffman_entries.push(huffman_entry);
if leaf_index == leaf_to_spend_from {
keypairs_of_interest = Some(keypairs);
script_buf_of_interest = Some(script_buf.clone());
actual_leaf_type_of_interest = effective_script_type;
debug!("Selected leaf {}: type: {:?}, weight: {}, script: {:?}",
leaf_index, effective_script_type, random_weight, script_buf);
}
}
return (huffman_entries, keypairs_of_interest.unwrap(), script_buf_of_interest.unwrap(), actual_leaf_type_of_interest);
}
/// Parses the TAP_TREE_LOCK_TYPE environment variable and returns the corresponding LeafScriptType.
/// Defaults to LeafScriptType::SchnorrOnly if the environment variable is not set.
/// Exits with error code 1 if an invalid value is provided.
///
/// Supported values:
/// - SLH_DSA_ONLY: All leaves use SLH-DSA signatures
/// - SCHNORR_ONLY: All leaves use Schnorr signatures
/// - CONCATENATED_SCHNORR_AND_SLH_DSA: All leaves require both Schnorr and SLH-DSA signatures
/// - MIXED: Different leaves use different algorithms (Schnorr or SLH-DSA) (default)
pub fn tap_tree_lock_type() -> LeafScriptType {
match env::var("TAP_TREE_LOCK_TYPE") {
Ok(value) => match value.as_str() {
"SLH_DSA_ONLY" => LeafScriptType::SlhDsaOnly,
"SCHNORR_ONLY" => LeafScriptType::SchnorrOnly,
"CONCATENATED_SCHNORR_AND_SLH_DSA" => LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf,
"MIXED" => LeafScriptType::Mixed,
_ => {
error!("Invalid TAP_TREE_LOCK_TYPE '{}'. Must be one of: SLH_DSA_ONLY, SCHNORR_ONLY, CONCATENATED_SCHNORR_AND_SLH_DSA, MIXED", value);
std::process::exit(1);
}
},
Err(_) => {
// Default to Mixed if not set
LeafScriptType::Mixed
}
}
}
pub fn create_p2mr_multi_leaf_taptree() -> TaptreeReturn {
let leaf_script_type = tap_tree_lock_type();
let (huffman_entries, keypairs_of_interest, script_buf_of_interest, actual_leaf_type) = create_huffman_tree(leaf_script_type);
let p2mr_builder: P2mrBuilder = P2mrBuilder::with_huffman_tree(huffman_entries).unwrap();
let p2mr_spend_info: P2mrSpendInfo = p2mr_builder.clone().finalize().unwrap();
let merkle_root:TapNodeHash = p2mr_spend_info.merkle_root.unwrap();
let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let mut script_leaves: ScriptLeaves = tap_tree.script_leaves();
let script_leaf = script_leaves
.find(|leaf| leaf.script() == script_buf_of_interest.as_script())
.expect("Script leaf not found");
let merkle_root_node_info: NodeInfo = p2mr_builder.clone().into_inner().try_into_node_info().unwrap();
let merkle_root: TapNodeHash = merkle_root_node_info.node_hash();
let leaf_hash: TapLeafHash = TapLeafHash::from_script(script_leaf.script(), LeafVersion::from_consensus(P2MR_LEAF_VERSION).unwrap());
// Convert leaf hash to big-endian for display (like Bitcoin Core)
let mut leaf_hash_bytes = leaf_hash.as_raw_hash().to_byte_array().to_vec();
leaf_hash_bytes.reverse();
info!("leaf_hash: {}, merkle_root: {}, merkle_root: {}",
hex::encode(leaf_hash_bytes),
merkle_root,
merkle_root);
let leaf_script = script_leaf.script();
let merkle_branch: &TaprootMerkleBranch = script_leaf.merkle_branch();
info!("Leaf script: {}, merkle branch: {:?}", leaf_script, merkle_branch);
let control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(),
};
// Not a requirement here but useful to demonstrate what Bitcoin Core does as the verifier when spending from a p2mr UTXO
control_block.verify_script_in_merkle_root_path(leaf_script, merkle_root);
let control_block_hex: String = hex::encode(control_block.serialize());
return TaptreeReturn {
leaf_script_priv_keys_hex: keypairs_of_interest.secret_key_bytes()
.into_iter()
.map(|bytes| hex::encode(bytes))
.collect(),
leaf_script_hex: leaf_script.to_hex_string(),
tree_root_hex: hex::encode(merkle_root.to_byte_array()),
control_block_hex: control_block_hex,
leaf_script_type: actual_leaf_type.to_string(),
};
}
pub fn create_p2tr_multi_leaf_taptree(p2tr_internal_pubkey_hex: String) -> TaptreeReturn {
let (huffman_entries, keypairs_of_interest, script_buf_of_interest, actual_leaf_type) = create_huffman_tree(LeafScriptType::SchnorrOnly);
let pub_key_string = format!("02{}", p2tr_internal_pubkey_hex);
let internal_pubkey: PublicKey = pub_key_string.parse::().unwrap();
let internal_xonly_pubkey: XOnlyPublicKey = internal_pubkey.inner.into();
let p2tr_builder: TaprootBuilder = TaprootBuilder::with_huffman_tree(huffman_entries).unwrap();
let p2tr_spend_info: TaprootSpendInfo = p2tr_builder.clone().finalize(&SECP, internal_xonly_pubkey).unwrap();
let merkle_root: TapNodeHash = p2tr_spend_info.merkle_root().unwrap();
// During taproot construction, the internal key is "tweaked" by adding a scalar (the tap tweak hash) to it.
// If this tweaking operation results in a public key w/ an odd Y-coordinate, the parity bit is set to 1.
// When spending via script path, the verifier needs to know whether the output key has an even or odd Y-coordinate to properly reconstruct & verify the internal key.
// The internal key can be recovered from the output key using the parity bit and the merkle root.
let output_key_parity: Parity = p2tr_spend_info.output_key_parity();
let output_key: XOnlyPublicKey = p2tr_spend_info.output_key().into();
info!("keypairs_of_interest: \n\tsecret_bytes: {:?} \n\tpubkeys: {:?} \n\tmerkle_root: {}",
keypairs_of_interest.secret_key_bytes().iter().map(|bytes| hex::encode(bytes)).collect::>(), // secret_bytes returns big endian
keypairs_of_interest.public_key_bytes().iter().map(|bytes| hex::encode(bytes)).collect::>(), // serialize returns little endian
merkle_root);
let tap_tree: TapTree = p2tr_builder.clone().try_into_taptree().unwrap();
let mut script_leaves: ScriptLeaves = tap_tree.script_leaves();
let script_leaf = script_leaves
.find(|leaf| leaf.script() == script_buf_of_interest.as_script())
.expect("Script leaf not found");
let leaf_script = script_leaf.script().to_hex_string();
let merkle_branch: &TaprootMerkleBranch = script_leaf.merkle_branch();
debug!("Leaf script: {}, merkle branch: {:?}", leaf_script, merkle_branch);
let control_block: ControlBlock = ControlBlock{
leaf_version: LeafVersion::TapScript,
output_key_parity: output_key_parity,
internal_key: internal_xonly_pubkey,
merkle_branch: merkle_branch.clone(),
};
let control_block_hex: String = hex::encode(control_block.serialize());
// Not a requirement but useful to demonstrate what Bitcoin Core does as the verifier when spending from a p2tr UTXO
let verify: bool = verify_taproot_commitment(control_block_hex.clone(), output_key, script_leaf.script());
info!("verify_taproot_commitment: {}", verify);
return TaptreeReturn {
leaf_script_priv_keys_hex: keypairs_of_interest.secret_key_bytes()
.into_iter()
.map(|bytes| hex::encode(bytes))
.collect(),
leaf_script_hex: leaf_script,
tree_root_hex: hex::encode(merkle_root.to_byte_array()),
control_block_hex: control_block_hex,
leaf_script_type: actual_leaf_type.to_string(),
};
}
/// Parses the BITCOIN_NETWORK environment variable and returns the corresponding Network.
/// Defaults to Network::Regtest if the environment variable is not set or has an invalid value.
pub fn get_bitcoin_network() -> Network {
let mut bitcoin_network: Network = Network::Regtest;
// Check for BITCOIN_NETWORK environment variable and override if set
if let Ok(network_str) = std::env::var("BITCOIN_NETWORK") {
bitcoin_network = match network_str.to_lowercase().as_str() {
"regtest" => Network::Regtest,
"testnet" => Network::Testnet,
"signet" => Network::Signet,
_ => {
debug!("Invalid BITCOIN_NETWORK value '{}', using default Regtest network", network_str);
Network::Regtest
}
};
}
bitcoin_network
}
pub fn create_p2mr_utxo(merkle_root_hex: String) -> UtxoReturn {
let merkle_root_bytes= hex::decode(merkle_root_hex.clone()).unwrap();
let merkle_root: TapNodeHash = TapNodeHash::from_byte_array(merkle_root_bytes.try_into().unwrap());
/* commit (in scriptPubKey) to the merkle root of all the script path leaves. ie:
This output key is what gets committed to in the final P2MR address (ie: scriptPubKey)
*/
let script_buf: P2mrScriptBuf = P2mrScriptBuf::new_p2mr(merkle_root);
let script: &Script = script_buf.as_script();
let script_pubkey = script.to_hex_string();
let bitcoin_network = get_bitcoin_network();
// derive bech32m address and verify against test vector
// p2mr address is comprised of network HRP + WitnessProgram (version + program)
let bech32m_address = Address::p2mr(Some(merkle_root), bitcoin_network);
return UtxoReturn {
script_pubkey_hex: script_pubkey,
bech32m_address: bech32m_address.to_string(),
bitcoin_network,
};
}
// Given script path p2tr or p2mr UTXO details, spend to p2wpkh
pub fn pay_to_p2wpkh_tx(
funding_tx_id_bytes: Vec,
funding_utxo_index: u32,
funding_utxo_amount_sats: u64,
funding_script_pubkey_bytes: Vec,
control_block_bytes: Vec,
leaf_script_bytes: Vec,
leaf_script_priv_keys_bytes: Vec>, // Changed to support multiple private keys
spend_output_pubkey_hash_bytes: Vec,
spend_output_amount_sats: u64,
leaf_script_type: LeafScriptType
) -> SpendDetails {
let mut txid_little_endian = funding_tx_id_bytes.clone(); // initially in big endian format
txid_little_endian.reverse(); // convert to little endian format
// vin: Create TxIn from the input utxo
// Details of this input tx are not known at this point
let input_tx_in = bitcoin::TxIn {
previous_output: OutPoint {
txid: bitcoin::Txid::from_slice(&txid_little_endian).unwrap(), // bitcoin::Txid expects the bytes in little-endian format
vout: funding_utxo_index,
},
script_sig: ScriptBuf::new(), // Empty for segwit transactions - script goes in witness
sequence: Sequence::MAX, // Default sequence, allows immediate spending (no RBF or timelock)
witness: bitcoin::Witness::new(), // Empty for now, will be filled with signature and pubkey after signing
};
let spend_wpubkey_hash = WPubkeyHash::from_byte_array(spend_output_pubkey_hash_bytes.try_into().unwrap());
let spend_output: TxOut = TxOut {
value: Amount::from_sat(spend_output_amount_sats),
script_pubkey: ScriptBuf::new_p2wpkh(&spend_wpubkey_hash),
};
// The spend tx to eventually be signed and broadcast
let mut unsigned_spend_tx = Transaction {
version: bitcoin::transaction::Version::TWO,
lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
input: vec![input_tx_in],
output: vec![spend_output],
};
// Create the leaf hash
let leaf_script = ScriptBuf::from_bytes(leaf_script_bytes.clone());
let leaf_hash: TapLeafHash = TapLeafHash::from_script(&leaf_script, LeafVersion::TapScript);
/* prevouts parameter tells the sighash algorithm:
1. The value of each input being spent (needed for fee calculation and sighash computation)
2. The scriptPubKey of each input being spent (ie: type of output & how to validate the spend)
*/
let prevouts = vec![TxOut {
value: Amount::from_sat(funding_utxo_amount_sats),
script_pubkey: ScriptBuf::from_bytes(funding_script_pubkey_bytes.clone()),
}];
info!("prevouts: {:?}", prevouts);
let spending_tx_input_index = 0;
// Create SighashCache
// At this point, sighash_cache does not know the values and type of input UTXO
let mut tapscript_sighash_cache = SighashCache::new(&mut unsigned_spend_tx);
// Compute the sighash
let tapscript_sighash: TapSighash = tapscript_sighash_cache.taproot_script_spend_signature_hash(
spending_tx_input_index, // input_index
&Prevouts::All(&prevouts),
leaf_hash,
TapSighashType::All
).unwrap();
info!("sighash: {:?}", tapscript_sighash);
let spend_msg = Message::from(tapscript_sighash);
let mut derived_witness: Witness = Witness::new();
let mut sig_bytes = Vec::new();
match leaf_script_type {
LeafScriptType::SlhDsaOnly => {
if leaf_script_priv_keys_bytes.len() != 1 {
panic!("SlhDsaOnly requires exactly one private key");
}
let secret_key: bitcoinpqc::SecretKey = bitcoinpqc::SecretKey::try_from_slice(
Algorithm::SLH_DSA_128S, &leaf_script_priv_keys_bytes[0]).unwrap();
let signature = sign(&secret_key, spend_msg.as_ref()).expect("Failed to sign with SLH-DSA-128S");
debug!("SlhDsaOnly signature.bytes: {:?}", signature.bytes.len());
let mut sig_bytes_with_sighash = signature.bytes.clone();
sig_bytes_with_sighash.push(TapSighashType::All as u8);
derived_witness.push(&sig_bytes_with_sighash);
sig_bytes = signature.bytes;
},
LeafScriptType::SchnorrOnly => {
if leaf_script_priv_keys_bytes.len() != 1 {
panic!("SchnorrOnly requires exactly one private key");
}
// assumes bytes are in big endian format
let secret_key = SecretKey::from_slice(&leaf_script_priv_keys_bytes[0]).unwrap();
// Spending a p2tr UTXO thus using Schnorr signature
// The aux_rand parameter ensures that signing the same message with the same key produces the same signature
// Otherwise (without providing aux_rand), the secp256k1 library internally generates a random nonce for each signature
let signature: bitcoin::secp256k1::schnorr::Signature = SECP.sign_schnorr_with_aux_rand(
&spend_msg,
&secret_key.keypair(&SECP),
&[0u8; 32] // 32 zero bytes of auxiliary random data
);
sig_bytes = signature.serialize().to_vec();
let mut sig_bytes_with_sighash = sig_bytes.clone();
sig_bytes_with_sighash.push(TapSighashType::All as u8);
derived_witness.push(&sig_bytes_with_sighash);
debug!("SchnorrOnly signature bytes: {:?}", sig_bytes.len());
},
LeafScriptType::ConcatenatedSchnorrAndSlhDsaSameLeaf => {
if leaf_script_priv_keys_bytes.len() != 2 {
panic!("SchnorrAndSlhDsa requires exactly two private keys (Schnorr first, then SLH-DSA)");
}
// Generate Schnorr signature (first key)
let schnorr_secret_key = SecretKey::from_slice(&leaf_script_priv_keys_bytes[0]).unwrap();
let schnorr_signature: bitcoin::secp256k1::schnorr::Signature = SECP.sign_schnorr_with_aux_rand(
&spend_msg,
&schnorr_secret_key.keypair(&SECP),
&[0u8; 32] // 32 zero bytes of auxiliary random data
);
// Build combined signature for return value (without sighash bytes)
let mut combined_sig_bytes = schnorr_signature.serialize().to_vec();
debug!("SchnorrAndSlhDsa schnorr_sig_bytes: {:?}", combined_sig_bytes.len());
// Generate SLH-DSA signature (second key)
let slh_dsa_secret_key: bitcoinpqc::SecretKey = bitcoinpqc::SecretKey::try_from_slice(
Algorithm::SLH_DSA_128S, &leaf_script_priv_keys_bytes[1]).unwrap();
// Debug: Print the private key being used for signature creation
info!("SLH-DSA DEBUG: Using private key for signature creation: {}", hex::encode(&leaf_script_priv_keys_bytes[1]));
let slh_dsa_signature = sign(&slh_dsa_secret_key, spend_msg.as_ref()).expect("Failed to sign with SLH-DSA-128S");
debug!("SchnorrAndSlhDsa slh_dsa_signature.bytes: {:?}", slh_dsa_signature.bytes.len());
// Add SLH-DSA signature to combined signature for return value
combined_sig_bytes.extend_from_slice(&slh_dsa_signature.bytes);
sig_bytes = combined_sig_bytes;
// Build witness with sighash bytes
let mut witness_sig_bytes = schnorr_signature.serialize().to_vec();
witness_sig_bytes.push(TapSighashType::All as u8);
witness_sig_bytes.extend_from_slice(&slh_dsa_signature.bytes);
witness_sig_bytes.push(TapSighashType::All as u8);
derived_witness.push(&witness_sig_bytes);
}
LeafScriptType::Mixed => {
// Mixed is not a valid type for spending - the actual leaf type should be used
panic!("LeafScriptType::Mixed is not valid for spending. Use the actual leaf type (SchnorrOnly or SlhDsaOnly).");
}
LeafScriptType::NotApplicable => {
panic!("LeafScriptType::NotApplicable is not applicable");
}
}
// Note: sighash byte is now appended to signatures, not as separate witness element
derived_witness.push(&leaf_script_bytes);
derived_witness.push(&control_block_bytes);
let derived_witness_vec: Vec = derived_witness.iter().flatten().cloned().collect();
// Update the witness data for the tx's first input (index 0)
*tapscript_sighash_cache.witness_mut(spending_tx_input_index).unwrap() = derived_witness;
// Get the signed transaction.
let signed_tx_obj: &mut Transaction = tapscript_sighash_cache.into_transaction();
let tx_hex = bitcoin::consensus::encode::serialize_hex(&signed_tx_obj);
return SpendDetails {
tx_hex,
sighash: tapscript_sighash.as_byte_array().to_vec(),
sig_bytes: sig_bytes,
derived_witness_vec: derived_witness_vec,
};
}
pub fn create_p2tr_utxo(merkle_root_hex: String, internal_pubkey_hex: String) -> UtxoReturn {
let merkle_root_bytes= hex::decode(merkle_root_hex.clone()).unwrap();
let merkle_root: TapNodeHash = TapNodeHash::from_byte_array(merkle_root_bytes.try_into().unwrap());
let pub_key_string = format!("02{}", internal_pubkey_hex);
let internal_pubkey: PublicKey = pub_key_string.parse::().unwrap();
let internal_xonly_pubkey: XOnlyPublicKey = internal_pubkey.inner.into();
let script_buf: ScriptBuf = ScriptBuf::new_p2tr(&SECP, internal_xonly_pubkey, Option::Some(merkle_root));
let script: &Script = script_buf.as_script();
let script_pubkey = script.to_hex_string();
let bitcoin_network = get_bitcoin_network();
// 4) derive bech32m address and verify against test vector
// p2mr address is comprised of network HRP + WitnessProgram (version + program)
let bech32m_address = Address::p2tr(
&SECP,
internal_xonly_pubkey,
Option::Some(merkle_root),
bitcoin_network
);
return UtxoReturn {
script_pubkey_hex: script_pubkey,
bech32m_address: bech32m_address.to_string(),
bitcoin_network,
};
}
// https://learnmeabitcoin.com/technical/upgrades/taproot/#examples
pub fn tagged_hash(tag: &str, data: &[u8]) -> String {
// Create a hash of the tag first
let tag_hash = sha256::Hash::hash(tag.as_bytes());
// Create preimage: tag_hash || tag_hash || message
// tag_hash is prefixed twice so that the prefix is 64 bytes in total
let mut preimage = sha256::Hash::engine();
preimage.write_all(&tag_hash.to_byte_array()).unwrap(); // First tag hash
preimage.write_all(&tag_hash.to_byte_array()).unwrap(); // Second tag hash
preimage.write_all(data).unwrap(); // Message data
let hash = sha256::Hash::from_engine(preimage).to_byte_array();
hex::encode(hash)
}
pub fn serialize_script(script: &Vec) -> Vec {
// get length of script as number of bytes
let length = script.len();
// return script with compact size prepended
let mut result = compact_size(length as u64);
result.extend_from_slice(&script);
result
}
/// Encodes an integer into Bitcoin's compact size format
/// Returns a Vec containing the encoded bytes
fn compact_size(n: u64) -> Vec {
if n <= 252 {
vec![n as u8]
} else if n <= 0xffff {
let mut result = vec![0xfd];
result.extend_from_slice(&(n as u16).to_le_bytes());
result
} else if n <= 0xffffffff {
let mut result = vec![0xfe];
result.extend_from_slice(&(n as u32).to_le_bytes());
result
} else {
let mut result = vec![0xff];
result.extend_from_slice(&n.to_le_bytes());
result
}
}
pub fn acquire_schnorr_keypair() -> UnifiedKeypair {
/* OsRng typically draws from the OS's entropy pool (hardware random num generators, system events, etc), ie:
* 1. $ cat /proc/sys/kernel/random/entropy_avail
* 2. $ sudo dmesg | grep -i "random\|rng\|entropy"
The Linux kernel's RNG (/dev/random and /dev/urandom) typically combines multiple entropy sources: ie:
* Hardware RNG (if available)
* CPU RNG instructions (RDRAND/RDSEED)
* Hardware events (disk I/O, network packets, keyboard/mouse input)
* Timer jitter
* Interrupt timing
*/
let keypair = Keypair::new(&SECP, &mut OsRng);
let privkey: SecretKey = keypair.secret_key();
let pubkey: (XOnlyPublicKey, Parity) = XOnlyPublicKey::from_keypair(&keypair);
UnifiedKeypair::new_schnorr(privkey, pubkey.0)
}
pub fn verify_schnorr_signature_via_bytes(signature: &[u8], message: &[u8], pubkey_bytes: &[u8]) -> bool {
// schnorr is 64 bytes so remove possible trailing Sighash Type byte if present
let mut sig_bytes = signature.to_vec();
if sig_bytes.len() == 65 {
sig_bytes.pop(); // Remove the last byte
}
let signature = bitcoin::secp256k1::schnorr::Signature::from_slice(&sig_bytes).unwrap();
let message = Message::from_digest_slice(message).unwrap();
let pubkey = XOnlyPublicKey::from_slice(pubkey_bytes).unwrap();
verify_schnorr_signature(signature, message, pubkey)
}
pub fn verify_slh_dsa_via_bytes(signature: &[u8], message: &[u8], pubkey_bytes: &[u8]) -> bool {
// Remove possible trailing Sighash Type byte if present (SLH-DSA-128S is 7856 bytes, so 7857 would indicate SIGHASH byte)
let mut sig_bytes = signature.to_vec();
if sig_bytes.len() == 7857 {
sig_bytes.pop(); // Remove the last byte
}
info!("verify_slh_dsa_via_bytes: signature length: {:?}, message: {:?}, pubkey_bytes: {:?}",
sig_bytes.len(),
hex::encode(message),
hex::encode(pubkey_bytes));
let signature = bitcoinpqc::Signature::try_from_slice(Algorithm::SLH_DSA_128S, &sig_bytes).unwrap();
let public_key: bitcoinpqc::PublicKey = bitcoinpqc::PublicKey::try_from_slice(Algorithm::SLH_DSA_128S, pubkey_bytes).unwrap();
verify(&public_key, message, &signature).is_ok()
}
pub fn verify_schnorr_signature(mut signature: Signature, message: Message, pubkey: XOnlyPublicKey) -> bool {
// schnorr is 64 bytes so remove possible trailing Sighash Type byte if present
if signature.serialize().to_vec().len() == 65 {
let mut sig_bytes = signature.serialize().to_vec();
sig_bytes.pop(); // Remove the last byte
signature = bitcoin::secp256k1::schnorr::Signature::from_slice(&sig_bytes).unwrap();
}
let is_valid: bool = SECP.verify_schnorr(&signature, &message, &pubkey).is_ok();
if !is_valid {
error!("verify schnorr failed:\n\tsignature: {:?}\n\tmessage: {:?}\n\tpubkey: {:?}",
signature,
message,
hex::encode(pubkey.serialize()));
}
is_valid
}
/* 1. Re-constructs merkle_root from merkle_path (found in control_block) and provided script.
2. Determines the parity of the output key via the control byte (found in the control block).
- the parity bit indicates whether the output key has an even or odd Y-coordinate
3. Computes the tap tweak hash using the internal key and reconstructed merkle root.
- tap_tweak_hash = tagged_hash("TapTweak", internal_key || merkle_root)
4. Verifies that the provided output key can be derived from the internal key using the tweak.
- tap_tweak_hash = tagged_hash("TapTweak", internal_key || merkle_root)
5. This proves the script is committed to in the taptree described by the output key.
*/
pub fn verify_taproot_commitment(control_block_hex: String, output_key: XOnlyPublicKey, script: &Script) -> bool {
let control_block_bytes = hex::decode(control_block_hex).unwrap();
let control_block: ControlBlock = ControlBlock::decode(&control_block_bytes).unwrap();
return control_block.verify_taproot_commitment(&SECP, output_key, script);
}
fn acquire_slh_dsa_keypair() -> UnifiedKeypair {
/*
In SPHINCS+ (underlying algorithm of SLH-DSA), the random data is used to:
* Initialize hash function parameters within the key generation
* Seed the Merkle tree construction that forms the public key
* Generate the secret key components that enable signing
*/
let random_data = get_random_bytes(128);
let keypair: KeyPair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data)
.expect("Failed to generate SLH-DSA-128S keypair");
UnifiedKeypair::new_slh_dsa(keypair)
}
fn get_random_bytes(size: usize) -> Vec {
let mut bytes = vec![0u8; size];
rng().fill_bytes(&mut bytes);
bytes
}
================================================
FILE: bip-0360/ref-impl/rust/tests/p2mr_construction.rs
================================================
use std::collections::HashSet;
use bitcoin::{Network, ScriptBuf};
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
use bitcoin::hashes::Hash;
use hex;
use log::debug;
use once_cell::sync::Lazy;
use p2mr_ref::data_structures::{TVScriptTree, TestVector, Direction, TestVectors, UtxoReturn};
use p2mr_ref::error::P2MRError;
use p2mr_ref::{create_p2mr_utxo, tagged_hash};
// This file contains tests that execute against the BIP360 script-path-only test vectors.
static TEST_VECTORS: Lazy = Lazy::new(|| {
let bip360_test_vectors = include_str!("../../common/tests/data/p2mr_construction.json");
let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
assert_eq!(test_vectors.version, 1);
test_vectors
});
static P2TR_USING_V2_WITNESS_VERSION_ERROR: &str = "p2tr_using_v2_witness_version_error";
static P2MR_MISSING_LEAF_SCRIPT_TREE_ERROR_TEST: &str = "p2mr_missing_leaf_script_tree_error";
static P2MR_SINGLE_LEAF_SCRIPT_TREE_TEST: &str = "p2mr_single_leaf_script_tree";
static P2MR_DIFFERENT_VERSION_LEAVES_TEST: &str = "p2mr_different_version_leaves";
static P2MR_TWO_LEAF_SAME_VERSION_TEST: &str = "p2mr_two_leaf_same_version";
static P2MR_THREE_LEAF_COMPLEX_TEST: &str = "p2mr_three_leaf_complex";
static P2MR_THREE_LEAF_ALTERNATIVE_TEST: &str = "p2mr_three_leaf_alternative";
static P2MR_SIMPLE_LIGHTNING_CONTRACT_TEST: &str = "p2mr_simple_lightning_contract";
#[test]
fn test_p2tr_using_v2_witness_version_error() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2TR_USING_V2_WITNESS_VERSION_ERROR).unwrap();
let test_result: anyhow::Result<()> = process_test_vector_p2tr(test_vector);
assert!(matches!(test_result.unwrap_err().downcast_ref::(),
Some(P2MRError::P2trRequiresWitnessVersion1)));
}
// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
#[test]
fn test_p2mr_missing_leaf_script_tree_error() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_MISSING_LEAF_SCRIPT_TREE_ERROR_TEST).unwrap();
let test_result: anyhow::Result<()> = process_test_vector_p2mr(test_vector);
assert!(matches!(test_result.unwrap_err().downcast_ref::(),
Some(P2MRError::MissingScriptTreeLeaf)));
}
// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
#[test]
fn test_p2mr_single_leaf_script_tree() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_SINGLE_LEAF_SCRIPT_TREE_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_different_version_leaves() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_DIFFERENT_VERSION_LEAVES_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_simple_lightning_contract() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_SIMPLE_LIGHTNING_CONTRACT_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_two_leaf_same_version() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_TWO_LEAF_SAME_VERSION_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_three_leaf_complex() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_THREE_LEAF_COMPLEX_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_three_leaf_alternative() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_THREE_LEAF_ALTERNATIVE_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
fn process_test_vector_p2tr(test_vector: &TestVector) -> anyhow::Result<()> {
let script_pubkey_hex = test_vector.expected.script_pubkey.as_ref().unwrap();
let script_pubkey_bytes = hex::decode(script_pubkey_hex).unwrap();
if script_pubkey_bytes[0] != 0x51 {
return Err(P2MRError::P2trRequiresWitnessVersion1.into());
}
Ok(())
}
fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
let tv_script_tree: Option<&TVScriptTree> = test_vector.given.script_tree.as_ref();
let mut tv_leaf_count: u8 = 0;
let mut current_branch_id: u8 = 0;
// TaprootBuilder expects the addition of each leaf script with its associated depth
// It then constructs the binary tree in DFS order, sorting siblings lexicographically & combining them via BIP341's tapbranch_hash
// Use of TaprootBuilder avoids user error in constructing branches manually and ensures Merkle tree correctness and determinism
let mut p2mr_builder: P2mrBuilder = P2mrBuilder::new();
let mut control_block_data: Vec<(ScriptBuf, LeafVersion)> = Vec::new();
// 1) traverse test vector script tree and add leaves to P2MR builder
if let Some(script_tree) = tv_script_tree {
script_tree.traverse_with_right_subtree_first(0, Direction::Root,&mut |node, depth, direction| {
if let TVScriptTree::Leaf(tv_leaf) = node {
let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap();
// NOTE: IOT to execute script_info.control_block(..), will add these to a vector
let tv_leaf_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap();
control_block_data.push((tv_leaf_script_buf.clone(), tv_leaf_version));
let mut modified_depth = depth + 1;
if direction == Direction::Root {
modified_depth = depth;
}
debug!("traverse_with_depth: leaf_count: {}, depth: {}, modified_depth: {}, direction: {}, tv_leaf_script: {}",
tv_leaf_count, depth, modified_depth, direction, tv_leaf.script);
// NOTE: Some of the the test vectors in this project specify leaves with non-standard versions (ie: 250 / 0xfa)
p2mr_builder = p2mr_builder.clone().add_leaf_with_ver(depth, tv_leaf_script_buf.clone(), tv_leaf_version)
.unwrap_or_else(|e| {
panic!("Failed to add leaf: {:?}", e);
});
tv_leaf_count += 1;
} else if let TVScriptTree::Branch { left, right } = node {
// No need to calculate branch hash.
// TaprootBuilder does this for us.
debug!("branch_count: {}, depth: {}, direction: {}", current_branch_id, depth, direction);
current_branch_id += 1;
}
});
}else {
return Err(P2MRError::MissingScriptTreeLeaf.into());
}
let spend_info: P2mrSpendInfo = p2mr_builder.clone()
.finalize()
.unwrap_or_else(|e| {
panic!("finalize failed: {:?}", e);
});
let derived_merkle_root: TapNodeHash = spend_info.merkle_root.unwrap();
// 2) verify derived merkle root against test vector
let test_vector_merkle_root = test_vector.intermediary.merkle_root.as_ref().unwrap();
assert_eq!(
derived_merkle_root.to_string(),
*test_vector_merkle_root,
"Merkle root mismatch"
);
debug!("just passed merkle root validation: {}", test_vector_merkle_root);
let test_vector_leaf_hashes_vec: Vec = test_vector.intermediary.leaf_hashes.clone();
let test_vector_leaf_hash_set: HashSet = test_vector_leaf_hashes_vec.iter().cloned().collect();
let test_vector_control_blocks_vec = &test_vector.expected.script_path_control_blocks;
let test_vector_control_blocks_set: HashSet = test_vector_control_blocks_vec.as_ref().unwrap().iter().cloned().collect();
let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let script_leaves: ScriptLeaves = tap_tree.script_leaves();
// TO-DO: Investigate why the ordering of script leaves seems to be reverse of test vectors.
// 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
for derived_leaf in script_leaves {
let version = derived_leaf.version();
let script = derived_leaf.script();
let merkle_branch: &TaprootMerkleBranch = derived_leaf.merkle_branch();
let derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array());
assert!(
test_vector_leaf_hash_set.contains(&leaf_hash),
"Leaf hash not found in expected set for {}", leaf_hash
);
debug!("just passed leaf_hash validation: {}", leaf_hash);
// Each leaf in the script tree has a corresponding control block.
// Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
// https://learnmeabitcoin.com/technical/upgrades/taproot/#script-path-spend-control-block
// The control block, which includes the Merkle path, must be 33 + 32 * n bytes, where n is the number of Merkle path hashes (n ≥ 0).
// There is no consensus limit on n, but large Merkle trees increase the witness size, impacting block weight.
// NOTE: Control blocks could have also been obtained from spend_info.control_block(..) using the data in control_block_data
debug!("merkle_branch nodes: {:?}", merkle_branch);
let derived_control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(),
};
let serialized_control_block = derived_control_block.serialize();
debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}",
derived_control_block,
merkle_branch.len(),
derived_control_block.size(),
serialized_control_block.len());
let derived_serialized_control_block = hex::encode(serialized_control_block);
assert!(
test_vector_control_blocks_set.contains(&derived_serialized_control_block),
"Control block mismatch: {}, expected: {:?}", derived_serialized_control_block, test_vector_control_blocks_set
);
debug!("leaf_hash: {}, derived_serialized_control_block: {}", leaf_hash, derived_serialized_control_block);
}
let p2mr_utxo_return: UtxoReturn = create_p2mr_utxo(derived_merkle_root.to_string());
assert_eq!(
p2mr_utxo_return.script_pubkey_hex,
*test_vector.expected.script_pubkey.as_ref().unwrap(),
"Script pubkey mismatch"
);
debug!("just passed script_pubkey validation. script_pubkey = {}", p2mr_utxo_return.script_pubkey_hex);
let bech32m_address: String = p2mr_utxo_return.bech32m_address;
debug!("derived bech32m address for bitcoin_network: {} : {}", p2mr_utxo_return.bitcoin_network, bech32m_address);
if p2mr_utxo_return.bitcoin_network == Network::Bitcoin {
assert_eq!(bech32m_address, *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
}
Ok(())
}
================================================
FILE: bip-0360/ref-impl/rust/tests/p2mr_pqc_construction.rs
================================================
use std::collections::HashSet;
use bitcoin::{Network, ScriptBuf};
use bitcoin::taproot::{LeafVersion, TapTree, ScriptLeaves, TapLeafHash, TaprootMerkleBranch, TapNodeHash};
use bitcoin::p2mr::{P2mrBuilder, P2mrControlBlock, P2mrSpendInfo};
use bitcoin::hashes::Hash;
use hex;
use log::debug;
use once_cell::sync::Lazy;
use p2mr_ref::data_structures::{TVScriptTree, TestVector, Direction, TestVectors, UtxoReturn};
use p2mr_ref::error::P2MRError;
use p2mr_ref::{create_p2mr_utxo, tagged_hash};
// This file contains tests that execute against the BIP360 script-path-only test vectors.
static TEST_VECTORS: Lazy = Lazy::new(|| {
let bip360_test_vectors = include_str!("../../common/tests/data/p2mr_pqc_construction.json");
let test_vectors: TestVectors = serde_json::from_str(bip360_test_vectors).unwrap();
assert_eq!(test_vectors.version, 1);
test_vectors
});
static P2MR_MISSING_LEAF_SCRIPT_TREE_ERROR_TEST: &str = "p2mr_missing_leaf_script_tree_error";
static P2MR_SINGLE_LEAF_SCRIPT_TREE_TEST: &str = "p2mr_single_leaf_script_tree";
static P2MR_DIFFERENT_VERSION_LEAVES_TEST: &str = "p2mr_different_version_leaves";
static P2MR_TWO_LEAF_SAME_VERSION_TEST: &str = "p2mr_two_leaf_same_version";
static P2MR_THREE_LEAF_COMPLEX_TEST: &str = "p2mr_three_leaf_complex";
static P2MR_THREE_LEAF_ALTERNATIVE_TEST: &str = "p2mr_three_leaf_alternative";
static P2MR_SIMPLE_LIGHTNING_CONTRACT_TEST: &str = "p2mr_simple_lightning_contract";
// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
#[test]
fn test_p2mr_pqc_missing_leaf_script_tree_error() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_MISSING_LEAF_SCRIPT_TREE_ERROR_TEST).unwrap();
let test_result: anyhow::Result<()> = process_test_vector_p2mr(test_vector);
assert!(matches!(test_result.unwrap_err().downcast_ref::(),
Some(P2MRError::MissingScriptTreeLeaf)));
}
// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
#[test]
fn test_p2mr_pqc_single_leaf_script_tree() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_SINGLE_LEAF_SCRIPT_TREE_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_pqc_different_version_leaves() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_DIFFERENT_VERSION_LEAVES_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_pqc_simple_lightning_contract() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_SIMPLE_LIGHTNING_CONTRACT_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_pqc_two_leaf_same_version() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_TWO_LEAF_SAME_VERSION_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_pqc_three_leaf_complex() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_THREE_LEAF_COMPLEX_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
#[test]
fn test_p2mr_pqc_three_leaf_alternative() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let test_vectors = &*TEST_VECTORS;
let test_vector = test_vectors.test_vector_map.get(P2MR_THREE_LEAF_ALTERNATIVE_TEST).unwrap();
process_test_vector_p2mr(test_vector).unwrap();
}
fn process_test_vector_p2mr(test_vector: &TestVector) -> anyhow::Result<()> {
let tv_script_tree: Option<&TVScriptTree> = test_vector.given.script_tree.as_ref();
let mut tv_leaf_count: u8 = 0;
let mut current_branch_id: u8 = 0;
// TaprootBuilder expects the addition of each leaf script with its associated depth
// It then constructs the binary tree in DFS order, sorting siblings lexicographically & combining them via BIP341's tapbranch_hash
// Use of TaprootBuilder avoids user error in constructing branches manually and ensures Merkle tree correctness and determinism
let mut p2mr_builder: P2mrBuilder = P2mrBuilder::new();
let mut control_block_data: Vec<(ScriptBuf, LeafVersion)> = Vec::new();
// 1) traverse test vector script tree and add leaves to P2MR builder
if let Some(script_tree) = tv_script_tree {
script_tree.traverse_with_right_subtree_first(0, Direction::Root,&mut |node, depth, direction| {
if let TVScriptTree::Leaf(tv_leaf) = node {
let tv_leaf_script_bytes = hex::decode(&tv_leaf.script).unwrap();
// NOTE: IOT to execute script_info.control_block(..), will add these to a vector
let tv_leaf_script_buf = ScriptBuf::from_bytes(tv_leaf_script_bytes.clone());
let tv_leaf_version = LeafVersion::from_consensus(tv_leaf.leaf_version).unwrap();
control_block_data.push((tv_leaf_script_buf.clone(), tv_leaf_version));
let mut modified_depth = depth + 1;
if direction == Direction::Root {
modified_depth = depth;
}
debug!("traverse_with_depth: leaf_count: {}, depth: {}, modified_depth: {}, direction: {}, tv_leaf_script: {}",
tv_leaf_count, depth, modified_depth, direction, tv_leaf.script);
// NOTE: Some of the the test vectors in this project specify leaves with non-standard versions (ie: 250 / 0xfa)
p2mr_builder = p2mr_builder.clone().add_leaf_with_ver(depth, tv_leaf_script_buf.clone(), tv_leaf_version)
.unwrap_or_else(|e| {
panic!("Failed to add leaf: {:?}", e);
});
tv_leaf_count += 1;
} else if let TVScriptTree::Branch { left, right } = node {
// No need to calculate branch hash.
// TaprootBuilder does this for us.
debug!("branch_count: {}, depth: {}, direction: {}", current_branch_id, depth, direction);
current_branch_id += 1;
}
});
}else {
return Err(P2MRError::MissingScriptTreeLeaf.into());
}
let spend_info: P2mrSpendInfo = p2mr_builder.clone()
.finalize()
.unwrap_or_else(|e| {
panic!("finalize failed: {:?}", e);
});
let derived_merkle_root: TapNodeHash = spend_info.merkle_root.unwrap();
// 2) verify derived merkle root against test vector
let test_vector_merkle_root = test_vector.intermediary.merkle_root.as_ref().unwrap();
assert_eq!(
derived_merkle_root.to_string(),
*test_vector_merkle_root,
"Merkle root mismatch"
);
debug!("just passed merkle root validation: {}", test_vector_merkle_root);
let test_vector_leaf_hashes_vec: Vec = test_vector.intermediary.leaf_hashes.clone();
let test_vector_leaf_hash_set: HashSet = test_vector_leaf_hashes_vec.iter().cloned().collect();
let test_vector_control_blocks_vec = &test_vector.expected.script_path_control_blocks;
let test_vector_control_blocks_set: HashSet = test_vector_control_blocks_vec.as_ref().unwrap().iter().cloned().collect();
let tap_tree: TapTree = p2mr_builder.clone().into_inner().try_into_taptree().unwrap();
let script_leaves: ScriptLeaves = tap_tree.script_leaves();
// TO-DO: Investigate why the ordering of script leaves seems to be reverse of test vectors.
// 3) Iterate through leaves of derived script tree and verify both script leaf hashes and control blocks
for derived_leaf in script_leaves {
let version = derived_leaf.version();
let script = derived_leaf.script();
let merkle_branch: &TaprootMerkleBranch = derived_leaf.merkle_branch();
let derived_leaf_hash: TapLeafHash = TapLeafHash::from_script(script, version);
let leaf_hash = hex::encode(derived_leaf_hash.as_raw_hash().to_byte_array());
assert!(
test_vector_leaf_hash_set.contains(&leaf_hash),
"Leaf hash not found in expected set for {}", leaf_hash
);
debug!("just passed leaf_hash validation: {}", leaf_hash);
// Each leaf in the script tree has a corresponding control block.
// Specific to P2TR, the 3 sections of the control block (control byte, public key & merkle path) are highlighted here:
// https://learnmeabitcoin.com/technical/upgrades/taproot/#script-path-spend-control-block
// The control block, which includes the Merkle path, must be 33 + 32 * n bytes, where n is the number of Merkle path hashes (n ≥ 0).
// There is no consensus limit on n, but large Merkle trees increase the witness size, impacting block weight.
// NOTE: Control blocks could have also been obtained from spend_info.control_block(..) using the data in control_block_data
debug!("merkle_branch nodes: {:?}", merkle_branch);
let derived_control_block: P2mrControlBlock = P2mrControlBlock{
merkle_branch: merkle_branch.clone(),
};
let serialized_control_block = derived_control_block.serialize();
debug!("derived_control_block: {:?}, merkle_branch size: {}, control_block size: {}, serialized size: {}",
derived_control_block,
merkle_branch.len(),
derived_control_block.size(),
serialized_control_block.len());
let derived_serialized_control_block = hex::encode(serialized_control_block);
assert!(
test_vector_control_blocks_set.contains(&derived_serialized_control_block),
"Control block mismatch: {}, expected: {:?}", derived_serialized_control_block, test_vector_control_blocks_set
);
debug!("leaf_hash: {}, derived_serialized_control_block: {}", leaf_hash, derived_serialized_control_block);
}
let p2mr_utxo_return: UtxoReturn = create_p2mr_utxo(derived_merkle_root.to_string());
assert_eq!(
p2mr_utxo_return.script_pubkey_hex,
*test_vector.expected.script_pubkey.as_ref().unwrap(),
"Script pubkey mismatch"
);
debug!("just passed script_pubkey validation. script_pubkey = {}", p2mr_utxo_return.script_pubkey_hex);
let bech32m_address: String = p2mr_utxo_return.bech32m_address;
debug!("derived bech32m address for bitcoin_network: {} : {}", p2mr_utxo_return.bitcoin_network, bech32m_address);
if p2mr_utxo_return.bitcoin_network == Network::Bitcoin {
assert_eq!(bech32m_address, *test_vector.expected.bip350_address.as_ref().unwrap(), "Bech32m address mismatch.");
}
Ok(())
}
================================================
FILE: bip-0360/ref-impl/rust/tests/p2mr_spend.rs
================================================
use log::info;
use bitcoin::blockdata::witness::Witness;
use p2mr_ref::{ pay_to_p2wpkh_tx, serialize_script };
use p2mr_ref::data_structures::{SpendDetails, LeafScriptType};
/* The rust-bitcoin crate does not provide a single high-level API that builds the full Taproot script-path witness stack for you.
It does expose all the necessary types and primitives to build it manually and correctly.
*/
// https://learnmeabitcoin.com/technical/upgrades/taproot/#example-2-script-path-spend-simple
#[test]
fn test_script_path_spend_simple() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let script_inputs_count = hex::decode("03").unwrap();
let script_inputs_bytes: Vec = hex::decode("08").unwrap();
let leaf_script_bytes: Vec = hex::decode("5887").unwrap();
let control_block_bytes: Vec =
hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
let test_witness_bytes: Vec = hex::decode(
"03010802588721c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329",
)
.unwrap();
let mut derived_witness: Witness = Witness::new();
derived_witness.push(script_inputs_count);
derived_witness.push(serialize_script(&script_inputs_bytes));
derived_witness.push(serialize_script(&leaf_script_bytes));
derived_witness.push(serialize_script(&control_block_bytes));
info!("witness: {:?}", derived_witness);
let derived_witness_vec: Vec = derived_witness.iter().flatten().cloned().collect();
assert_eq!(derived_witness_vec, test_witness_bytes);
}
// Inspired by: https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature
// Spends from a p2mr UTXO to a p2wpk UTXO
#[test]
fn test_script_path_spend_signatures() {
let _ = env_logger::try_init(); // Use try_init to avoid reinitialization error
let funding_tx_id_bytes: Vec =
hex::decode("d1c40446c65456a9b11a9dddede31ee34b8d3df83788d98f690225d2958bfe3c").unwrap();
// The input index of the funding tx
let funding_tx_index: u32 = 0;
let funding_utxo_amount_sats: u64 = 20000;
// OP_PUSHBYTES_32 6d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0 OP_CHECKSIG
let input_leaf_script_bytes: Vec =
hex::decode("206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0ac").unwrap();
// Modified from learnmeabitcoin example
// Changed from c0 to c1 control byte to reflect p2mr specification: The parity bit of the control byte is always 1 since P2MR does not have a key-spend path.
let input_control_block_bytes: Vec =
hex::decode("c1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
let input_script_pubkey_bytes: Vec =
hex::decode("5120f3778defe5173a9bf7169575116224f961c03c725c0e98b8da8f15df29194b80")
.unwrap();
let input_script_priv_key_bytes: Vec = hex::decode("9b8de5d7f20a8ebb026a82babac3aa47a008debbfde5348962b2c46520bd5189").unwrap();
// Convert to Vec> format expected by the function
let input_script_priv_keys_bytes: Vec> = vec![input_script_priv_key_bytes];
// https://learnmeabitcoin.com/explorer/tx/797505b104b5fb840931c115ea35d445eb1f64c9279bf23aa5bb4c3d779da0c2#outputs
let spend_output_pubkey_bytes: Vec = hex::decode("0de745dc58d8e62e6f47bde30cd5804a82016f9e").unwrap();
let spend_output_amount_sats: u64 = 15000;
let test_sighash_bytes: Vec = hex::decode("752453d473e511a0da2097d664d69fe5eb89d8d9d00eab924b42fc0801a980c9").unwrap();
let test_signature_bytes: Vec = hex::decode("01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f").unwrap();
// Modified from learnmeabitcoin example
// Changed from c0 to c1 control byte to reflect p2mr specification: The parity bit of the control byte is always 1 since P2MR does not have a key-spend path.
let test_witness_bytes: Vec = hex::decode("01769105cbcbdcaaee5e58cd201ba3152477fda31410df8b91b4aee2c4864c7700615efb425e002f146a39ca0a4f2924566762d9213bd33f825fad83977fba7f01206d4ddc0e47d2e8f82cbe2fc2d0d749e7bd3338112cecdc76d8f831ae6620dbe0acc1924c163b385af7093440184af6fd6244936d1288cbb41cc3812286d3f83a3329").unwrap();
let result: SpendDetails = pay_to_p2wpkh_tx(funding_tx_id_bytes,
funding_tx_index,
funding_utxo_amount_sats,
input_script_pubkey_bytes,
input_control_block_bytes,
input_leaf_script_bytes,
input_script_priv_keys_bytes, // Now passing Vec> format
spend_output_pubkey_bytes,
spend_output_amount_sats,
LeafScriptType::SchnorrOnly // This test uses a Schnorr signature
);
assert_eq!(result.sighash.as_slice(), test_sighash_bytes.as_slice(), "sighash mismatch");
assert_eq!(result.sig_bytes, test_signature_bytes, "signature mismatch");
assert_eq!(result.derived_witness_vec, test_witness_bytes, "derived_witness mismatch");
}
================================================
FILE: bip-0360.mediawiki
================================================
==Introduction==
===Abstract===
This document proposes a new output type: Pay-to-Merkle-Root (P2MR), via a soft fork. P2MR outputs operate with nearly the same functionality as P2TR (Pay-to-Taproot) outputs, but with the key path spend removed.
Through this modification, P2MR outputs allow developers to use script trees and tapscript in a manner that is:
# resistant to long exposure attacks by Cryptographically Relevant Quantum Computers (CRQCs), and
# resistant to future cryptanalytic approaches that may compromise the elliptic curve cryptography (ECC) used by Bitcoin.
It is worth noting that proposed P2MR outputs are only resistant to "long exposure attacks" on elliptic curve cryptography; that is, attacks on keys exposed for time periods longer than needed to confirm a spending transaction.
Protection against more sophisticated quantum attacks, including protection against private key recovery from public keys exposed in the mempool while a transaction is waiting to be confirmed (a.k.a. "short exposure attacks"), may require the introduction of post-quantum signatures in Bitcoin. We believe it's worth considering this path in the future and intend to offer a separate proposal for this purpose upon further research.
This document additionally defines "long exposure" and "short exposure" attacks, and other new terminology in the Glossary.
===Copyright===
This document is licensed under the 3-clause BSD license.
===Motivation===
The primary threat to Bitcoin from Cryptographically Relevant Quantum Computers (CRQCs) is their potential to break the key cryptographic assumption which secures the digital signatures used in Bitcoin.A Cryptographically Relevant Quantum Computer is an ''object'' which is only loosely defined by ''characteristics'' in quantum physics as of today. It could be understood in the context of this BIP and in Bitcoin that it's a ''hardware-agnostic'' computer supposed to have the architecture to keep ''coherent'' a sufficient number of logical qubits to be able to run Shor's algorithm in an efficient fashion. More specifically, [https://arxiv.org/pdf/quant-ph/0301141 Shor's algorithm] enables a CRQC to solve the Discrete Logarithm Problem (DLP) exponentially faster than classical methods.Shor's algorithm is believed to need 10^8 operations to break a 256-bit elliptic curve public key. This allows the derivation of private keys from public keys — a process referred to here as quantum key recovery.Meaning, deriving private keys from public keys via Shor's algorithm While it is unclear when or if CRQCs will become viable in the future, we propose the addition of a quantum-resistant, [[#script-tree-output-type|script tree output type]] for those interested in this level of protection.
While some may balk at the potential threat of quantum computers to Bitcoin given their limited functionality to date, some others — including governments, corporations and some existing and potential Bitcoin users — are concerned about their potential for advancement. The Commercial National Security Algorithm Suite (CNSA) 2.0, for instance, has mandated software and networking equipment to be upgraded to post-quantum schemes by 2030, with browsers and operating systems fully upgraded by 2033. Additionally, according to NIST IR 8547, Elliptic Curve Cryptography (ECC) is planned to be disallowed within the US federal government after 2035 (with an exception made for hybrid cryptography, or the use of ECC and post-quantum algorithms together). These kinds of mandates have triggered concern by some ECC users, including some Bitcoin users who prefer to be prepared out of an abundance of caution.
In the most optimistic case, wherein quantum computers never pose a significant risk to ECC, we understand that the possibility of quantum advancement alone may be influencing adoption and broad confidence in the Bitcoin network. In other words, we believe users' fear of quantum computers may be worth addressing regardless of CRQC viability. Given these concerns, we think it's worth considering simple low risk changes that create options for using Bitcoin in a quantum-resistant way.
As a conservative first step in this effort, we propose Pay-to-Merkle-Root (P2MR), a script tree output that can be used in a quantum resistant manner.
===Long Exposure vs Short Exposure Attacks===
For clarity, this proposal specifically mitigates the risk of long exposure attacks on outputs that support tapscript and script trees. While some other Bitcoin output types, such as P2SH, are safe against long exposure attacks, taproot is not and taproot is the only currently activated output type that supports tapscript and script trees.
A long exposure attack is an attack performed on exposed blockchain data, such as exposed public keys, or the scripts of spent outputs. These are likely to be the earliest quantum attacks made possible on Bitcoin, because attackers will have ample time — as much time as vulnerable keys are exposed — to carry out quantum key recovery.
Short exposure attacks, however, require faster quantum computers, because they must occur within the relatively short time that a transaction is unconfirmed in the mempool.
Bitcoin outputs are generally vulnerable to short exposure attacks, as most Bitcoin transactions require revealing the associated public key when spending. Full protection of outputs from short exposure attacks may require the use of post-quantum signature schemes.
Since long exposure attacks on public keys are likely to be the first quantum-enabled threat to Bitcoin, we propose a script tree output that is resistant to long exposure attacks as a first step in hardening Bitcoin against the potential threat of quantum computers.
The following list of output types describes their long exposure attack vulnerability:
{| class="wikitable"
|-
! Type
! Vulnerable
! Prefix
! Example
|-
| P2PK
| Yes
| Varies
| 02103203b768951584fe9af6d9d9e6ff26a5f76e453212f19ba163774182ab8057f3eac
|-
| P2PKH
| No*
| 1
| 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
|-
| P2MS
| Yes
| Varies
| 52410496ec45f878b62c46c4be8e336dff7cc58df9b502178cc240e...
|-
| P2SH
| No*
| 3
| 3FkhZo7sGNue153xhgqPBcUaBsYvJW6tTx
|-
| P2WPKH
| No*
| bc1q
| bc1qsnh5ktku9ztqeqfr89yrqjd05eh58nah884mku
|-
| P2WSH
| No*
| bc1q
| bc1qvhu3557twysq2ldn6dut6rmaj3qk04p60h9l79wk4lzgy0ca8mfsnffz65
|-
| P2TR
| Yes
| bc1p
| bc1p92aslsnseq786wxfk3ekra90ds9ku47qttupfjsqmmj4z82xdq4q3rr58u
|-
| P2MR
| No*
| bc1z
| bc1zzmv50jjgxxhww6ve4g5zpewrkjqhr06fyujpm20tuezdlxmfphcqfc80ve
|}
The following output types are fundamentally vulnerable to long exposure attacks:
* P2PK outputs (e.g. Satoshi's coins, CPU miners)
* Reused outputs*
* Taproot outputs (starts with bc1p)
* Funds in P2PKH, P2SH, P2WPKH, P2WSH, and P2MR outputs can become vulnerable to long exposure quantum attacks anytime their script reveals a public key.
Note: Extended public keys, commonly known as "xpubs," and wallet descriptors also reveal quantum vulnerable public key information. For further clarification on quantum attack vectors, please refer to the [[#Glossary|Glossary of Terms]].
==Design==
Pay-to-Merkle-Root (P2MR) is a proposed new output type that commits to the root of a script tree. It operates with nearly the same functionality as P2TR (Pay-to-Taproot) outputs, but with the quantum vulnerable key path spend removed.
In other words, P2MR outputs commit to the Merkle root of a script tree without committing to an internal key. The script(s) being committed to, however, may contain a key or key-hash.
This output type is designed to offer users protection against long exposure quantum attacks as well as a practical output type with which post-quantum signatures may be used if such signatures are adopted in the future.
Since P2MR outputs have no key path spend, they omit the Taproot internal key. Instead, a P2MR output includes the 32-byte root of the script tree as defined in [[bip-0341.mediawiki|BIP 341]] hashed with the tag "TapBranch" as shown below.
[[File:bip-0360/media/merkletree.png|thumb|Construction of P2MR script tree root, scriptPubkey, and Witness]]
To construct a P2MR output, we follow the process outlined in [[bip-0341.mediawiki|BIP 341]] to compute the final tapbranch hash, which is the merkle root of the script leaves; however, instead of tweaking the internal key with the root of the Merkle tree (as is the case with P2TR outputs), P2MR outputs commit only to final tapbranch hash, which is tagged, "TapBranch".
D = tagged_hash("TapLeaf", bytes([leaf_version]) + ser_script(script))
CD = tagged_hash("TapBranch", C + D)
CDE = tagged_hash("TapBranch", CD + E)
ABCDE = tagged_hash("TapBranch", AB + CDE)
A P2MR input witness provides the following:
initial stack element 0,
...,
initial stack element N,
leaf script,
control block = [control byte, 32*m byte Merkle path] # m is the depth of the script in the Merkle tree
The initial stack elements of P2MR follow the same rules as P2TR script path spends.
That is, they place elements on the stack to be evaluated by the leaf script.
The control block is a ''1 + 32 * m'' byte array, where the first byte is the control byte and the next ''32 * m'' bytes are the Merkle path to the leaf script. The control byte is the same as the control byte in a P2TR control block, including the 7 bits which are used to specify the leaf version. The parity bit of the control byte is always 1, since P2MR does not have a key path spend. Unlike P2TR, we omit the public key from the control block as it is not needed in P2MR. We maintain support for the optional annex in the witness (see Specification section below for more details).
==Rationale==
Design of the P2MR output type is guided by the following intentions:
1. Minimize changes to the network. We should reuse existing Bitcoin code and preserve existing software behavior, workflows, user expectations and compatibility whenever possible.
P2MR leverages the battle tested P2TR, tapleaf and tapscript code already in Bitcoin, reducing the implementation burden on wallets, exchanges, and libraries that can reuse code they already have. This approach reduces complexity and minimizes implementation risks.
2. Create the safest possible path for the addition of post-quantum signature integrations, in the event that they are used in the future.
Importantly, we are proposing a script tree output, i.e. an output type that supports tapscript, that is resistant to long exposure attacks. While some existing output types are already resistant to long exposure attacks (e.g. P2WSH), no such output type supports tapscript — a feature that may be required for practical implementation of post-quantum signature opcodes.
P2WSH, for instance, does not support tapscript and as such does not support the OP_SUCCESSx opcode update path that will be critical for the integration of post-quantum OP_CHECKSIG opcodes into Bitcoin.OP_SUCCESSx is a mechanism to upgrade tapscript
3. Facilitate gradual integration of quantum resistant features that can be carried out iteratively as quantum computers evolve. This approach encourages responsiveness to the current threat-level, while avoiding heavy-handedness in our reactions to a potential threat.
We designed P2MR with an eye towards integrating post-quantum signatures in the future, without proposing more complex changes while CRQCs are still in their infancy.
===P2MR Trade-Offs===
While P2TR outputs (and the use of key path spend) will remain an option for folks wishing to use them, we aim to be clear about the tradeoffs of using P2MR outputs, which disable the key path spend for the benefit of quantum resistance.
The witness to a P2MR spend is always larger than the witness to a P2TR key path spend. This is because a P2TR key path spend requires only a Schnorr signature in the witness. For P2MR, the witness must include the chosen leaf script, the initial stack, and a control block consisting of the control byte and Merkle path (if any).
That said, the witness to a P2MR spend will always be smaller than the witness to an equivalent P2TR script path spend, because there is no longer any internal key in P2MR that must be revealed in the control block. For a more complete comparison of output type transaction sizes, the "Transaction Size and Fees" section may be reviewed later in this proposal.
Additionally, there is a privacy tradeoff when comparing P2MR and P2TR, which is that users reveal they are spending to a script tree whenever they are using P2MR outputs, since P2MR outputs can only be spent via script path spend. In P2TR when you spend an output as a key path spend, you don't reveal if you have any script path spends. This trade-off only exists when comparing P2TR key path spends to P2MR script path spends; P2TR and P2MR provide the same level of privacy when both are script path spends.
'''Note:''' P2MR and P2TR both provide greater script privacy than P2SH [[bip-0016.mediawiki|BIP 16]] because unused script paths are not revealed.
==Specification==
We define the Pay-to-Merkle-Root (P2MR) output structure as follows:
A P2MR output is similar to a P2TR output (as defined in [[bip-0341.mediawiki|BIP 341]]); however, unlike P2TR outputs, we disable the key path spend for the benefit of quantum resistance by omitting the internal key and the tap tweak step.
A P2MR output is then a SegWit version 2 byte followed by the Merkle root of the script tree as the witness program.
===Address Format===
P2MR outputs use SegWit version 2, resulting in mainnet addresses that start with bc1z, following [[bip-0173.mediawiki|BIP 173]]. Bech32m encoding maps version 2 to the prefix z.
Example P2MR address:
bc1zzmv50jjgxxhww6ve4g5zpewrkjqhr06fyujpm20tuezdlxmfphcqfc80ve
This commits to a 32-byte script tree Merkle root.
===ScriptPubKey===
The scriptPubKey for a P2MR output is:
OP_2 OP_PUSHBYTES_32
Where:
* OP_2 indicates SegWit version 2.
* is the 32-byte Merkle root of the script tree.
===Script Validation===
A P2MR output is a native SegWit output (see [[bip-0141.mediawiki|BIP 141]]) with version 2 and a 32-byte witness program. For the sake of comparison, we have — as much as possible — copied the language verbatim from the script validation section of [[bip-0341.mediawiki|BIP 341]].
* Let ''q'' be the 32-byte array containing the witness program (the second push in the scriptPubKey) which represents the Merkle root of the script tree.
* Fail if the witness stack does not have two or more elements.
* Fail if the witness stack has exactly two elements and the first byte of the last element is 0x50.
* If there are at least three witness elements, and the first byte of the last element is 0x50, this last element is called ''annex a'' and is removed from the witness stack. The annex (or the lack thereof) is always covered by the signature and contributes to transaction weight, but is otherwise ignored during P2MR validation.
* There must be at least two witness elements left.
** Call the second-to-last stack element ''s'', the script (as defined in [[bip-0341.mediawiki|BIP 341]]).
** The last stack element is called the control block ''c'', and must have length ''1 + 32 * m'', for a value of ''m'' that is an integer between 0 and 128, inclusive. Fail if it does not have such a length.
** Let ''v = c[0] & 0xfe'' be the ''leaf version'' (as defined in [[bip-0341.mediawiki|BIP 341]]). To maintain ''leaf version'' encoding compatibility the last bit of c[0] is unused and must be 1.Why set the last bit of c[0] to one? Consider a faulty implementation that deserializes the ''leaf version'' as c[0] rather than c[0] & 0xfe for both P2TR and P2MR. If they test against P2MR outputs and require that last bit is 1, this deserialization bug will cause an immediate error.
** Let ''k0 = hashTapLeaf(v || compact_size(size of s) || s)''; also call it the ''tapleaf hash''.
** For ''j'' in ''[0,1,...,m-1]'':
*** Let ''ej = c[1+32j:33+32j]''.
*** Let ''kj+1'' depend on whether ''kj < ej'' (lexicographically):
**** If ''kj < ej'': ''kj+1 = hashTapBranch(kj || ej)''.
**** If ''kj ≥ ej'': ''kj+1 = hashTapBranch(ej || kj)''.
** Let ''r = km''.
** If ''q ≠ r'', fail.
** Execute the script, according to the script rules specified in BIP 342, using the witness stack elements excluding the script ''s'', the control block ''c'', and the annex ''a'' if present, as initial stack. This implies that for the future leaf versions (non-''0xC0'') the execution must succeed.
The steps above follow the script path spend logic from [[bip-0341.mediawiki|BIP 341]] with the following changes:
* The witness program is the the Merkle root of the script tree and not a tweaked public key. This means that we skip directly to the BIP 341 script path validation.
* We compute the script tree Merkle root ''r'' and compare it directly to the witness program ''q''.
* The control block is ''1 + 32*m'' bytes, instead of ''33 + 32*m'' bytes.
===Common Signature Message Construction===
The [https://learnmeabitcoin.com/technical/upgrades/taproot/#common-signature-message common signature message] construction for P2MR outputs is exactly the same procedure as defined in [[bip-0342.mediawiki#user-content-Common_Signature_Message_Extension|BIP342 Common Signature Message]].
=== Compatibility with BIP 141 ===
By adhering to the SegWit transaction structure and versioning, P2MR outputs are compatible with existing transaction processing rules. Nodes that do not recognize SegWit version 2 will treat these outputs as anyone-can-spend but generally will not relay or mine such transactions.
===Transaction Size and Fees===
All P2MR and P2TR outputs are always the same size. P2MR inputs can be slightly larger or smaller than their equivalent P2TR inputs, depending on the use of key path vs script path spend in the case of P2TR. Let's consider the cases.
====Comparison with P2TR key path spend====
A P2MR witness will be larger than a P2TR witness when the P2TR output is spent via the key path spend. A witness to a P2TR key path spend is simply a signature. P2MR quantum resistance comes from removing the P2TR key path spend. Every P2MR spend is a P2TR script path spend and so requires a script, its input stack and a control block. Consequently, P2MR loses this size advantage of P2TR key path spends in order to gain quantum resistance. If the script tree only has a single leaf script, no Merkle path is needed in the control block, giving us a minimal size control block of 1 byte.
P2MR witness for depth-0 tree (103 bytes):
[count] (1 byte), # Number of elements in the witness
[size] signature (1 + 64 bytes = 65 bytes),
leaf script = [size] [OP_PUSHBYTES_32, 32-byte public key, OP_CHECKSIG] (1 + 1 + 32 + 1 bytes = 35 bytes),
control block = [size] [control byte] [merkle path (empty)] (1 + 1 + 0 bytes = 2 bytes)
P2TR key path spend witness (66 bytes):
[count] (1 byte), # Number of elements in the witness
[size] signature (1 + 64 bytes = 65 bytes)
Thus, the P2MR witness would be 103 - 66 = 37 bytes larger than a P2TR key path spend witness.
If the Merkle tree has more than a single leaf, then the Merkle path must be included in the control block, increasing the size by ''32 * m'' bytes, where m is the depth of the Merkle tree.
While script trees do support leaf scripts of different depths, here we assume the Merkle tree has been constructed such that each leaf is at the same depth.
This would make such witness 37 + 32 * m bytes larger than a P2TR key path spend witness.If ''m >= 8'', then the compact size will use 3 bytes rather than 1 byte
P2MR witness ''(103 + 32*m bytes)'':
[count] (1 byte), # Number of elements in the witness
[size] signature (64 + 1 bytes = 65 bytes),
leaf script = [size] [OP_PUSHBYTES_32, 32-byte public key, OP_CHECKSIG] (34 + 1 bytes = 35 bytes),
control block = [size] [control byte] [Merkle path] (1 + 1 + 32*m = 2 + 32*m bytes)
====Comparison with P2TR script path spend====
A P2MR witness will be smaller than the witness to an equivalent P2TR script path spend. This is because P2MR does not require inclusion of an internal public key in the control block to unlock and spend an output. For this reason, a P2MR witness will always be 32 bytes smaller than an equivalent P2TR script path spend witness.
==Performance Impact==
P2MR is slightly more computationally performant than P2TR script path spends, as the operations to spend a P2MR output is a strict subset of the operations needed to perform a script path spend on a P2TR output.
==Backward Compatibility==
Older wallets and nodes that have not been made compatible with SegWit version 2 and P2MR will not understand these outputs. Per [[bip-0350.mediawiki|BIP 350]] older wallets should be able to spend funds to SegWit version 2 outputs. Users should ensure they are using updated wallets and nodes to receive P2MR outputs and validate transactions using P2MR outputs. P2MR is fully compatible with tapscript and existing tapscript programs can be used in P2MR outputs without modification. P2MR can also support future scripts with new leaf versions.
==Security==
P2MR outputs provide the same tapscript functionality as P2TR outputs, but with the quantum-vulnerable key path spend removed. The similarity between these output types enables users to easily migrate script trees from P2TR outputs to P2MR outputs for protection against long exposure quantum attacks. Wallets supporting only P2TR key path spends would need to migrate to using script trees. This is a straightforward migration as it only requires moving to a simple OP_CHECKSIG leaf script.
Protection from long exposure quantum attacks does not depend on the activation of post-quantum signatures in Bitcoin, but requires that users do not expose their public keys to attackers via public key reuse or other unsafe practices.
P2MR uses a 256-bit hash output, providing 128 bits of collision resistance and 256 bits of preimage resistance. This is the same level of security as P2WSH specified in [[bip-0141.mediawiki|BIP 141]], which also uses a 256-bit hash output.
P2MR does not, by itself, protect against short exposure quantum attacks, but these attacks can be mitigated by future activation of post-quantum signatures.
Combined with P2MR, post-quantum signature schemes can provide comprehensive quantum resistance to P2MR outputs, including protection from short exposure attacks.
That said, protection against long exposure quantum attacks alone should not be underestimated. It's unlikely that early CRQCs will be fast enough to perform short exposure attacks, making preparedness against long exposure attacks more time-critical.
==Security Considerations for Post-Quantum Signature Schemes==
While this proposal does not include the introduction of post-quantum signature schemes, we think it's worth commenting on security considerations related to this possibility.
Quantum-resistant signature algorithms (e.g. ML-DSA or SLH-DSA) offer different levels of protection and should be scrutinized before use. We are currently researching options for the potential proposal of post-quantum signatures into Bitcoin and encourage others to engage in this research as well.
We also imagine the possibility of introducing multiple post-quantum signatures for redundancy. Balancing the risks of additional complexity with the benefits of signature-type redundancy will be the challenge here.
==Test Vectors and Reference Code==
Test vector data for creation of P2MR UTXOs can be found [https://github.com/bitcoin/bips/blob/master/bip-0360/ref-impl/common/tests/data/P2MR_construction.json here].
These test vectors build off of the test vectors for [[bip-0341.mediawiki|BIP 341]] (Taproot). One important distinction is that the P2MR test vectors do not include keypath spend scenarios.
Also included are test vectors in [https://github.com/bitcoin/bips/tree/master/bip-0360/ref-impl/rust rust implementation] and [https://github.com/bitcoin/bips/tree/master/bip-0360/ref-impl/python python implementation]. One of these tests demonstrates a tapscript that requires a secp256k1 signature to spend the P2MR UTXO (modeled after one of the extremely valuable examples provided by [https://learnmeabitcoin.com/technical/upgrades/taproot/#example-3-script-path-spend-signature this Taproot script path spend example]. Similar to BIP 341 test vectors, all signatures are created with an all-zero (0x0000...0000) [[bip-0340.mediawiki|BIP 340]] auxiliary randomness array.
==Related Work==
Below we attempt to summarize some of the ideas discussed on the Bitcoin Development Mailing List that relate to P2MR.
The idea of Taproot with key path spend removed has been discussed a number of times in the Bitcoin community.
For instance, [https://gnusha.org/pi/bitcoindev/CAD5xwhgzR8e5r1e4H-5EH2mSsE1V39dd06+TgYniFnXFSBqLxw@mail.gmail.com/ OP_CAT Makes Bitcoin Quantum Secure] notes that if we disable the key path spend in Taproot and activate OP_CAT [[bip-0347.mediawiki|BIP 347]], we could achieve quantum resistance by using Lamport signatures with OP_CAT.
Lamport and WOTS (Winternitz One-Time Signatures) built from CAT are quantum resistant, but are one-time signatures — meaning, if you sign twice for the same public key, you risk leaking your private key, which is a significant security concern for everyday users.
This would require major changes to wallet behavior and would represent a significant security downgrade. Common practices, such as RBF and CPFP, could risk revealing private keys if no stateless signature scheme is used.
[https://groups.google.com/g/bitcoindev/c/8O857bRSVV8/m/rTrpeFjWDAAJ Trivial QC signatures with clean upgrade path] and [https://groups.google.com/g/bitcoindev/c/oQKezDOc4us/m/T1vSMkZNAAAJ Re: P2QRH / BIP 360 Update] also discuss the possibility of Taproot with key path spend removed. The design of P2MR was partly inspired by these discussions.
Commit-reveal schemes such as [https://gnusha.org/pi/bitcoindev/1518710367.3550.111.camel@mmci.uni-saarland.de/ Re: Transition to post-quantum (2018)] and [https://groups.google.com/g/bitcoindev/c/LpWOcXMcvk8/m/YEiH-kTHAwAJ Post-Quantum commit / reveal Fawkescoin variant as a soft fork (2025)] have been proposed as a way to create cryptocurrencies without public key cryptography. The ideas in this paper were more recently expanded upon by Tadge Dryja in his "[https://www.youtube.com/watch?v=4bzOwYPf1yo Lifeboat]" proposal, which effectively quantum-proofs Bitcoin transactions through a similar pre-commitment scheme designed for Bitcoin.
==Other Methods of Addressing Quantum Vulnerabilities for Cryptocurrencies==
It is worth noting, by way of comparison, that [https://ethresear.ch/t/how-to-hard-fork-to-save-most-users-funds-in-a-quantum-emergency/18901 Vitalik Buterin's proposed solution] to Ethereum's quantum vulnerability is quite different from the approach in this BIP.
His plan involves a hard fork of the chain, reverting all blocks after some sufficient amount of theft, and using STARKs based on BIP 32 seeds to act as the authoritative secret when signing. We believe rollbacks of any kind are an untenable approach for Bitcoin and would likely be impractical to implement.
That said, we believe the use of STARKs (which are quantum-resistant) may prove useful as a method of proving access to external private keys, in the event that the community chooses to burn vulnerable coins as proposed by Jameson Lopp and others in [https://qbip.org/ QBIP].
Discussions related to the burning of coins, and other attempts to slow a potential supply shock caused by quantum-retrieval of vulnerable coins, are out of scope for this proposal. That said, members of our team have separately proposed [https://github.com/cryptoquick/bips/blob/hourglass/bip-hourglass.mediawiki Hourglass] to address this concern and are continuing research on this subject.
==Conclusion==
In this proposal, we adopt a "prepared not scared" approach to the possible advancement of quantum computing and offer Bitcoin users an option for increased protection if they so choose. This BIP does not take a position on any specific quantum computing timeline, but rather proposes a flexible and unobtrusive option for users that wish to mitigate this risk according to their own estimate of the timeline.
This is an issue that has been discussed with some regularity in [https://bitcointalk.org/index.php?topic=133425.0 Bitcoin forums] since at least 2012, and there is clearly user demand for increased quantum protection.
==Glossary==
'''Quantum Key Recovery'''
The derivation of private keys from public keys in elliptic curve cryptography (ECC), made possible by solving the discrete logarithm problem (DLP).
Shor's algorithm, developed by Peter Shor in 1994, is a quantum algorithm that efficiently solves the discrete logarithm problem — potentially made possible by the future viability of cryptographically relevant quantum computers (CRQCs).
'''Long Exposure Attacks'''
Attempts to derive private keys from public keys that are exposed for an extended period of time; that is, longer than the window of time that a public key is generally exposed in the mempool while waiting to be confirmed.
Long exposure attacks give attackers an unlimited amount of time to perform quantum key recovery, as long as funds remain in the output. Poor wallet hygiene (e.g. from address reuse) or use of outputs with exposed public keys (e.g. P2TR outputs) increases vulnerability to long exposure attacks.
'''Short Exposure Attacks'''
Attempts to derive private keys from public keys during the brief period when funds are unconfirmed in the mempool. These attacks cannot be prevented through wallet hygiene, as revealing a public key is necessary for spending.
Protection against short exposure attacks may require post-quantum signature schemes; that said, executing these attacks requires faster CRQCs than those capable of executing long exposure attacks and are therefore viewed as lower-risk than long exposure attacks in the nearer term.
'''Script Tree Output Type'''
Script tree output types are a category of output type that support a script tree consisting of leaf scripts. Script tree output types support tapscript and would support any new script language added to bitcoin which is able to be used as a leaf script in a script trees. If Pay-to-Merkle-Root (P2MR) is activated, P2MR would be the second script tree output type in Bitcoin, the other being Pay-to-Taproot (P2TR).
'''Pay-to-Merkle-Root (P2MR)'''
A script tree output type, similar to to Pay-to-Taproot (P2TR), but with the quantum-vulnerable key path spend removed.
==Footnotes==
==Changelog==
To help implementers understand updates to this BIP, we keep a list of substantial changes.
* __0.11.0__ (2026-02-10) - Rename BIP from Pay-to-Tapscript-Hash (P2TSH) to Pay-to-Merkle-Root (P2MR)
* __0.10.3__ (2026-02-06) - Rename tapscript-native output type to script tree output type.
* __0.10.2__ (2026-01-23) - Fix bug in verification, minor review comments and adopt [[bip-0003.mediawiki|BIP 003]] conventions.
* __0.10.1__ (2026-01-21) - Terminology and clarity improvements, addressed feedback from reviews.
* __0.10.0__ (2025-09-17) - Rewrote BIP for clarity and renamed from P2QRH to P2TSH
* __0.9.0__ (2025-07-20) - Changed the Witness Version from 3 to 2.
* __0.8.0__ (2025-07-07) - P2QRH is now a P2TR with the vulnerable key path spend removed. Number of PQ signature algorithms supported reduced from three to two. PQ signature algorithm support is now added via opcodes or leaf version.
* __0.7.0__ (2025-03-18) - Correct inconsistencies in commitment and attestation structure. Switch from Merkle tree commitment to sorted vector hash commitment. Update descriptor format.
* __0.6.2__ (2025-03-12) - Add verification times for each algorithm. 256 to 128 (NIST V to NIST I). Add key type bitmask. Clarify multisig semantics.
* __0.6.1__ (2025-02-23) - More points of clarification from review. Update dead link.
* __0.6.0__ (2025-01-20) - Remove SQIsign from consideration due to significant performance concerns. Refactor language from long range attack to long exposure so as to not be confused with the language around block re-org attacks.
* __0.5.1__ (2024-12-18) - Assigned BIP number.
* __0.5.0__ (2024-12-13) - Update to use Merkle tree for attestation commitment. Update LR & SR quantum attack scenarios.
* __0.4.0__ (2024-12-01) - Add details on attestation structure and parsing.
* __0.3.0__ (2024-10-21) - Replace XMSS with CRYSTALS-Dilithium due to NIST approval and size constraints.
* __0.2.2__ (2024-09-30) - Refactor the ECC vs PoW section. Swap quitness for attestation.
* __0.2.1__ (2024-09-29) - Update section on PoW to include partial-preimage.
* __0.2.0__ (2024-09-28) - Add Winternitz, XMSS signatures, and security assumption types to PQC table. Omit NIST Level I table. Add spend script specification. Add revealed public key scenario table.
* __0.1.0__ (2024-09-27) - Initial draft proposal
==Acknowledgements==
This document is inspired by [[bip-0341.mediawiki|BIP 341]], which introduced the design of the P2TR (Taproot) output type using Schnorr signatures.
I'm incredibly grateful to Ethan Heilman for joining as co-author and transforming this BIP into something far more congruent with existing Bitcoin design. Additionally, much gratitude to our most recent co-author, Isabel Foxen Duke, for her thoughtful editing and crafting much of the language in this proposal. I am likewise indebted to those on the Anduro Quantum Working Group who took the time to contribute including Jeff Bride, Michael Casey, and notmike.
Thank you as well to those who took the time to review and contribute, including Jon Atack, Adam Borcany, Ava Chow, Kyle Crews, Pierre-Luc Dallaire-Demers, D++, Mark Erhardt, Jameson Lopp, Antoine Riard, Armin Sabouri, Vojtěch Strnad, Guy Swann, and Joey Yandle.
Whatever inaccuracies may remain are attributable solely to the authors.
================================================
FILE: bip-0370.mediawiki
================================================
BIP: 370
Layer: Applications
Title: PSBT Version 2
Authors: Ava Chow
Status: Deployed
Type: Specification
Assigned: 2021-01-14
License: BSD-2-Clause
==Introduction==
===Abstract===
This document proposes a second version of the Partially Signed Bitcoin Transaction format
described in BIP 174 which allows for inputs and outputs to be added to the PSBT after creation.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
Partially Signed Bitcoin Transaction Version 0 as described in BIP 174 is unable to have new
inputs and outputs be added to the transaction. The fixed global unsigned transaction
cannot be changed which prevents any additional inputs or outputs to be added.
PSBT Version 2 is intended to rectify this problem.
An additional beneficial side effect is that all information for a given input or output will be
provided by its or . With Version 0, to retrieve
all of the information for an input or output, data would need to be found in two locations:
the / and the global unsigned transaction. PSBT
Version 2 now moves all related information to one place.
==Specification==
PSBT Version 2 (PSBTv2) only specifies new fields and field inclusion/exclusion requirements.
PSBT_GLOBAL_UNSIGNED_TX must be excluded in PSBTv2.
PSBT_GLOBAL_VERSION must be included in PSBTv2 and set to version number 2'''What happened to version number 1?'''
Version number 1 is skipped because PSBT Version 0 has been colloquially referred to as version 1. Originally this BIP was to be
version 1, but because it has been colloquially referred to as version 2 during its design phase, it was decided to change the
version number to 2 so that there would not be any confusion.
The new global types for PSBT Version 2 are as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Transaction Version
| PSBT_GLOBAL_TX_VERSION = 0x02
| None
| No key data
| <32-bit little endian int version>
| The 32-bit little endian signed integer representing the version number of the transaction being created. Note that this is not the same as the PSBT version number specified by the PSBT_GLOBAL_VERSION field.
| 2
| 0
| 2
|-
| Fallback Locktime
| PSBT_GLOBAL_FALLBACK_LOCKTIME = 0x03
| None
| No key data
| <32-bit little endian uint locktime>
| The 32-bit little endian unsigned integer representing the transaction locktime to use if no inputs specify a required locktime.
|
| 0
| 2
|-
| Input Count
| PSBT_GLOBAL_INPUT_COUNT = 0x04
| None
| No key data
|
| Compact size unsigned integer representing the number of inputs in this PSBT.
| 2
| 0
| 2
|-
| Output Count
| PSBT_GLOBAL_OUTPUT_COUNT = 0x05
| None
| No key data
|
| Compact size unsigned integer representing the number of outputs in this PSBT.
| 2
| 0
| 2
|-
| Transaction Modifiable Flags
| PSBT_GLOBAL_TX_MODIFIABLE = 0x06
| None
| No key data
| <8-bit uint flags>
| An 8 bit unsigned integer as a bitfield for various transaction modification flags. Bit 0 is the Inputs Modifiable Flag, set to 1 to indicate whether inputs can be added or removed. Bit 1 is the Outputs Modifiable Flag, set to 1 to indicate whether outputs can be added or removed. Bit 2 is the Has SIGHASH_SINGLE flag, set to 1 to indicate whether the transaction has a SIGHASH_SINGLE signature who's input and output pairing must be preserved. Bit 2 essentially indicates that the Constructor must iterate the inputs to determine whether and how to add or remove an input.
|
| 0
| 2
|}
The new per-input types for PSBT Version 2 are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Previous TXID
| PSBT_IN_PREVIOUS_TXID = 0x0e
| None
| No key data
| <32 byte txid>
| 32 byte txid in standard byte order, not display byte order, of the previous transaction whose output at PSBT_IN_OUTPUT_INDEX is being spent.
| 2
| 0
| 2
|-
| Spent Output Index
| PSBT_IN_OUTPUT_INDEX = 0x0f
| None
| No key data
| <32-bit little endian uint index>
| 32 bit little endian integer representing the index of the output being spent in the transaction with the txid of PSBT_IN_PREVIOUS_TXID.
| 2
| 0
| 2
|-
| Sequence Number
| PSBT_IN_SEQUENCE = 0x10
| None
| No key data
| <32-bit little endian uint sequence>
| The 32 bit unsigned little endian integer for the sequence number of this input. If omitted, the sequence number is assumed to be the final sequence number (0xffffffff).
|
| 0
| 2
|-
| Required Time-based Locktime
| PSBT_IN_REQUIRED_TIME_LOCKTIME = 0x11
| None
| No key data
| <32-bit little endian uint locktime>
| 32 bit unsigned little endian integer greater than or equal to 500000000 representing the minimum Unix timestamp that this input requires to be set as the transaction's lock time.
|
| 0
| 2
|-
| Required Height-based Locktime
| PSBT_IN_REQUIRED_HEIGHT_LOCKTIME = 0x12
| None
| No key data
| <32-bit uint locktime>
| 32 bit unsigned little endian integer greater than 0 and less than 500000000 representing the minimum block height that this input requires to be set as the transaction's lock time.
|
| 0
| 2
|}
The new per-output types for PSBT Version 2 are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Output Amount
| PSBT_OUT_AMOUNT = 0x03
| None
| No key data
| <64-bit little endian int amount>
| 64 bit signed little endian integer representing the output's amount in satoshis.
| 2
| 0
| 2
|-
| Output Script
| PSBT_OUT_SCRIPT = 0x04
| None
| No key data
|
| The script for this output, also known as the scriptPubKey. Must be omitted in PSBTv0. Must be provided in PSBTv2.
| 2
| 0
| 2
|}
===Determining Lock Time===
The nLockTime field of a transaction is determined by inspecting the PSBT_GLOBAL_FALLBACK_LOCKTIME and each input's PSBT_IN_REQUIRED_TIME_LOCKTIME and PSBT_IN_REQUIRED_HEIGHT_LOCKTIME fields.
If none of the inputs have a PSBT_IN_REQUIRED_TIME_LOCKTIME and PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, then PSBT_GLOBAL_FALLBACK_LOCKTIME must be used.
If PSBT_GLOBAL_FALLBACK_LOCKTIME is not provided, then it is assumed to be 0.
If one or more inputs have a PSBT_IN_REQUIRED_TIME_LOCKTIME or PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, then the field chosen is the one which is supported by all of the inputs.
This can be determined by looking at all of the inputs which specify a locktime in either of those fields, and choosing the field which is present in all of those inputs.
Inputs not specifying a lock time field can take both types of lock times, as can those that specify both.
The lock time chosen is then the maximum value of the chosen type of lock time.
If a PSBT has both types of locktimes possible because one or more inputs specify both PSBT_IN_REQUIRED_TIME_LOCKTIME and PSBT_IN_REQUIRED_HEIGHT_LOCKTIME, then locktime determined by looking at the PSBT_IN_REQUIRED_HEIGHT_LOCKTIME fields of the inputs must be chosen.'''Why choose the height based locktime?'''
In the event of a tie for the locktime type, signers need to be able to know which locktime to use as their signatures will commit to the locktime in the transaction, so choosing the wrong one will result in an invalid transaction.
Height based locktime is preferred over time based as Bitcoin's unit of time is the block height, so a height makes more sense in the context of Bitcoin.
===Unique Identification===
PSBTv2s can be uniquely identified by constructing an unsigned transaction given the information provided in the PSBT, and computing the transaction ID of that transaction.
Since PSBT_IN_SEQUENCE can be changed by Updaters and Combiners, the sequence number in this unsigned transaction must be set to 0 (not final, nor the sequence in PSBT_IN_SEQUENCE).
The lock time in this unsigned transaction must be computed as described previously.
==Roles==
PSBTv2 introduces new roles and modifies some existing roles.
===Creator===
In PSBTv2, the Creator initializes the PSBT with 0 inputs and 0 outputs.
The PSBT version number is set to 2.
The Creator should also set PSBT_GLOBAL_FALLBACK_LOCKTIME.
If the Creator is not also a Constructor and will be giving the PSBT to others to add inputs and outputs, the PSBT_GLOBAL_TX_MODIFIABLE field must be present and the Inputs Modifiable and Outputs Modifiable flags set appropriately; moreover, the transaction version number must be set to at least 2. '''Why does the transaction version number need to be at least 2?''' The transaction version number is part of the validation rules for some features such as OP_CHECKSEQUENCEVERIFY. Since it is backwards compatible, and there are other ways to disable those features (e.g. through sequence numbers), it is easier to require transactions be able to support these features than to try to negotiate the transaction version number.
If the Creator is a Constructor and no inputs and outputs will be added by other entities, PSBT_GLOBAL_TX_MODIFIABLE may be omitted.
===Constructor===
This Constructor is only present for PSBTv2.
Once a Creator initializes the PSBT, a constructor will add inputs and outputs.
Before any input or output may be added, the constructor must check the PSBT_GLOBAL_TX_MODIFIABLE field.
Inputs may only be added if the Inputs Modifiable flag is True.
Outputs may only be added if the Outputs Modifiable flag is True.
When an input or output is added, the corresponding PSBT_GLOBAL_INPUT_COUNT or PSBT_GLOBAL_OUTPUT_COUNT must be incremented to reflect the number of inputs and outputs in the PSBT.
When an input is added, it must have PSBT_IN_PREVIOUS_TXID and PSBT_IN_OUTPUT_INDEX set.
When an output is added, it must have PSBT_OUT_VALUE and PSBT_OUT_OUTPUT_SCRIPT set.
If the input has a required timelock, Constructors must set the requisite timelock field.
If the input has a required time based timelock, then PSBT_IN_REQUIRED_TIME_TIMELOCK must be set.
If the input has a required height based timelock, then PSBT_IN_REQUIRED_HEIGHT_TIMELOCK must be set.
If an input has both types of timelocks, then both may be set.
In some cases, an input that can allow both types, but a particular branch supporting only one type of timelock will be taken, then the type of timelock that will be used can be the only one set.
If an input being added specifies a required time lock, then the Constructor must iterate through all of the existing inputs and ensure that the time lock types are compatible.
Additionally, if during this iteration, it finds that any inputs have signatures, it must ensure that the newly added input does not change the transaction's locktime.
If the newly added input has an incompatible time lock, then it must not be added.
If it changes the transaction's locktime when there are existing signatures, it must not be added.
If the Has SIGHASH_SINGLE flag is True, then the Constructor must iterate through the inputs and find the inputs which have signatures that use SIGHASH_SINGLE.
The same number of inputs and outputs must be added before those inputs and their corresponding outputs.
A Constructor may choose to declare that no further inputs and outputs can be added to the transaction by setting the appropriate bits in PSBT_GLOBAL_TX_MODIFIABLE to 0 or by removing the field entirely.
A single entity is likely to be both a Creator and Constructor.
===Updater===
For PSBTv2, an Updater can set the sequence number.
===Signer===
For PSBTv2s, a signer must update the PSBT_GLOBAL_TX_MODIFIABLE field after signing inputs so that it accurately reflects the state of the PSBT.
If the Signer added a signature that does not use SIGHASH_ANYONECANPAY, the Input Modifiable flag must be set to False.
If the Signer added a signature that does not use SIGHASH_NONE, the Outputs Modifiable flag must be set to False.
If the Signer added a signature that uses SIGHASH_SINGLE, the Has SIGHASH_SINGLE flag must be set to True.
===Transaction Extractor===
For PSBTv2s, the transaction is constructed using the PSBTv2 fields.
The lock time for this transaction is determined as described in the Determining Lock Time section.
The Extractor should produce a fully valid, network serialized transaction if all inputs are complete.
==Backwards Compatibility==
PSBTv2 shares the same generic format as PSBTv0 as defined in BIP 174. Parsers for PSBTv0 should
be able to deserialize PSBTv2 with only changes to support the new fields.
However PSBTv2 is incompatible with PSBTv0, and vice versa due to the use of the PSBT_GLOBAL_VERSION.
This incompatibility is intentional so that PSBT_GLOBAL_UNSIGNED_TX could be removed in PSBTv2.
However it is possible to convert a PSBTv2 to a PSBTv0 by creating an unsigned
transaction from the PSBTv2 fields.
==Test Vectors==
The following are invalid PSBTs:
* Case: PSBTv0 but with PSBT_GLOBAL_VERSION set to 2.
** Bytes in Hex:
* Case: 1 input, 2 output updated PSBTv2, with both Inputs Modifiable Flag (bit 0) and Outputs Modifiable Flag (bit 1) of PSBT_GLOBAL_TX_MODIFIABLE set
** Bytes in Hex:
* Case: 1 input, 2 output updated PSBTv2, with both Inputs Modifiable Flag (bit 0) and Has SIGHASH_SINGLE Flag (bit 2) of PSBT_GLOBAL_TX_MODIFIABLE set
** Bytes in Hex:
* Case: 1 input, 2 output updated PSBTv2, with both Outputs Modifiable Flag (bit 1) and Has SIGHASH_SINGLE FLag (bit 2) of PSBT_GLOBAL_TX_MODIFIABLE set
** Bytes in Hex:
The following tests are the timelock determination algorithm.
The timelock for the following PSBTs should be computed to be 0:
* Case: No locktimes specified
** Bytes in Hex:
The timelock for the following PSBTs should be computed to be 10000:
* Case: Input 1 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 10000, Input 2 has no locktime fields
** Bytes in Hex:
* Case: Input 1 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 10000, Input 2 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 9000 and PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048460
** Bytes in Hex:
* Case: Input 1 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 10000 and PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048459, Input 2 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 9000 and PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048460
** Bytes in Hex:
The timelock for the following PSBTs should be computed to be 1657048460:
* Case: Input 1 has PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048459, Input 2 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 9000 and PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048460
** Bytes in Hex:
* Case: Input 1 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 10000 and PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048459, Input 2 has PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048460
** Bytes in Hex:
The timelock for the following PSBTs cannot be computed:
* Case: Input 1 has PSBT_IN_REQUIRED_HEIGHT_LOCKTIME of 10000, Input 2 has PSBT_IN_REQUIRED_TIME_LOCKTIME of 1657048460
** Bytes in Hex:
==Rationale==
==Reference implementation==
The reference implementation of the PSBT format is available in [https://github.com/bitcoin/bitcoin/pull/21283 Bitcoin Core PR 21283].
================================================
FILE: bip-0371.mediawiki
================================================
BIP: 371
Layer: Applications
Title: Taproot Fields for PSBT
Authors: Ava Chow
Status: Deployed
Type: Specification
Assigned: 2021-06-21
License: BSD-2-Clause
==Introduction==
===Abstract===
This document proposes additional fields for BIP 174 PSBTv0 and BIP 370 PSBTv2 that allow for
BIP 340/341/342 Taproot data to be included in a PSBT of any version. These will be fields for
signatures and scripts that are relevant to the creation of Taproot inputs.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
BIPs 340, 341, and 342 specify Taproot which provides a wholly new way to create and spend Bitcoin outputs.
The existing PSBT fields are unable to support Taproot due to the new signature algorithm and the method
by which scripts are embedded inside of a Taproot output. Therefore new fields must be defined to allow
PSBTs to carry the information necessary for signing Taproot inputs.
==Specification==
The new per-input types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Taproot Key Spend Signature
| PSBT_IN_TAP_KEY_SIG = 0x13
| None
| No key data '''Why is there no key data for PSBT_IN_TAP_KEY_SIG'''The signature in a key path spend corresponds directly with the pubkey provided in the output script. Thus it is not necessary to provide any metadata that attaches the key path spend signature to a particular pubkey.
| <64 or 65 byte signature>
| The 64 or 65 byte Schnorr signature for key path spending a Taproot output. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|-
| Taproot Script Spend Signature
| PSBT_IN_TAP_SCRIPT_SIG = 0x14
|
| A 32 byte X-only public key involved in a leaf script concatenated with the 32 byte hash of the leaf it is part of.
| <64 or 65 byte signature>
| The 64 or 65 byte Schnorr signature for this pubkey and leaf combination. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|-
| Taproot Leaf Script
| PSBT_IN_TAP_LEAF_SCRIPT = 0x15
|
| The control block for this leaf as specified in BIP 341. The control block contains the merkle tree path to this leaf.
| <8-bit uint leaf version>
| The script for this leaf as would be provided in the witness stack followed by the single byte leaf version. Note that the leaves included in this field should be those that the signers of this input are expected to be able to sign for. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|-
| Taproot Key BIP 32 Derivation Path
| PSBT_IN_TAP_BIP32_DERIVATION = 0x16
| <32 byte xonlypubkey>
| A 32 byte X-only public key involved in this input. It may be the output key, the internal key, or a key present in a leaf script.
| <32 byte leaf hash>* <4 byte fingerprint> <32-bit little endian uint path element>*
| A compact size unsigned integer representing the number of leaf hashes, followed by a list of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output. The leaf hashes are of the leaves which involve this public key. The internal key does not have leaf hashes, so can be indicated with a hashes len of 0. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|-
| Taproot Internal Key
| PSBT_IN_TAP_INTERNAL_KEY = 0x17
| None
| No key data
| <32 byte xonlypubkey>
| The X-only pubkey used as the internal key in this output.'''Why is the internal key provided?'''The internal key is not necessarily the same key as in the Taproot output script. BIP 341 recommends tweaking the key with the hash of itself. It may be necessary for signers to know what the internal key actually is so that they are able to determine whether an input can be signed by it. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|-
| Taproot Merkle Root
| PSBT_IN_TAP_MERKLE_ROOT = 0x18
| None
| No key data
| <32-byte hash>
| The 32 byte Merkle root hash. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|}
The new per-output types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Taproot Internal Key
| PSBT_OUT_TAP_INTERNAL_KEY = 0x05
| None
| No key data
| <32 byte xonlypubkey>
| The X-only pubkey used as the internal key in this output.
|
|
| 0, 2
|-
| Taproot Tree
| PSBT_OUT_TAP_TREE = 0x06
| None
| No key data
| {<8-bit uint depth> <8-bit uint leaf version> }*
| One or more tuples representing the depth, leaf version, and script for a leaf in the Taproot tree, allowing the entire tree to be reconstructed. The tuples must be in depth first search order so that the tree is correctly reconstructed. Each tuple is an 8-bit unsigned integer representing the depth in the Taproot tree for this script, an 8-bit unsigned integer representing the leaf version, the length of the script as a compact size unsigned integer, and the script itself.
|
|
| 0, 2
|-
| Taproot Key BIP 32 Derivation Path
| PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
| <32 byte xonlypubkey>
| A 32 byte X-only public key involved in this output. It may be the output key, the internal key, or a key present in a leaf script.
| <32 byte leaf hash>* <4 byte fingerprint> <32-bit little endian uint path element>*
| A compact size unsigned integer representing the number of leaf hashes, followed by a list of leaf hashes, followed by the 4 byte master key fingerprint concatenated with the derivation path of the public key. The derivation path is represented as 32-bit little endian unsigned integer indexes concatenated with each other. Public keys are those needed to spend this output. The leaf hashes are of the leaves which involve this public key. The internal key does not have leaf hashes, so can be indicated with a hashes len of 0. Finalizers should remove this field after PSBT_IN_FINAL_SCRIPTWITNESS is constructed.
|
|
| 0, 2
|}
===UTXO Types===
BIP 174 recommends using PSBT_IN_NON_WITNESS_UTXO for all inputs because of potential attacks involving
an updater lying about the amounts in an output. Because a Taproot signature will commit to all of the amounts
and output scripts spent by the inputs of the transaction, such attacks are prevented as any such lying would
result in an invalid signature. Thus Taproot inputs can use just PSBT_IN_WITNESS_UTXO.
==Compatibility==
These are simply new fields added to the existing PSBT format. Because PSBT is designed to be extensible, old
software will ignore the new fields.
==Test Vectors==
The following are invalid PSBTs:
* Case: PSBT With PSBT_IN_TAP_INTERNAL_KEY key that is too long (incorrectly serialized as compressed DER)
** Bytes in Hex:
* Case: PSBT with one P2TR script path only input with dummy internal key, scripts, derivation paths for keys in the scripts, and merkle root
** Bytes in Hex:
* Case: PSBT with one P2TR script path only input with dummy internal key, scripts, script key derivation paths, merkle root, and script path signatures
** Bytes in Hex:
==Rationale==
==Reference implementation==
The reference implementation of the PSBT format is available at https://github.com/achow101/bitcoin/tree/taproot-psbt.
==Acknowledgements==
TBD
================================================
FILE: bip-0372.mediawiki
================================================
==Introduction==
===Abstract===
This document proposes additional fields for BIP 174 PSBTv0 and BIP 370 PSBTv2
that allow for pay-to-contract (P2C) key tweaking data to be included in a PSBT
of any version. These will represent extra-transaction information required
for the signer to produce valid signatures spending previous outputs.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Background===
Key tweaking is a procedure for creating a cryptographic commitment to a
message using elliptic curve properties. The procedure uses the discrete log
problem (DLP) to commit to an extra-transaction message. This is done by adding
to a public key (for which the output owner knows the corresponding private key)
a hash of the message multiplied by the generator point G of the elliptic curve.
This produces a tweaked public key containing the commitment. Later, in order
to spend an output containing the P2C commitment, the same commitment should be
added to the corresponding private key.
This type of commitment was originally proposed as a part of the pay to contract
concept by Ilja Gerhardt and Timo Hanke in [1] and later used by Eternity Wall
[2] for the same purpose. Since that time, multiple different protocols for P2C
have been developed, including OpenTimeStamps [3], Elements sidechain P2C tweaks
[4] and LNPBP-1 [5], used for constructing Peter Todd's single-use-seals [6]
in client-side-validation protocols like RGB.
===Motivation===
P2C outputs can be detected onchain and spent only if the output owner
not only knows the corresponding original private key, but also is aware of
a P2C tweak applied to the public key. In order to produce a valid signature, the
same tweak value must be added (modulo group order) to the original private key
by a signer device. This represents a challenge for external signers, which may
not have any information about such commitment. This proposal addresses this
issue by adding relevant fields to the PSBT input information.
The proposal abstracts details of specific P2C protocols and provides a universal
method for spending previous outputs containing P2C tweaks, applied to the public
key contained within any standard form of the scriptPubkey, including
bare scripts and P2PK, P2PKH, P2SH, witness v0 P2WPKH, P2WSH, nested witness v0
P2WPKH-P2SH, P2WSH-P2SH and witness v1 P2TR outputs.
==Design==
P2C-tweaked public keys are already exposed in the
PSBT_IN_REDEEM_SCRIPT, PSBT_IN_WITNESS_SCRIPT,
PSBT_IN_TAP_INTERNAL_KEY and PSBT_IN_TAP_LEAF_SCRIPT fields;
the only information signer is needed to recognize which keys it should sign
with is from which of the original keys they were generated. This is achieved by
introducing a new `PSBT_IN_P2C_TWEAK` field, which has the original key as a field
key and the tweak as a field value. The signer will recognize the keys which are
available to it, apply the tweak to them and see in which scripts it was used --
and use this information to apply tweaks for the corresponding private keys and
produce valid signatures.
==Specification==
The new per-input type is defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| P2C Key Tweak
| PSBT_IN_P2C_TWEAK = 0x19
|
| 33 bytes of compact public key serialization specifying to which keys the
P2C tweak may be applied (i.e. this MUST be a value of a public key before the
tweak is applied). BIP-340 keys are serialized by appending `0x02`
byte.'''Why compressed public keys are not distinguished from BIP-340
public keys''' We follow the logic of BIP32 key derivation, which does not
distinguish them. The type of the key is defined by the input type,
and adding additional PSBT field types will just create the need for handling
errors when the input type does not match the provided key type.
|
| The 32 byte value which MUST be added to a private key to produce a correct
ECDSA and/or Schnorr signature ("key tweak"). Signers SHOULD remove this field
after PSBT_IN_PARTIAL_SIG is constructed.
|
|
| 0, 2
| BIP-P2C
|}
==Security considerations==
The scope of this proposal is deliberately kept narrow; it addresses
only spending of transaction outputs containing P2C tweaks - and does not
address construction of new P2C commitments or transactions containing them
in their outputs.'''Why only spending of P2C tweaked outputs is covered'''
P2C tweaks commit to external data, some of which may represent certain values
(like in some sidechains, single-use-seal applications like RGB, etc). Creation
of such outputs may allow hardware devices to understand the structure of such
extra-transaction data, which may be in different formats and constantly
evolve. Thus, this should be addressed with separate standards (or be
vendor-based). The current proposal only touches the question of spending an
output that contained a previously created P2C commitment, which does not create
a new commitment and does not provide that kind of risk of extra-blockchain
value losses.
==Rationale==
==Compatibility==
The proposal is compatible with the existing consensus rules and does not
require any modification to them.
The proposed P2C PSBT fields provide sufficient information for creating
valid signatures for spending the following output types containing tweaked
public keys:
- bare scripts,
- P2PK,
- P2PKH,
- P2SH,
- witness v0 P2WPKH and P2WSH,
- nested witness v0 P2WPKH-P2SH and P2WSH-P2SH
Post-0 witness versions, including taproot outputs and future witness versions,
may not be supported or covered by this BIP and may require the addition of new
fields to the PSBT inputs.
==Reference implementation==
WIP
==Acknowledgements==
The author is grateful to Andrew Poelstra, who provided an initial set of ideas
and information with his previous work on the topic, on which this standard
was designed.
==Test vectors==
TBD
==References==
[1] Ilja Gerhardt, Timo Hanke. ''Homomorphic Payment Addresses and the Pay-to-Contract Protocol.'' arXiv:1212.3257 [cs.CR]. [https://arxiv.org/pdf/1212.3257.pdf arxiv.org/pdf/1212.3257.pdf]
[2] Eternity Wall. ''Sign-to-contract.'' [https://blog.eternitywall.com/2018/04/13/sign-to-contract/ blog.eternitywall.com]
[3] Peter Todd. ''OpenTimestamps: Scalable, Trust-Minimized, Distributed Timestamping with Bitcoin.'' [https://petertodd.org/2016/opentimestamps-announcement petertodd.org]
[4] Adam Back, Matt Corallo, Luke Dashjr, et al. ''Enabling Blockchain Innovations with Pegged Sidechains (commit5620e43). Appendix A.'' [https://blockstream.com/sidechains.pdf blockstream.com/sidechains.pdf]
[5] Maxim Orlovsky, Rene Pickhardt, Federico Tenga, et al. ''Key tweaking: collision-resistant elliptic curve-based commitments. LNPBP-1 Standard.'' [https://github.com/LNP-BP/LNPBPs/blob/master/lnpbp-0001.md LNPBP-1 on GitHub]
[6] Peter Todd. ''Single-use-seals. LNPBP-8 Standard.'' [https://github.com/LNP-BP/LNPBPs/blob/master/lnpbp-0008.md LNPBP-8 on GitHub]
================================================
FILE: bip-0373.mediawiki
================================================
==Introduction==
===Abstract===
This document proposes additional fields for [[bip-0174.mediawiki|BIP 174]] PSBTv0 and [[bip-0370.mediawiki|BIP 370]] PSBTv2 that allow for
[[bip-0327.mediawiki|BIP 327]] MuSig2 Multi-Signature data to be included in a PSBT of any version. These will be fields for
the participants' keys, the public nonces, and the partial signatures produced with MuSig2.
===Copyright===
This BIP is licensed under the Creative Commons CC0 1.0 Universal license.
===Motivation===
[[bip-0327.mediawiki|BIP 327]] specifies a way to create [[bip-0340.mediawiki|BIP 340]] compatible public keys and signatures using the MuSig2
Multi-Signature scheme. The existing PSBT fields are unable to support MuSig2 as it introduces new
concepts and additional rounds of communication. Therefore new fields must be defined to allow PSBTs
to carry the information necessary to produce a valid signature with MuSig2.
==Specification==
The new per-input types are defined as follows:
{|
! Name
!
!
!
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| rowspan="2"|MuSig2 Participant Public Keys
| rowspan="2"|PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS = 0x1a
| <33 byte aggregate pubkey (compressed)>
| <33 byte participant pubkey (compressed)>*
| rowspan="2"|
| rowspan="2"|
| rowspan="2"| 0, 2
|-
| The MuSig2 aggregate public key (compressed) '''Why the compressed aggregate public key instead of x-only?'''
[[bip-0032.mediawiki|BIP 32]] public keys can be derived from a [[bip-0327.mediawiki|BIP 327]] MuSig2 aggregate public key (see: [[bip-0328.mediawiki|BIP 328]]).
But since BIP 32 requires public keys to include their evenness byte, BIP 327 MuSig2 aggregate public keys must
include their evenness byte as well. Furthermore, PSBT_IN_TAP_BIP32_DERIVATION fields include fingerprints to identify
master keys, and these fingerprints require the y-coordinate of the public key, so x-only serialization can't be used.
By including the aggregate key as a full public key, signers that are unaware of the MuSig2 outside of the PSBT will
still be able to identify which keys are derived from the aggregate key by computing and then comparing the
fingerprints. This is necessary for the signer to apply the correct tweaks to their partial signature. from the
KeyAgg algorithm. This key may or may not appear (as x-only) in the Taproot output key, the internal key, or
in a script. It may instead be a parent public key from which the Taproot output key, internal key, or keys in a script
were derived.
| A list of the compressed public keys of the participants in the MuSig2 aggregate key in the order
required for aggregation. If sorting was done, then the keys must be in the sorted order.
|-
| rowspan="2"|MuSig2 Public Nonce
| rowspan="2"|PSBT_IN_MUSIG2_PUB_NONCE = 0x1b
| <33 byte participant pubkey (compressed)> <33 byte aggregate pubkey (compressed)> <32 byte hash or omitted>
| <66 byte public nonce>
| rowspan="2"|
| rowspan="2"|
| rowspan="2"| 0, 2
|-
| The compressed public key of the participant providing this nonce, followed by the compressed aggregate public
key the participant is providing the nonce for, followed by the [[bip-0341.mediawiki|BIP 341]] tapleaf hash of
the Taproot leaf script that will be signed. If the aggregate key is the Taproot internal key or the
Taproot output key, then the tapleaf hash must be omitted. The compressed participant public key must be
the Taproot output key or found in a script. It is not the internal key nor the aggregate public key that
it was derived from, if it was derived from an aggregate key.
| The public nonce produced by the NonceGen algorithm.
|-
| rowspan="2"|MuSig2 Participant Partial Signature
| rowspan="2"|PSBT_IN_MUSIG2_PARTIAL_SIG = 0x1c
| <33 byte participant pubkey (compressed)> <33 byte aggregate pubkey (compressed)> <32 byte hash or omitted>
| <32 byte partial signature>
| rowspan="2"|
| rowspan="2"|
| rowspan="2"| 0, 2
|-
| The compressed public key of the participant providing this partial signature, followed by the
compressed aggregate public key the participant is providing the signature for, followed by the [[bip-0341.mediawiki|BIP 341]] tapleaf hash
of the Taproot leaf script that will be signed. If the aggregate key is the Taproot internal key or
the Taproot output key, then the tapleaf hash must be omitted. Note that the compressed participant public key must be
the Taproot output key or found in a script. It is not the internal key nor the aggregate public key that
it was derived from, if it was derived from an aggregate key.
| The partial signature produced by the Sign algorithm.
|}
The new per-output types are defined as follows:
{|
! Name
!
!
!
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| rowspan="2"|MuSig2 Participant Public Keys
| rowspan="2"|PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS = 0x08
| <33 byte aggregate pubkey (compressed)>
| <33 byte participant pubkey (compressed)>*
| rowspan="2"|
| rowspan="2"|
| rowspan="2"|0, 2
|-
| The MuSig2 compressed aggregate public key from the KeyAgg algorithm. This key may or may not
appear (as x-only) in the Taproot output key, the internal key, or in a script. It may instead be a parent
public key from which the Taproot output key, internal key, or keys in a script were derived.
| A list of the compressed public keys of the participants in the MuSig2 aggregate key in the order
required for aggregation. If sorting was done, then the keys must be in the sorted order.
|}
==Roles==
===Updater===
When an updater observes a Taproot output which involves a MuSig2 aggregate public key that it is
aware of, it can add a PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS field containing the public keys
of the participants. This aggregate public key may be directly in the script, the Taproot internal
key, the Taproot output key, or a public key from which the key in the script was derived from.
An aggregate public key that appears directly in the script or internal key may be from the result
of deriving child pubkeys from participant xpubs. If the updater has this derivation information, it
should also add PSBT_IN_TAP_BIP32_DERIVATION for each participant public key.
If the public key found was derived from an aggregate public key, then all MuSig2 PSBT fields for
that public key should contain the aggregate public key rather than the found pubkey itself. The
updater should also add PSBT_IN_TAP_BIP32_DERIVATION that contains the derivation path used
to derive the found pubkey from the aggregate pubkey.
Derivation from the aggregate pubkey can be assumed to follow [[bip-0328.mediawiki|BIP 328]]
if there is no PSBT_GLOBAL_XPUB that specifies the synthetic xpub for the aggregate
public key.
Updaters should add PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS and
PSBT_OUT_TAP_BIP32_DERIVATION similarly to inputs to aid in change detection.
===Signer===
To determine whether a signer is a participant in the MuSig2 aggregate key, the signer should first
look at all PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS and see if any key which it knows the
private key for appears as a participant in any aggregate pubkey. Signers should also check whether
any of the keys in PSBT_IN_TAP_BIP32_DERIVATION belong to it, and if any of those keys
appear in as a participant in PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS.
For each aggregate public key that the signer is a participant of that it wants
to produce a signature for, if the signer does not find an existing
PSBT_IN_MUSIG2_PUB_NONCE field for its key, then it should add one using
the NonceGen algorithm (or one of its variations) to produce a public
nonce that is added in a PSBT_IN_MUSIG2_PUB_NONCE field. However
signers must keep in mind that '''improper nonce usage can compromise private
keys.''' Please see [[bip-0327.mediawiki|BIP 327]] for best practices on nonce generation and usage.
Once all signers have added their PSBT_IN_MUSIG2_PUB_NONCE fields, each signer will perform
the NonceAgg algorithm followed by the Sign algorithm in order to produce the
partial signature for their key. The result will be added to the PSBT in a
PSBT_IN_MUSIG2_PARTIAL_SIG field.
Signers must remember to apply any relevant tweaks such as a tweak that is the result of performing
BIP 32 unhardened derivation with the aggregate public key as the parent key.
If all other signers have provided a PSBT_IN_MUSIG2_PARTIAL_SIG, then the final signer may
perform the PartialSigAgg algorithm and produce a [[bip-0340.mediawiki|BIP 340]] compatible signature that can be
placed into a PSBT_IN_TAP_KEY_SIG or a PSBT_IN_TAP_SCRIPT_SIG.
===Finalizer===
A finalizer may perform the same PartialSigAgg step as the final signer if it has not
already been done.
Otherwise, the resulting signature is a [[bip-0340.mediawiki|BIP 340]] compatible signature and finalizers should treat it
as such.
==Backwards Compatibility==
These are simply new fields added to the existing PSBT format. Because PSBT is designed to be
extensible, old software will ignore the new fields.
Reusing PSBT_IN_TAP_BIP32_DERIVATION to provide derivation paths for participant public
keys may cause software unaware of MuSig2 to produce a signature for that public key. This is still
safe. If that public key does not directly appear in the leaf script that was signed, then the
signature produced will not be useful and so cannot be replayed. If the public key does directly
appear in the leaf script, then the signer will have validated the script as if it did not involve a
MuSig2 and will have found it acceptable in order for it to have produced a signature. In either
case, producing a signature does not give rise to the possibility of losing funds.
==Test Vectors==
The following are valid PSBTs
All of the following test cases use the aggregate pubkey 030b58e337aa4d3852a8c29387c42408d8cfbe3a613a5e397e0a9f01a5fb7107d4
which has the following participant keys:
# 02346B99593357107C9D3459E9DEBA8D3EAF44E6636C85C7F853EB90BA52E8CD00, L2XJhGmS9rkNwzn1eFJVD5ydKpA5K5p54uk9qqWpURj85VkEPuNE, cStJABmHavSe7SFH2f7caQUgx3TUyXum8wtcxFyKyYP8LEqnMiEh
# 024fafd65f8169186fc2bfdb2233c77e630d10be280a24c7165c09a27611775c2c, L19kEzCkrce5E3v7CWKn9pTceVzFwwdorjNXfqtUc5nKLXz4qXSX, cRWjhuCcHgLLPVPNav8uX8xgGjHfcPjVvmWznGLz7CSKbGzmfvRQ
# 02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9, KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU74sHUHy8S, cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87KcLPVfXz
* Case: Spend of a Taproot output where the output key is a MuSig2 Aggregate Pubkey
** With participant pubkeys only
*** Bytes in Hex:
==Rationale==
==Reference implementation==
The reference implementation of the PSBT format is available at Bitcoin Core [[https://github.com/bitcoin/bitcoin/pull/31247|PR #31247]].
==Acknowledgements==
Thanks to Sanket Kanjalkar whose notes on this topic formed the initial basis of this BIP. Also
thanks to Pieter Wuille, Jonas Nick, Tim Ruffing, Marko Bencun, Salvatore Ingala, and all others who
have participated in discussions about these fields.
================================================
FILE: bip-0374/gen_test_vectors.py
================================================
#!/usr/bin/env python3
"""Generate the BIP-0374 test vectors."""
import csv
from pathlib import Path
from reference import (
dleq_generate_proof,
dleq_verify_proof,
)
from secp256k1lab.secp256k1 import G as GENERATOR, GE
from secp256k1lab.util import tagged_hash
NUM_SUCCESS_TEST_VECTORS = 8
DLEQ_TAG_TESTVECTORS_RNG = "BIP0374/testvectors_rng"
FILENAME_GENERATE_PROOF_TEST = Path(__file__).parent / 'test_vectors_generate_proof.csv'
FILENAME_VERIFY_PROOF_TEST = Path(__file__).parent / 'test_vectors_verify_proof.csv'
def random_scalar_int(vector_i, purpose):
rng_out = tagged_hash(DLEQ_TAG_TESTVECTORS_RNG, purpose.encode() + vector_i.to_bytes(4, 'little'))
return int.from_bytes(rng_out, 'big') % GE.ORDER
def random_bytes(vector_i, purpose):
rng_out = tagged_hash(DLEQ_TAG_TESTVECTORS_RNG, purpose.encode() + vector_i.to_bytes(4, 'little'))
return rng_out
def create_test_vector_data(vector_i):
g = random_scalar_int(vector_i, "scalar_g") if vector_i < 5 else 1
assert 0 < g < GE.ORDER
G = g * GENERATOR
assert not G.infinity
a = random_scalar_int(vector_i, "scalar_a")
A = a * G
b = random_scalar_int(vector_i, "scalar_b")
B = b * G
C = a * B # shared secret
assert C.to_bytes_compressed() == (b * A).to_bytes_compressed()
auxrand = random_bytes(vector_i, "auxrand")
msg = random_bytes(vector_i, "message") if vector_i != 5 else None
proof = dleq_generate_proof(a, B, auxrand, G=G, m=msg)
return (G, a, A, b, B, C, auxrand, msg, proof)
TEST_VECTOR_DATA = [create_test_vector_data(i) for i in range(NUM_SUCCESS_TEST_VECTORS)]
def gen_all_generate_proof_vectors(f):
writer = csv.writer(f)
writer.writerow(("index", "point_G", "scalar_a", "point_B", "auxrand_r", "message", "result_proof", "comment"))
# success cases with random values
idx = 0
for i in range(NUM_SUCCESS_TEST_VECTORS):
G, a, A, b, B, C, auxrand, msg, proof = TEST_VECTOR_DATA[i]
assert proof is not None and len(proof) == 64
if msg is None: msg = b""
writer.writerow((idx, G.to_bytes_compressed().hex(), f"{a:064x}", B.to_bytes_compressed().hex(), auxrand.hex(), msg.hex(), proof.hex(), f"Success case {i+1}"))
idx += 1
# failure cases: a is not within group order (a=0, a=N)
a_invalid = 0
assert dleq_generate_proof(a_invalid, B, auxrand, G=G, m=msg) is None
writer.writerow((idx, G.to_bytes_compressed().hex(), f"{a_invalid:064x}", B.to_bytes_compressed().hex(), auxrand.hex(), msg.hex(), "INVALID", f"Failure case (a=0)"))
idx += 1
a_invalid = GE.ORDER
assert dleq_generate_proof(a_invalid, B, auxrand, G=G, m=msg) is None
writer.writerow((idx, G.to_bytes_compressed().hex(), f"{a_invalid:064x}", B.to_bytes_compressed().hex(), auxrand.hex(), msg.hex(), "INVALID", f"Failure case (a=N [group order])"))
idx += 1
# failure case: B is point at infinity
B_infinity = GE()
B_infinity_str = "INFINITY"
assert dleq_generate_proof(a, B_infinity, auxrand, m=msg) is None
writer.writerow((idx, G.to_bytes_compressed().hex(), f"{a:064x}", B_infinity_str, auxrand.hex(), msg.hex(), "INVALID", f"Failure case (B is point at infinity)"))
idx += 1
def gen_all_verify_proof_vectors(f):
writer = csv.writer(f)
writer.writerow(("index", "point_G", "point_A", "point_B", "point_C", "proof", "message", "result_success", "comment"))
# success cases (same as above)
idx = 0
for i in range(NUM_SUCCESS_TEST_VECTORS):
G, _, A, _, B, C, _, msg, proof = TEST_VECTOR_DATA[i]
assert dleq_verify_proof(A, B, C, proof, G=G, m=msg)
if msg is None: msg = b""
writer.writerow((idx, G.to_bytes_compressed().hex(), A.to_bytes_compressed().hex(), B.to_bytes_compressed().hex(),
C.to_bytes_compressed().hex(), proof.hex(), msg.hex(), "TRUE", f"Success case {i+1}"))
idx += 1
# other permutations of A, B, C should always fail
for i, points in enumerate(([A, C, B], [B, A, C], [B, C, A], [C, A, B], [C, B, A])):
assert not dleq_verify_proof(points[0], points[1], points[2], proof, m=msg)
writer.writerow((idx, G.to_bytes_compressed().hex(), points[0].to_bytes_compressed().hex(), points[1].to_bytes_compressed().hex(),
points[2].to_bytes_compressed().hex(), proof.hex(), msg.hex(), "FALSE", f"Swapped points case {i+1}"))
idx += 1
# modifying proof should fail (flip one bit)
proof_damage_pos = random_scalar_int(idx, "damage_pos") % 256
proof_damaged = list(proof)
proof_damaged[proof_damage_pos // 8] ^= (1 << (proof_damage_pos % 8))
proof_damaged = bytes(proof_damaged)
writer.writerow((idx, G.to_bytes_compressed().hex(), A.to_bytes_compressed().hex(), B.to_bytes_compressed().hex(),
C.to_bytes_compressed().hex(), proof_damaged.hex(), msg.hex(), "FALSE", f"Tampered proof (random bit-flip)"))
idx += 1
# modifying message should fail (flip one bit)
msg_damage_pos = random_scalar_int(idx, "damage_pos") % 256
msg_damaged = list(msg)
msg_damaged[msg_damage_pos // 8] ^= (1 << (msg_damage_pos % 8))
msg_damaged = bytes(msg_damaged)
writer.writerow((idx, G.to_bytes_compressed().hex(), A.to_bytes_compressed().hex(), B.to_bytes_compressed().hex(),
C.to_bytes_compressed().hex(), proof.hex(), msg_damaged.hex(), "FALSE", f"Tampered message (random bit-flip)"))
idx += 1
if __name__ == "__main__":
print(f"Generating {FILENAME_GENERATE_PROOF_TEST}...")
with open(FILENAME_GENERATE_PROOF_TEST, "w", encoding="utf-8") as fil_generate_proof:
gen_all_generate_proof_vectors(fil_generate_proof)
print(f"Generating {FILENAME_VERIFY_PROOF_TEST}...")
with open(FILENAME_VERIFY_PROOF_TEST, "w", encoding="utf-8") as fil_verify_proof:
gen_all_verify_proof_vectors(fil_verify_proof)
================================================
FILE: bip-0374/reference.py
================================================
#!/usr/bin/env python3
"""Reference implementation of DLEQ BIP for secp256k1 with unit tests."""
from pathlib import Path
import random
import sys
import unittest
# Prefer the vendored copy of secp256k1lab
sys.path.insert(0, str(Path(__file__).parent / "secp256k1lab/src"))
from secp256k1lab.secp256k1 import G, GE
from secp256k1lab.util import tagged_hash, xor_bytes
DLEQ_TAG_AUX = "BIP0374/aux"
DLEQ_TAG_NONCE = "BIP0374/nonce"
DLEQ_TAG_CHALLENGE = "BIP0374/challenge"
def dleq_challenge(
A: GE, B: GE, C: GE, R1: GE, R2: GE, m: bytes | None, G: GE,
) -> int:
if m is not None:
assert len(m) == 32
m = bytes([]) if m is None else m
return int.from_bytes(
tagged_hash(
DLEQ_TAG_CHALLENGE,
A.to_bytes_compressed()
+ B.to_bytes_compressed()
+ C.to_bytes_compressed()
+ G.to_bytes_compressed()
+ R1.to_bytes_compressed()
+ R2.to_bytes_compressed()
+ m,
),
"big",
)
def dleq_generate_proof(
a: int, B: GE, r: bytes, G: GE = G, m: bytes | None = None
) -> bytes | None:
assert len(r) == 32
if not (0 < a < GE.ORDER):
return None
if B.infinity:
return None
if m is not None:
assert len(m) == 32
A = a * G
C = a * B
t = xor_bytes(a.to_bytes(32, "big"), tagged_hash(DLEQ_TAG_AUX, r))
m_prime = bytes([]) if m is None else m
rand = tagged_hash(
DLEQ_TAG_NONCE, t + A.to_bytes_compressed() + C.to_bytes_compressed() + m_prime
)
k = int.from_bytes(rand, "big") % GE.ORDER
if k == 0:
return None
R1 = k * G
R2 = k * B
e = dleq_challenge(A, B, C, R1, R2, m, G)
s = (k + e * a) % GE.ORDER
proof = e.to_bytes(32, "big") + s.to_bytes(32, "big")
if not dleq_verify_proof(A, B, C, proof, G=G, m=m):
return None
return proof
def dleq_verify_proof(
A: GE, B: GE, C: GE, proof: bytes, G: GE = G, m: bytes | None = None
) -> bool:
if A.infinity or B.infinity or C.infinity or G.infinity:
return False
assert len(proof) == 64
e = int.from_bytes(proof[:32], "big")
s = int.from_bytes(proof[32:], "big")
if s >= GE.ORDER:
return False
R1 = s * G - e * A
if R1.infinity:
return False
R2 = s * B - e * C
if R2.infinity:
return False
if e != dleq_challenge(A, B, C, R1, R2, m, G):
return False
return True
class DLEQTests(unittest.TestCase):
def test_dleq(self):
seed = random.randrange(sys.maxsize)
random.seed(seed)
print(f"PRNG seed is: {seed}")
for _ in range(10):
# generate random keypairs for both parties
a = random.randrange(1, GE.ORDER)
A = a * G
b = random.randrange(1, GE.ORDER)
B = b * G
# create shared secret
C = a * B
# create dleq proof
rand_aux = random.randbytes(32)
proof = dleq_generate_proof(a, B, rand_aux)
self.assertTrue(proof is not None)
# verify dleq proof
success = dleq_verify_proof(A, B, C, proof)
self.assertTrue(success)
# flip a random bit in the dleq proof and check that verification fails
for _ in range(5):
proof_damaged = list(proof)
proof_damaged[random.randrange(len(proof))] ^= 1 << (
random.randrange(8)
)
success = dleq_verify_proof(A, B, C, bytes(proof_damaged))
self.assertFalse(success)
# create the same dleq proof with a message
message = random.randbytes(32)
proof = dleq_generate_proof(a, B, rand_aux, m=message)
self.assertTrue(proof is not None)
# verify dleq proof with a message
success = dleq_verify_proof(A, B, C, proof, m=message)
self.assertTrue(success)
# flip a random bit in the dleq proof and check that verification fails
for _ in range(5):
proof_damaged = list(proof)
proof_damaged[random.randrange(len(proof))] ^= 1 << (
random.randrange(8)
)
success = dleq_verify_proof(A, B, C, bytes(proof_damaged), m=message)
self.assertFalse(success)
================================================
FILE: bip-0374/run_test_vectors.py
================================================
#!/usr/bin/env python3
"""Run the BIP-DLEQ test vectors."""
import csv
from pathlib import Path
import sys
from reference import (
dleq_generate_proof,
dleq_verify_proof,
)
from secp256k1lab.secp256k1 import GE
FILENAME_GENERATE_PROOF_TEST = Path(__file__).parent / 'test_vectors_generate_proof.csv'
FILENAME_VERIFY_PROOF_TEST = Path(__file__).parent / 'test_vectors_verify_proof.csv'
all_passed = True
print("-----------------------------------------")
print("----- Proof generation test vectors -----")
print("-----------------------------------------")
with open(FILENAME_GENERATE_PROOF_TEST, newline='') as csvfile:
reader = csv.reader(csvfile)
next(reader)
for row in reader:
(index, point_G_hex, seckey_a_hex, point_B_hex, aux_rand_hex, msg_hex, result_str, comment) = row
G = GE() if point_G_hex == 'INFINITY' else GE.from_bytes(bytes.fromhex(point_G_hex))
a = int.from_bytes(bytes.fromhex(seckey_a_hex), 'big')
B = GE() if point_B_hex == 'INFINITY' else GE.from_bytes(bytes.fromhex(point_B_hex))
aux_rand = bytes.fromhex(aux_rand_hex)
msg = bytes.fromhex(msg_hex)
if msg == b"": msg = None
print('Test vector', ('#' + index).rjust(3, ' ') + ':' + f' ({comment})')
expected_result = None if result_str == 'INVALID' else bytes.fromhex(result_str)
actual_result = dleq_generate_proof(a, B, aux_rand, G=G, m=msg)
if expected_result == actual_result:
print(' * Passed proof generation test.')
else:
print(' * Failed proof generation test.')
print(' Expected proof: ', expected_result.hex() if expected_result is not None else 'INVALID')
print(' Actual proof: ', actual_result.hex() if actual_result is not None else 'INVALID')
all_passed = False
print()
print("-------------------------------------------")
print("----- Proof verification test vectors -----")
print("-------------------------------------------")
with open(FILENAME_VERIFY_PROOF_TEST, newline='') as csvfile:
reader = csv.reader(csvfile)
next(reader)
for row in reader:
(index, point_G_hex, point_A_hex, point_B_hex, point_C_hex, proof_hex, msg_hex, result_success, comment) = row
G = GE() if point_G_hex == 'INFINITY' else GE.from_bytes(bytes.fromhex(point_G_hex))
A = GE() if point_A_hex == 'INFINITY' else GE.from_bytes(bytes.fromhex(point_A_hex))
B = GE() if point_B_hex == 'INFINITY' else GE.from_bytes(bytes.fromhex(point_B_hex))
C = GE() if point_C_hex == 'INFINITY' else GE.from_bytes(bytes.fromhex(point_C_hex))
proof = bytes.fromhex(proof_hex)
msg = bytes.fromhex(msg_hex)
if msg == b"": msg = None
print('Test vector', ('#' + index).rjust(3, ' ') + ':' + f' ({comment})')
expected_result = result_success == 'TRUE'
actual_result = dleq_verify_proof(A, B, C, proof, G=G, m=msg)
if expected_result == actual_result:
print(' * Passed proof verification test.')
else:
print(' * Failed proof verification test.')
print(' Expected verification result: ', expected_result)
print(' Actual verification result: ', actual_result)
all_passed = False
print()
if all_passed:
print('All test vectors passed.')
sys.exit(0)
else:
print('Some test vectors failed.')
sys.exit(1)
================================================
FILE: bip-0374/secp256k1lab/.github/workflows/main.yml
================================================
name: Tests
on: [push, pull_request]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
- run: uvx ruff check .
mypy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v5
- run: uvx mypy .
================================================
FILE: bip-0374/secp256k1lab/.python-version
================================================
3.9
================================================
FILE: bip-0374/secp256k1lab/CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2025-03-31
Initial release.
================================================
FILE: bip-0374/secp256k1lab/COPYING
================================================
The MIT License (MIT)
Copyright (c) 2009-2024 The Bitcoin Core developers
Copyright (c) 2009-2024 Bitcoin Developers
Copyright (c) 2025- The secp256k1lab Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: bip-0374/secp256k1lab/README.md
================================================
secp256k1lab
============

An INSECURE implementation of the secp256k1 elliptic curve and related cryptographic schemes written in Python, intended for prototyping, experimentation and education.
Features:
* Low-level secp256k1 field and group arithmetic.
* Schnorr signing/verification and key generation according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
* ECDH key exchange.
WARNING: The code in this library is slow and trivially vulnerable to side channel attacks.
================================================
FILE: bip-0374/secp256k1lab/pyproject.toml
================================================
[project]
name = "secp256k1lab"
version = "1.0.0"
description = "An INSECURE implementation of the secp256k1 elliptic curve and related cryptographic schemes, intended for prototyping, experimentation and education"
readme = "README.md"
authors = [
{ name = "Pieter Wuille", email = "pieter@wuille.net" },
{ name = "Tim Ruffing", email = "me@real-or-random.org" },
{ name = "Jonas Nick", email = "jonasd.nick@gmail.com" },
{ name = "Sebastian Falbesoner", email = "sebastian.falbesoner@gmail.com" }
]
maintainers = [
{ name = "Tim Ruffing", email = "me@real-or-random.org" },
{ name = "Jonas Nick", email = "jonasd.nick@gmail.com" },
{ name = "Sebastian Falbesoner", email = "sebastian.falbesoner@gmail.com" }
]
requires-python = ">=3.9"
license = "MIT"
license-files = ["COPYING"]
keywords = ["secp256k1", "elliptic curves", "cryptography", "Bitcoin"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Topic :: Security :: Cryptography",
]
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/__init__.py
================================================
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/bip340.py
================================================
# The following functions are based on the BIP 340 reference implementation:
# https://github.com/bitcoin/bips/blob/master/bip-0340/reference.py
from .secp256k1 import FE, GE, G
from .util import int_from_bytes, bytes_from_int, xor_bytes, tagged_hash
def pubkey_gen(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
P = d0 * G
assert not P.infinity
return P.to_bytes_xonly()
def schnorr_sign(
msg: bytes, seckey: bytes, aux_rand: bytes, tag_prefix: str = "BIP0340"
) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
if len(aux_rand) != 32:
raise ValueError("aux_rand must be 32 bytes instead of %i." % len(aux_rand))
P = d0 * G
assert not P.infinity
d = d0 if P.has_even_y() else GE.ORDER - d0
t = xor_bytes(bytes_from_int(d), tagged_hash(tag_prefix + "/aux", aux_rand))
k0 = (
int_from_bytes(tagged_hash(tag_prefix + "/nonce", t + P.to_bytes_xonly() + msg))
% GE.ORDER
)
if k0 == 0:
raise RuntimeError("Failure. This happens only with negligible probability.")
R = k0 * G
assert not R.infinity
k = k0 if R.has_even_y() else GE.ORDER - k0
e = (
int_from_bytes(
tagged_hash(
tag_prefix + "/challenge", R.to_bytes_xonly() + P.to_bytes_xonly() + msg
)
)
% GE.ORDER
)
sig = R.to_bytes_xonly() + bytes_from_int((k + e * d) % GE.ORDER)
assert schnorr_verify(msg, P.to_bytes_xonly(), sig, tag_prefix=tag_prefix)
return sig
def schnorr_verify(
msg: bytes, pubkey: bytes, sig: bytes, tag_prefix: str = "BIP0340"
) -> bool:
if len(pubkey) != 32:
raise ValueError("The public key must be a 32-byte array.")
if len(sig) != 64:
raise ValueError("The signature must be a 64-byte array.")
try:
P = GE.from_bytes_xonly(pubkey)
except ValueError:
return False
r = int_from_bytes(sig[0:32])
s = int_from_bytes(sig[32:64])
if (r >= FE.SIZE) or (s >= GE.ORDER):
return False
e = (
int_from_bytes(tagged_hash(tag_prefix + "/challenge", sig[0:32] + pubkey + msg))
% GE.ORDER
)
R = s * G - e * P
if R.infinity or (not R.has_even_y()) or (R.x != r):
return False
return True
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/ecdh.py
================================================
import hashlib
from .secp256k1 import GE, Scalar
def ecdh_compressed_in_raw_out(seckey: bytes, pubkey: bytes) -> GE:
"""TODO"""
shared_secret = Scalar.from_bytes_checked(seckey) * GE.from_bytes_compressed(pubkey)
assert not shared_secret.infinity # prime-order group
return shared_secret
def ecdh_libsecp256k1(seckey: bytes, pubkey: bytes) -> bytes:
"""TODO"""
shared_secret = ecdh_compressed_in_raw_out(seckey, pubkey)
return hashlib.sha256(shared_secret.to_bytes_compressed()).digest()
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/keys.py
================================================
from .secp256k1 import GE, G
from .util import int_from_bytes
# The following function is based on the BIP 327 reference implementation
# https://github.com/bitcoin/bips/blob/master/bip-0327/reference.py
# Return the plain public key corresponding to a given secret key
def pubkey_gen_plain(seckey: bytes) -> bytes:
d0 = int_from_bytes(seckey)
if not (1 <= d0 <= GE.ORDER - 1):
raise ValueError("The secret key must be an integer in the range 1..n-1.")
P = d0 * G
assert not P.infinity
return P.to_bytes_compressed()
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/py.typed
================================================
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/secp256k1.py
================================================
# Copyright (c) 2022-2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test-only implementation of low-level secp256k1 field and group arithmetic
It is designed for ease of understanding, not performance.
WARNING: This code is slow and trivially vulnerable to side channel attacks. Do not use for
anything but tests.
Exports:
* FE: class for secp256k1 field elements
* GE: class for secp256k1 group elements
* G: the secp256k1 generator point
"""
# TODO Docstrings of methods still say "field element"
class APrimeFE:
"""Objects of this class represent elements of a prime field.
They are represented internally in numerator / denominator form, in order to delay inversions.
"""
# The size of the field (also its modulus and characteristic).
SIZE: int
def __init__(self, a=0, b=1):
"""Initialize a field element a/b; both a and b can be ints or field elements."""
if isinstance(a, type(self)):
num = a._num
den = a._den
else:
num = a % self.SIZE
den = 1
if isinstance(b, type(self)):
den = (den * b._num) % self.SIZE
num = (num * b._den) % self.SIZE
else:
den = (den * b) % self.SIZE
assert den != 0
if num == 0:
den = 1
self._num = num
self._den = den
def __add__(self, a):
"""Compute the sum of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._den + self._den * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num + self._den * a, self._den)
return NotImplemented
def __radd__(self, a):
"""Compute the sum of an integer and a field element."""
return type(self)(a) + self
@classmethod
# REVIEW This should be
# def sum(cls, *es: Iterable[Self]) -> Self:
# but Self needs the typing_extension package on Python <= 3.12.
def sum(cls, *es):
"""Compute the sum of field elements.
sum(a, b, c, ...) is identical to (0 + a + b + c + ...)."""
return sum(es, start=cls(0))
def __sub__(self, a):
"""Compute the difference of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._den - self._den * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num - self._den * a, self._den)
return NotImplemented
def __rsub__(self, a):
"""Compute the difference of an integer and a field element."""
return type(self)(a) - self
def __mul__(self, a):
"""Compute the product of two field elements (second may be int)."""
if isinstance(a, type(self)):
return type(self)(self._num * a._num, self._den * a._den)
if isinstance(a, int):
return type(self)(self._num * a, self._den)
return NotImplemented
def __rmul__(self, a):
"""Compute the product of an integer with a field element."""
return type(self)(a) * self
def __truediv__(self, a):
"""Compute the ratio of two field elements (second may be int)."""
if isinstance(a, type(self)) or isinstance(a, int):
return type(self)(self, a)
return NotImplemented
def __pow__(self, a):
"""Raise a field element to an integer power."""
return type(self)(pow(self._num, a, self.SIZE), pow(self._den, a, self.SIZE))
def __neg__(self):
"""Negate a field element."""
return type(self)(-self._num, self._den)
def __int__(self):
"""Convert a field element to an integer in range 0..SIZE-1. The result is cached."""
if self._den != 1:
self._num = (self._num * pow(self._den, -1, self.SIZE)) % self.SIZE
self._den = 1
return self._num
def sqrt(self):
"""Compute the square root of a field element if it exists (None otherwise)."""
raise NotImplementedError
def is_square(self):
"""Determine if this field element has a square root."""
# A more efficient algorithm is possible here (Jacobi symbol).
return self.sqrt() is not None
def is_even(self):
"""Determine whether this field element, represented as integer in 0..SIZE-1, is even."""
return int(self) & 1 == 0
def __eq__(self, a):
"""Check whether two field elements are equal (second may be an int)."""
if isinstance(a, type(self)):
return (self._num * a._den - self._den * a._num) % self.SIZE == 0
return (self._num - self._den * a) % self.SIZE == 0
def to_bytes(self):
"""Convert a field element to a 32-byte array (BE byte order)."""
return int(self).to_bytes(32, 'big')
@classmethod
def from_int_checked(cls, v):
"""Convert an integer to a field element (no overflow allowed)."""
if v >= cls.SIZE:
raise ValueError
return cls(v)
@classmethod
def from_int_wrapping(cls, v):
"""Convert an integer to a field element (reduced modulo SIZE)."""
return cls(v % cls.SIZE)
@classmethod
def from_bytes_checked(cls, b):
"""Convert a 32-byte array to a field element (BE byte order, no overflow allowed)."""
v = int.from_bytes(b, 'big')
return cls.from_int_checked(v)
@classmethod
def from_bytes_wrapping(cls, b):
"""Convert a 32-byte array to a field element (BE byte order, reduced modulo SIZE)."""
v = int.from_bytes(b, 'big')
return cls.from_int_wrapping(v)
def __str__(self):
"""Convert this field element to a 64 character hex string."""
return f"{int(self):064x}"
def __repr__(self):
"""Get a string representation of this field element."""
return f"{type(self).__qualname__}(0x{int(self):x})"
class FE(APrimeFE):
SIZE = 2**256 - 2**32 - 977
def sqrt(self):
# Due to the fact that our modulus p is of the form (p % 4) == 3, the Tonelli-Shanks
# algorithm (https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm) is simply
# raising the argument to the power (p + 1) / 4.
# To see why: (p-1) % 2 = 0, so 2 divides the order of the multiplicative group,
# and thus only half of the non-zero field elements are squares. An element a is
# a (nonzero) square when Euler's criterion, a^((p-1)/2) = 1 (mod p), holds. We're
# looking for x such that x^2 = a (mod p). Given a^((p-1)/2) = 1, that is equivalent
# to x^2 = a^(1 + (p-1)/2) mod p. As (1 + (p-1)/2) is even, this is equivalent to
# x = a^((1 + (p-1)/2)/2) mod p, or x = a^((p+1)/4) mod p.
v = int(self)
s = pow(v, (self.SIZE + 1) // 4, self.SIZE)
if s**2 % self.SIZE == v:
return type(self)(s)
return None
class Scalar(APrimeFE):
"""TODO Docstring"""
SIZE = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
class GE:
"""Objects of this class represent secp256k1 group elements (curve points or infinity)
GE objects are immutable.
Normal points on the curve have fields:
* x: the x coordinate (a field element)
* y: the y coordinate (a field element, satisfying y^2 = x^3 + 7)
* infinity: False
The point at infinity has field:
* infinity: True
"""
# TODO The following two class attributes should probably be just getters as
# classmethods to enforce immutability. Unfortunately Python makes it hard
# to create "classproperties". `G` could then also be just a classmethod.
# Order of the group (number of points on the curve, plus 1 for infinity)
ORDER = Scalar.SIZE
# Number of valid distinct x coordinates on the curve.
ORDER_HALF = ORDER // 2
@property
def infinity(self):
"""Whether the group element is the point at infinity."""
return self._infinity
@property
def x(self):
"""The x coordinate (a field element) of a non-infinite group element."""
assert not self.infinity
return self._x
@property
def y(self):
"""The y coordinate (a field element) of a non-infinite group element."""
assert not self.infinity
return self._y
def __init__(self, x=None, y=None):
"""Initialize a group element with specified x and y coordinates, or infinity."""
if x is None:
# Initialize as infinity.
assert y is None
self._infinity = True
else:
# Initialize as point on the curve (and check that it is).
fx = FE(x)
fy = FE(y)
assert fy**2 == fx**3 + 7
self._infinity = False
self._x = fx
self._y = fy
def __add__(self, a):
"""Add two group elements together."""
# Deal with infinity: a + infinity == infinity + a == a.
if self.infinity:
return a
if a.infinity:
return self
if self.x == a.x:
if self.y != a.y:
# A point added to its own negation is infinity.
assert self.y + a.y == 0
return GE()
else:
# For identical inputs, use the tangent (doubling formula).
lam = (3 * self.x**2) / (2 * self.y)
else:
# For distinct inputs, use the line through both points (adding formula).
lam = (self.y - a.y) / (self.x - a.x)
# Determine point opposite to the intersection of that line with the curve.
x = lam**2 - (self.x + a.x)
y = lam * (self.x - x) - self.y
return GE(x, y)
@staticmethod
def sum(*ps):
"""Compute the sum of group elements.
GE.sum(a, b, c, ...) is identical to (GE() + a + b + c + ...)."""
return sum(ps, start=GE())
@staticmethod
def batch_mul(*aps):
"""Compute a (batch) scalar group element multiplication.
GE.batch_mul((a1, p1), (a2, p2), (a3, p3)) is identical to a1*p1 + a2*p2 + a3*p3,
but more efficient."""
# Reduce all the scalars modulo order first (so we can deal with negatives etc).
naps = [(int(a), p) for a, p in aps]
# Start with point at infinity.
r = GE()
# Iterate over all bit positions, from high to low.
for i in range(255, -1, -1):
# Double what we have so far.
r = r + r
# Add then add the points for which the corresponding scalar bit is set.
for (a, p) in naps:
if (a >> i) & 1:
r += p
return r
def __rmul__(self, a):
"""Multiply an integer with a group element."""
if self == G:
return FAST_G.mul(Scalar(a))
return GE.batch_mul((Scalar(a), self))
def __neg__(self):
"""Compute the negation of a group element."""
if self.infinity:
return self
return GE(self.x, -self.y)
def __sub__(self, a):
"""Subtract a group element from another."""
return self + (-a)
def __eq__(self, a):
"""Check if two group elements are equal."""
return (self - a).infinity
def has_even_y(self):
"""Determine whether a non-infinity group element has an even y coordinate."""
assert not self.infinity
return self.y.is_even()
def to_bytes_compressed(self):
"""Convert a non-infinite group element to 33-byte compressed encoding."""
assert not self.infinity
return bytes([3 - self.y.is_even()]) + self.x.to_bytes()
def to_bytes_compressed_with_infinity(self):
"""Convert a group element to 33-byte compressed encoding, mapping infinity to zeros."""
if self.infinity:
return 33 * b"\x00"
return self.to_bytes_compressed()
def to_bytes_uncompressed(self):
"""Convert a non-infinite group element to 65-byte uncompressed encoding."""
assert not self.infinity
return b'\x04' + self.x.to_bytes() + self.y.to_bytes()
def to_bytes_xonly(self):
"""Convert (the x coordinate of) a non-infinite group element to 32-byte xonly encoding."""
assert not self.infinity
return self.x.to_bytes()
@staticmethod
def lift_x(x):
"""Return group element with specified field element as x coordinate (and even y)."""
y = (FE(x)**3 + 7).sqrt()
if y is None:
raise ValueError
if not y.is_even():
y = -y
return GE(x, y)
@staticmethod
def from_bytes_compressed(b):
"""Convert a compressed to a group element."""
assert len(b) == 33
if b[0] != 2 and b[0] != 3:
raise ValueError
x = FE.from_bytes_checked(b[1:])
r = GE.lift_x(x)
if b[0] == 3:
r = -r
return r
@staticmethod
def from_bytes_uncompressed(b):
"""Convert an uncompressed to a group element."""
assert len(b) == 65
if b[0] != 4:
raise ValueError
x = FE.from_bytes_checked(b[1:33])
y = FE.from_bytes_checked(b[33:])
if y**2 != x**3 + 7:
raise ValueError
return GE(x, y)
@staticmethod
def from_bytes(b):
"""Convert a compressed or uncompressed encoding to a group element."""
assert len(b) in (33, 65)
if len(b) == 33:
return GE.from_bytes_compressed(b)
else:
return GE.from_bytes_uncompressed(b)
@staticmethod
def from_bytes_xonly(b):
"""Convert a point given in xonly encoding to a group element."""
assert len(b) == 32
x = FE.from_bytes_checked(b)
r = GE.lift_x(x)
return r
@staticmethod
def is_valid_x(x):
"""Determine whether the provided field element is a valid X coordinate."""
return (FE(x)**3 + 7).is_square()
def __str__(self):
"""Convert this group element to a string."""
if self.infinity:
return "(inf)"
return f"({self.x},{self.y})"
def __repr__(self):
"""Get a string representation for this group element."""
if self.infinity:
return "GE()"
return f"GE(0x{int(self.x):x},0x{int(self.y):x})"
def __hash__(self):
"""Compute a non-cryptographic hash of the group element."""
if self.infinity:
return 0 # 0 is not a valid x coordinate
return int(self.x)
# The secp256k1 generator point
G = GE.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
class FastGEMul:
"""Table for fast multiplication with a constant group element.
Speed up scalar multiplication with a fixed point P by using a precomputed lookup table with
its powers of 2:
table = [P, 2*P, 4*P, (2^3)*P, (2^4)*P, ..., (2^255)*P]
During multiplication, the points corresponding to each bit set in the scalar are added up,
i.e. on average ~128 point additions take place.
"""
def __init__(self, p):
self.table = [p] # table[i] = (2^i) * p
for _ in range(255):
p = p + p
self.table.append(p)
def mul(self, a):
result = GE()
a = int(a)
for bit in range(a.bit_length()):
if a & (1 << bit):
result += self.table[bit]
return result
# Precomputed table with multiples of G for fast multiplication
FAST_G = FastGEMul(G)
================================================
FILE: bip-0374/secp256k1lab/src/secp256k1lab/util.py
================================================
import hashlib
# This implementation can be sped up by storing the midstate after hashing
# tag_hash instead of rehashing it all the time.
def tagged_hash(tag: str, msg: bytes) -> bytes:
tag_hash = hashlib.sha256(tag.encode()).digest()
return hashlib.sha256(tag_hash + tag_hash + msg).digest()
def bytes_from_int(x: int) -> bytes:
return x.to_bytes(32, byteorder="big")
def xor_bytes(b0: bytes, b1: bytes) -> bytes:
return bytes(x ^ y for (x, y) in zip(b0, b1))
def int_from_bytes(b: bytes) -> int:
return int.from_bytes(b, byteorder="big")
def hash_sha256(b: bytes) -> bytes:
return hashlib.sha256(b).digest()
================================================
FILE: bip-0374/test_vectors_generate_proof.csv
================================================
index,point_G,scalar_a,point_B,auxrand_r,message,result_proof,comment
0,02cef38f55e78b321a1f785cb1c6e33dfcef9784c18bdc4e279801c449ccdfb88e,07ff93d43f1012a5d4a44aba55240212ed39c87b3344e46757d99f24177fc576,02dad4b35c2379ba8334c9a5dda8f6e6d5cd575a7cc9d3ca4faaac51839daaa30f,cb979b0fc8ccc7f237751e719d992fcc324b6500af33999cd54a3e5c05fb1ea4,efb07d4b382d3da1079fbf24df623ba6c2e4c764993bbfa6dd7a4fe4aaf33859,7e7e934169e0bf4706e6b29e5a621c7fe199a524744a25af80071e111c0e2e94118e730d8add118dd2ee4f7d1cc183e1b87168362d1a6f85c16d8671a3fc7a8a,Success case 1
1,02464e351831efedb755223cabbf664f10564b4742c725c023034bc928ed339e0e,f4e9172285393c6ada994c811b3e50fc47e96421ea7e54f4a4e459528d4cf562,03fe589b0fa23f060f6d4d1e76b9b19d5bb3db0e56d39a4303913de0e706463008,75f12482b9209dae12230ea1f8bf69723a1b447d361db8f510dd9ab33556fd4c,76184ce9eea5b339ebf5304b57452c1ada1466610f0a58574d6c496798cee04b,6b4521a8363a7ebc5d95ac6ec6b64db81fcf21795187d7c4600c42b73fb4fb9870ab8d106c0fd2d292c1710e10437b20575ddb3cb32eb77a5618d94ddba600f2,Success case 2
2,0222db2054fef98344352a13bc0304a71da7b5e9a2f7fd1f3c9f3519a3d9377fb7,589476913e763b60d5c2a5bfb39230ec669caac1b44312e9bcd2d3f4473abfef,03bc7a19970c812118f74ba659b491e00dade6096ff62d1afe032a92b8671498ed,4da1c4c4b0f9db4eb6b2e5cb648d7e8a0aa35aa5c4ec4d07f096e0e03deca366,66503623468a78cfcef47888c85e0010ecd897f441d263448bfc7a89b882ab20,12aa2aa469b3c037871a09d18ab18d3840219b1ed169f6ef9deae6d927949884a459705ae89a57522224ce3482dee00a41ba511188ae60efdeb736223eb66e7b,Success case 3
3,03dfa65bd3711eba75fa1996a0c1d95a4419bd835304152d9aa6efa590670f2af6,24d0ed3fc189eb1b64e5dc9dd4af0f3c8c143b0c79cb5fcca0dfa08a11cc60a1,03b51081323d38fb0b75f0c1ec6755fdb79c239c327ca11269fe68ba8a878b704e,31a68d6db27f6404bbceff646ff1b26a34704a0105a36c5a845d0257cea19c9b,f2996b3766d123a949e65541baf1d89d446360d05af51bd93f0445d8c472c952,7907653d29c5722ae44510e7f2839f253450aefc833b7e0a3b38384032f847f2cf41136b2fe6a558ad125287d20c0117f2a30c4ac0c4cebbcfa1dd3a69d84200,Success case 4
4,02b15de5a3aefcfe2473916c76e619b5800ac7250ef93a9e6e0dd1505104fc58e7,73fffa796edb72d111b5e0bbda1608f098ac98120796f971b438691e1bfb7b96,03a4692be176ff89a972de9cc407083096847b950d1cae72b947665a3d5f4c2f01,1cdfb4d7cce5e50783299896a471a44e6aa2c5e2100d6c37987c6b40503c6162,0ceb45f560f2cf6b76a139ffe2c47c5ca6d26d6a3a210e59f197413bbec040b4,02277ca5a7acfe8ae13c2db4a8f74489d0ba100ed8b082381ddb6522c4510718ab88b8dbbd785c388ade79586cf6416f3c47a79670af84abccc788a5d9f2e327,Success case 5
5,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,c08ca8e0bb59769fc6a4e078456284e00ea34f65add988c246e1bba85824ccdc,034bccb1c570ac1f3bc42d61fe35de605b99626501ccb20297e1acbbf2d7152aa1,c8d7056abd4726eb5a0f198740af14d6c1f0c16e5d7a37eaec621b661e669ac4,,503562d36910cd2d61a4d07c8ff680265c713e63dde0dcb88e6ea3c58597bdc05b86db9af95eccc475ce2177f941c118fefed20227d4ce8ce9557cb008758de6,Success case 6
6,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,8e641ba6bf7f64eec76005a29585a5035376375f33e331215aedfe03b8e80e7a,0231c64e3efa506fdad6aad0f6084d5f6739de7f448d7e66f9d22f842638f41d60,02a7b2e2f5a5e9b1078dbb160502a32491fe80a091e91dd92cf77b0b7d90970f,35841ca532846e1cdd23a3d107824343584f88eff580929469865eae8355ee3c,5c7b27a33210750e9de8679d9f43497cf9f12ac642cde0a1fc26443aa2fc89bf71aabf7bac89f5d8a96cbe86daba155fa74d6f3e111136179e53b04eb6d7807f,Success case 7
7,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,cfb9a7ecc49bea4f2e2ee34c38a6f48b5cd5bd06f4e4d4ffb45905b3d26db842,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,d38466b77484154a3fcb3151094c1c8a845c73a3c036b3a8ebffd8ef62c9047f,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,Success case 8
8,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,0000000000000000000000000000000000000000000000000000000000000000,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,d38466b77484154a3fcb3151094c1c8a845c73a3c036b3a8ebffd8ef62c9047f,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,INVALID,Failure case (a=0)
9,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,d38466b77484154a3fcb3151094c1c8a845c73a3c036b3a8ebffd8ef62c9047f,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,INVALID,Failure case (a=N [group order])
10,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,cfb9a7ecc49bea4f2e2ee34c38a6f48b5cd5bd06f4e4d4ffb45905b3d26db842,INFINITY,d38466b77484154a3fcb3151094c1c8a845c73a3c036b3a8ebffd8ef62c9047f,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,INVALID,Failure case (B is point at infinity)
================================================
FILE: bip-0374/test_vectors_verify_proof.csv
================================================
index,point_G,point_A,point_B,point_C,proof,message,result_success,comment
0,02cef38f55e78b321a1f785cb1c6e33dfcef9784c18bdc4e279801c449ccdfb88e,02b540b22c2c5ef0dc886abdaad27498453d893265560bc08a187319af6f845f58,02dad4b35c2379ba8334c9a5dda8f6e6d5cd575a7cc9d3ca4faaac51839daaa30f,03fefe00951dcd0ef10b12523393c2b8113119de4fdeeab320694e96bdccd2775b,7e7e934169e0bf4706e6b29e5a621c7fe199a524744a25af80071e111c0e2e94118e730d8add118dd2ee4f7d1cc183e1b87168362d1a6f85c16d8671a3fc7a8a,efb07d4b382d3da1079fbf24df623ba6c2e4c764993bbfa6dd7a4fe4aaf33859,TRUE,Success case 1
1,02464e351831efedb755223cabbf664f10564b4742c725c023034bc928ed339e0e,032baaf1b10845a51b551196984a91efe2adf9d41b92bec3927218e6e4ca344002,03fe589b0fa23f060f6d4d1e76b9b19d5bb3db0e56d39a4303913de0e706463008,031f59aa1df22190e00380d8c5941adf899f596593765a1251005fd24f2bf7c884,6b4521a8363a7ebc5d95ac6ec6b64db81fcf21795187d7c4600c42b73fb4fb9870ab8d106c0fd2d292c1710e10437b20575ddb3cb32eb77a5618d94ddba600f2,76184ce9eea5b339ebf5304b57452c1ada1466610f0a58574d6c496798cee04b,TRUE,Success case 2
2,0222db2054fef98344352a13bc0304a71da7b5e9a2f7fd1f3c9f3519a3d9377fb7,026aa26fcd626f8f55295859e9f8dd1f103149dd64d77c2bbba1bcf33bb37ebaa2,03bc7a19970c812118f74ba659b491e00dade6096ff62d1afe032a92b8671498ed,035628d1a69910daef614c7cae68d71ece55c5908af2360629e25c1b7de21eeb4b,12aa2aa469b3c037871a09d18ab18d3840219b1ed169f6ef9deae6d927949884a459705ae89a57522224ce3482dee00a41ba511188ae60efdeb736223eb66e7b,66503623468a78cfcef47888c85e0010ecd897f441d263448bfc7a89b882ab20,TRUE,Success case 3
3,03dfa65bd3711eba75fa1996a0c1d95a4419bd835304152d9aa6efa590670f2af6,031bf61ba89009ee1266c9003a72e8e07d77877678ccda7f15325aadcd64ed186b,03b51081323d38fb0b75f0c1ec6755fdb79c239c327ca11269fe68ba8a878b704e,02d1b1f37a80217ba73785babfa63251052775f9d3ca65060054033288b7a3f66b,7907653d29c5722ae44510e7f2839f253450aefc833b7e0a3b38384032f847f2cf41136b2fe6a558ad125287d20c0117f2a30c4ac0c4cebbcfa1dd3a69d84200,f2996b3766d123a949e65541baf1d89d446360d05af51bd93f0445d8c472c952,TRUE,Success case 4
4,02b15de5a3aefcfe2473916c76e619b5800ac7250ef93a9e6e0dd1505104fc58e7,0296c8e00dda60bb5565b77371ff913091978646b58ccf218bc591f68a75232e6e,03a4692be176ff89a972de9cc407083096847b950d1cae72b947665a3d5f4c2f01,03a7a7f9527fd387c2b2ce0c76669d646c78a3b470a4b34d3a2dabafc8505ef472,02277ca5a7acfe8ae13c2db4a8f74489d0ba100ed8b082381ddb6522c4510718ab88b8dbbd785c388ade79586cf6416f3c47a79670af84abccc788a5d9f2e327,0ceb45f560f2cf6b76a139ffe2c47c5ca6d26d6a3a210e59f197413bbec040b4,TRUE,Success case 5
5,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,02637b2c3ea8ca80b9caecc50f4134c86ae9cf7a269133e7afc71f30e3a3cda60c,034bccb1c570ac1f3bc42d61fe35de605b99626501ccb20297e1acbbf2d7152aa1,0285b826c8dd175805901906b6c9b4140a30cbcc94c6e7dcf36476038bf90d4718,503562d36910cd2d61a4d07c8ff680265c713e63dde0dcb88e6ea3c58597bdc05b86db9af95eccc475ce2177f941c118fefed20227d4ce8ce9557cb008758de6,,TRUE,Success case 6
6,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,02983a72b4cb44d4322641a7b2001900cd6ae0908a610546c73ed126accdba0514,0231c64e3efa506fdad6aad0f6084d5f6739de7f448d7e66f9d22f842638f41d60,03af1bc14b384eda28398df6a7900e567c5b6f6613cafce5027b98be015286f71b,5c7b27a33210750e9de8679d9f43497cf9f12ac642cde0a1fc26443aa2fc89bf71aabf7bac89f5d8a96cbe86daba155fa74d6f3e111136179e53b04eb6d7807f,35841ca532846e1cdd23a3d107824343584f88eff580929469865eae8355ee3c,TRUE,Success case 7
7,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,TRUE,Success case 8
8,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Swapped points case 1
9,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Swapped points case 2
10,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Swapped points case 3
11,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Swapped points case 4
12,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Swapped points case 5
13,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131ff090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb2d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Tampered proof (random bit-flip)
14,0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,03611410561c35dae13135e4ad8094baac9bbcf2f4e18498181a8ff8a6d43be9d9,021cb81121a00f89769903305a367ad3cc02d5b402b12c026e06ac94bde28cd608,03d9a98624c0c74fc7eebd39ed84175f80d03c774908e75ca737a0745d1c64e20a,78a5544afa75bf152653fe55fb76926f2f65131bf090972a0b0b37d310c28a6bde0e7bfacc10ac12d36f55316ba134b6ba0b844a65ae05cad53c0b296c6639bb,22616bb5fb6d7c68270f305122f2a09e833239c4b1c9a04e285119fb606ac794,FALSE,Tampered message (random bit-flip)
================================================
FILE: bip-0374.mediawiki
================================================
== Introduction ==
=== Abstract ===
This document proposes a standard for 64-byte zero-knowledge ''discrete logarithm equality proofs'' (DLEQ proofs) over an elliptic curve. For given elliptic curve points ''A'', ''B'', ''C'', ''G'', and a scalar ''a'' known only to the prover where ''A = a⋅G'' and ''C = a⋅B'', the prover proves knowledge of ''a'' without revealing anything about ''a''. This can, for instance, be useful in ECDH: if ''A'' and ''B'' are ECDH public keys, and ''C'' is their ECDH shared secret computed as ''C = a⋅B'', the proof establishes that the same secret key ''a'' is used for generating both ''A'' and ''C'' without revealing ''a''.
=== Copyright ===
This document is licensed under the 2-clause BSD license.
=== Motivation ===
[https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#specification BIP352] requires senders to compute output scripts using ECDH shared secrets from the same secret keys used to sign the inputs. Generating an incorrect signature will produce an invalid transaction that will be rejected by consensus. An incorrectly generated output script can still be consensus-valid, meaning funds may be lost if it gets broadcast.
By producing a DLEQ proof for the generated ECDH shared secrets, the signing entity can prove to other entities that the output scripts have been generated correctly without revealing the private keys.
== Specification ==
All conventions and notations are used as defined in [https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki#user-content-Notation BIP327].
=== Description ===
The basic proof generation uses a random scalar ''k'', the secret ''a'', and the point being proven ''C = a⋅B''.
* Let ''R1 = k⋅G''.
* Let ''R2 = k⋅B''.
* Let ''e = hash(R1 || R2)''.
* Let ''s = (k + e⋅a)''.
Providing only ''C'', ''e'' and ''s'' as a proof does not reveal ''a'' or ''k''.
Verifying the proof involves recreating ''R1'' and ''R2'' with only ''e'' and ''s'' as follows:
* Let ''R1 = s⋅G - e⋅A''.
* Let ''R2 = s⋅B - e⋅C''.
This can be verified by substituting ''s = (k + e⋅a)'':
* ''s⋅G - e⋅A = (k + e⋅a)⋅G - e⋅A = k⋅G + e⋅(a⋅G) - e⋅A = k⋅G + e⋅A - e⋅A = k⋅G''.
* ''s⋅B - e⋅C = (k + e⋅a)⋅B - e⋅C = k⋅B + e⋅(a⋅B) - e⋅C = k⋅B + e⋅C - e⋅C = k⋅B''.
Thus verifying ''e = hash(R1 || R2)'' proves the discrete logarithm equivalency of ''A'' and ''C''.
=== DLEQ Proof Generation ===
The following generates a proof that the result of ''a⋅B'' and the result of ''a⋅G'' are both generated from the same scalar ''a'' without having to reveal ''a''.
Input:
* The secret key ''a'': a 256-bit unsigned integer
* The public key ''B'': a point on the curve
* Auxiliary random data ''r'': a 32-byte array ''' Why include auxiliary random data?''' The auxiliary random data should be set to fresh randomness for each proof. The same rationale and recommendations from [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#default-signing BIP340] should be applied.
* The generator point ''G'': a point on the curve ''' Why include the generator point G as an input?''' While all other BIPs have used the generator point from secp256k1, passing it as an input here lets this algorithm be used for other curves.
* An optional message ''m'': a 32-byte array ''' Why include a message as an input?''' This could be useful for protocols that want to authorize on a compound statement, not just knowledge of a scalar. This allows the protocol to combine knowledge of the scalar and the statement.
The algorithm ''GenerateProof(a, B, r, G, m)'' is defined as:
* Fail if ''a = 0'' or ''a ≥ n''.
* Fail if ''is_infinite(B)''.
* Let ''A = a⋅G''.
* Let ''C = a⋅B''.
* Let ''t'' be the byte-wise xor of ''bytes(32, a)'' and ''hashBIP0374/aux(r)''.
* Let ''m' = m if m is provided, otherwise an empty byte array''.
* Let ''rand = hashBIP0374/nonce(t || cbytes(A) || cbytes(C) || m')''. ''' Why include the message in the rand computation?''' Not including the message in the rand computation could leak ''a'' if two proofs were constructed for the same ''a'', ''B'', and ''G'' but a different message ''m'' and an all-zero ''r''.
* Let ''k = int(rand) mod n''.
* Fail if ''k = 0''.
* Let ''R1 = k⋅G''.
* Let ''R2 = k⋅B''.
* Let ''e = int(hashBIP0374/challenge(cbytes(A) || cbytes(B) || cbytes(C) || cbytes(G) || cbytes(R1) || cbytes(R2) || m'))''.
* Let ''s = (k + e⋅a) mod n''.
* Let ''proof = bytes(32, e) || bytes(32, s)''.
* If ''VerifyProof(A, B, C, proof, G, m)'' (see below) returns failure, abort.
* Return the proof ''proof''.
=== DLEQ Proof Verification ===
The following verifies the proof generated in the previous section. If the following algorithm succeeds, the points ''A'' and ''C'' were both generated from the same scalar. The former from multiplying by ''G'', and the latter from multiplying by ''B''.
Input:
* The public key of the secret key used in the proof generation ''A'': a point on the curve
* The public key used in the proof generation ''B'': a point on the curve
* The result of multiplying the secret and public keys used in the proof generation ''C'': a point on the curve
* A proof ''proof'': a 64-byte array
* The generator point used in the proof generation ''G'': a point on the curve ''' Why include the generator point G as an input?''' While all other BIPs have used the generator point from Secp256k1, passing it as an input here lets this algorithm be used for other curves.
* An optional message ''m'': a 32-byte array ''' Why include a message as an input?''' This could be useful for protocols that want to authorize on a compound statement, not just knowledge of a scalar. This allows the protocol to combine knowledge of the scalar and the statement.
The algorithm ''VerifyProof(A, B, C, proof, G, m)'' is defined as:
* Fail if any of ''is_infinite(A)'', ''is_infinite(B)'', ''is_infinite(C)'', ''is_infinite(G)''
* Let ''e = int(proof[0:32])''.
* Let ''s = int(proof[32:64])''; fail if ''s ≥ n''.
* Let ''R1 = s⋅G - e⋅A''.
* Fail if ''is_infinite(R1)''.
* Let ''R2 = s⋅B - e⋅C''.
* Fail if ''is_infinite(R2)''.
* Let ''m' = m if m is provided, otherwise an empty byte array''.
* Fail if ''e ≠ int(hashBIP0374/challenge(cbytes(A) || cbytes(B) || cbytes(C) || cbytes(G) || cbytes(R1) || cbytes(R2) || m'))''.
* Return success iff no failure occurred before reaching this point.
==Backwards Compatibility==
This proposal is compatible with all older clients.
== Test Vectors and Reference Code ==
A reference python implementation is included [https://github.com/bitcoin/bips/blob/master/bip-0374/reference.py here].
It uses a vendored copy of the [https://github.com/secp256k1lab/secp256k1lab/ secp256k1lab] library at version 1.0.0
(commit [https://github.com/secp256k1lab/secp256k1lab/commit/44dc4bd893b8f03e621585e3bf255253e0e0fbfb
44dc4bd893b8f03e621585e3bf255253e0e0fbfb]).
Test vectors can be generated by running ./bip-0374/gen_test_vectors.py which will produce a CSV file of random test vectors for both generating and verifying proofs. These can be run against the reference implementation with ./bip-0374/run_test_vectors.py.
== Changelog ==
* 0.2.0 (2025-02-27):
** Add the message to the rand computation
* 0.1.0 (2024-12-26):
** Initial version
== Footnotes ==
== Acknowledgements ==
Thanks to josibake, Tim Ruffing, benma, stratospher, waxwing, Yuval Kogman and all others who
participated in discussions on this topic.
================================================
FILE: bip-0375.mediawiki
================================================
BIP: 375
Layer: Applications
Title: Sending Silent Payments with PSBTs
Authors: Andrew Toth
Ava Chow
josibake
Status: Draft
Type: Specification
Assigned: 2025-01-08
License: BSD-2-Clause
Discussion: https://groups.google.com/g/bitcoindev/c/5G5wzqUXyk4
Requires: 352, 370, 374
==Introduction==
===Abstract===
This document proposes additional fields and updated role responsibilities for BIP370 PSBTv2
which adds support for sending to silent payments as described in BIP352.
===Copyright===
This BIP is licensed under the 2-clause BSD license.
===Motivation===
Partially Signed Bitcoin Transaction Version 2 as described in BIP370 is not compatible with sending to silent payments as described in BIP352.
In particular, the output script of a silent payment cannot be computed until after all transaction inputs have been added.
Additionally, the silent payment outputs computed by a signer must be verifiable by other entities, otherwise funds could be sent to an incorrect output script.
Therefore, new fields and role responsibilities must be added to carry, compute, and verify the silent payment data.
==Specification==
This document specifies new fields and new field inclusion/exclusion requirements.
The new global types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Silent Payment Global ECDH Share
| PSBT_GLOBAL_SP_ECDH_SHARE = 0x07
| <33 byte scan key>
| The scan key that this ECDH share is for.
| <33 byte share>
| An ECDH share for a scan key. The ECDH shared is computed with ''a * B_scan'', where ''a'' is the sum of all private keys of all eligible inputs, and ''B_scan'' is the scan key of a recipient.
|
| 0
| 2
|-
| Silent Payment Global DLEQ Proof
| PSBT_GLOBAL_SP_DLEQ = 0x08
| <33 byte scan key>
| The scan key that this proof covers.
| <64-byte proof>
| A BIP374 DLEQ proof computed for the matching ECDH share.
|
| 0
| 2
|}
The new per-input types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Silent Payment Input ECDH Share
| PSBT_IN_SP_ECDH_SHARE = 0x1d
| <33 byte scan key>
| The scan key that this ECDH share is for.
| <33 byte share>
| An ECDH share for a scan key. The ECDH shared is computed with ''a * B_scan'', where ''a'' is the private key of the corresponding prevout public key, and ''B_scan'' is the scan key of a recipient.
|
| 0
| 2
|-
| Silent Payment Input DLEQ Proof
| PSBT_IN_SP_DLEQ = 0x1e
| <33 byte scan key>
| The scan key that this proof covers.
| <64-byte proof>
| A BIP374 DLEQ proof computed for the matching ECDH share.
|
| 0
| 2
|}
The new per-output types are defined as follows:
{|
! Name
!
!
! Description
!
! Description
! Versions Requiring Inclusion
! Versions Requiring Exclusion
! Versions Allowing Inclusion
|-
| Silent Payment Data
| PSBT_OUT_SP_V0_INFO = 0x09
| None
| No key data
| <33 byte scan key> <33 byte spend key>
| The scan and spend public keys from the silent payments address.
|
| 0
| 2
|-
| Silent Payment Label
| PSBT_OUT_SP_V0_LABEL = 0x0a
| None
| No key data
| <32-bit little endian uint label>
| The label to use to compute the spend key of the silent payments address to verify change.
|
| 0
| 2
|}
PSBT_OUT_SCRIPT is modified to be optional for outputs in silent payments capable PSBTs. If this field is not included in the output, then the field PSBT_OUT_SP_V0_INFO must be included.
If a PSBT_OUT_SCRIPT is not present for an output, then that output is being sent to a silent payment address represented by PSBT_OUT_SP_V0_INFO but the script has not yet been computed.
If both PSBT_OUT_SCRIPT and PSBT_OUT_SP_V0_INFO are present for an output, then the PSBT_OUT_SCRIPT is the computed output script corresponding to the silent payment address in PSBT_OUT_SP_V0_INFO.
If only PSBT_OUT_SCRIPT is present for an output, then the output is not being sent to a silent payment address.
===Unique Identification===
Silent payment capable PSBTs can be uniquely identified the same way as PSBTv2s, except when including silent payment outputs. If an output contains the PSBT_OUT_SP_V0_INFO field, it must use that field instead of PSBT_OUT_SCRIPT as the output script when creating the unsigned transaction used for unique identification. ''' Why use PSBT_OUT_SP_V0_INFO when serializing for a unique identifier?''' Since the same silent payment capable PSBT is valid whether or not a PSBT_OUT_SCRIPT is included in an output that has PSBT_OUT_SP_V0_INFO set, using the PSBT_OUT_SCRIPT if present for the unique identifier will cause malleability. The identifier will be different depending on whether PSBT_OUT_SCRIPT is present, so always using PSBT_OUT_SP_V0_INFO if it exists makes sure the PSBT is always identified uniquely.
The PSBT_OUT_SP_V0_INFO should be serialized as a zero byte for the version, followed by the 33 bytes of the scan key and then 33 bytes for the spend key.
==Roles==
This document modifies some existing roles.
===Constructor===
All rules must be followed from PSBTv2 for this role, with the following exception:
When an output is added, it must have either PSBT_OUT_SCRIPT or PSBT_OUT_SP_V0_INFO, or both, set.
Additionally to PSBTv2, the Constructor must also follow additional rules:
Inputs spending an output with script using Segwit version > 1 may only be added if there are no outputs with PSBT_OUT_SP_V0_INFO set.
Outputs with PSBT_OUT_SP_V0_INFO set may only be added if there are no inputs spending an output script using Segwit version > 1.
===Updater===
The updater should add a PSBT_IN_BIP32_DERIVATION for any p2wpkh, p2sh-p2wpkh, or p2pkh input so the public key is available for creating the ecdh_shared_secret when the private key is not known. If the updater does not want to reveal the fingerprint or derivation path, it can set the value of the field to zero.
====Change Detection====
Updaters may add two PSBT_OUT_BIP32_DERIVATION key-value-pairs with the corresponding derivation path of both the scan and spend keys. A label can be specified in PSBT_OUT_SP_V0_LABEL. The Signer can then use these fields to verify that the silent payment code is change.
===Signer===
All rules must be followed from PSBTv2 for this role. If there are any outputs with PSBT_OUT_SP_V0_INFO set, then the following additional rules must also be adhered to:
If any input is spending an output with script using Segwit version > 1, the Signer must fail.
For each output with PSBT_OUT_SP_V0_INFO set, the Signer should:
* Compute and set an ECDH share and DLEQ proof for each input it has the private key for, or set a global ECDH share and DLEQ proof if it has private keys for all eligible inputs.
* Verify the DLEQ proofs for all inputs it does not have the private keys for, or the global DLEQ proof if it is set.
* If all eligible inputs have an ECDH share or the global ECDH share is set, compute and set the PSBT_OUT_SCRIPT.
If the Signer sets any missing PSBT_OUT_SCRIPTs, it must set the Inputs Modifiable and Outputs Modifiable flags to False.
If any output does not have PSBT_OUT_SCRIPT set, the Signer must not yet add a signature.
The Signer should additionally compute the silent payment addresses, optionally showing this data to the user instead of the computed segwit v1 addresses.
If a sighash type is provided and there are silent payment outputs present, the signer must fail if the sighash type is not SIGHASH_ALL.
If a sighash type is not provided and there are silent payment outputs present, the signer must sign using SIGHASH_ALL. ''' Why use only SIGHASH_ALL?''' BIP352 allows signing with SIGHASH_NONE and SIGHASH_SINGLE. However, silent payment capable PSBTs compute the output scripts deterministically based on the number and position of silent payment codes with the same scan key. SIGHASH_NONE and SIGHASH_SINGLE allow changing the amount or position of silent payment codes with the same scan and spend keys, which would invalidate computed output scripts.
====Computing the ECDH Shares and DLEQ Proofs====
For each output with PSBT_OUT_SP_V0_INFO set, the Signer may generate a proof for other entities to generate the output scripts and verify that the output scripts were generated correctly.
If the Signer has the private keys for all eligible inputs, the Signer should generate a global ECDH share for each scan key ''Bscan'' as follows:
Using the notation from [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#specification BIP352]
* Let ''an'' be the sum of the private keys ''a'' of all eligible inputs
* Let ''C = an·Bscan''
Set the key as ''Bscan'' and the value as ''C'' for the PSBT_GLOBAL_SP_ECDH_SHARE field.
Compute the DLEQ proof for ''C'' using [https://github.com/bitcoin/bips/blob/master/bip-0374.mediawiki#user-content-DLEQ_Proof_Generation BIP374 GenerateProof] and passing ''an'' as ''a'' and ''Bscan'' as ''B''.
Set the key as ''Bscan'' and the value as the proof for the PSBT_GLOBAL_SP_DLEQ field.
If the Signer has the private keys for some eligible inputs or does not want to create a global ECDH share, the Signer should generate a per-input ECDH share for each scan key ''Bscan'' as follows:
Using the notation from [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#specification BIP352], for each eligible input:
* Let ''a'' be the private key of the input
* Let ''C = a·Bscan''
Set the key as ''Bscan'' and the value as ''C'' for the PSBT_IN_SP_ECDH_SHARE field of the input.
Compute the DLEQ proof for ''C'' using [https://github.com/bitcoin/bips/blob/master/bip-0374.mediawiki#user-content-DLEQ_Proof_Generation BIP374 GenerateProof] and passing ''Bscan'' as ''B''.
Set the key as ''Bscan'' and the value as the proof for the PSBT_IN_SP_DLEQ field of the input.
====Verifying the DLEQ Proof====
For each output with PSBT_OUT_SP_V0_INFO set, the Signer should verify the ECDH shares for all eligible inputs it does not have the private key for using the proofs provided by other Signers.
If PSBT_GLOBAL_SP_ECDH_SHARE and PSBT_GLOBAL_SP_DLEQ are set, verify as follows:
* Let ''An'' be the sum of the public keys ''A'' of all eligible inputs
Using [https://github.com/bitcoin/bips/blob/master/bip-0374.mediawiki#dleq-proof-verification BIP374 VerifyProof] and passing ''A'' as ''An'', ''B'' as ''Bscan'', ''C'' as the value of PSBT_GLOBAL_SP_ECDH_SHARE, and ''proof'' as the value of PSBT_GLOBAL_SP_DLEQ.
If PSBT_IN_SP_ECDH_SHARE and PSBT_IN_SP_DLEQ are set for a particular input, verify as follows:
Using [https://github.com/bitcoin/bips/blob/master/bip-0374.mediawiki#dleq-proof-verification BIP374 VerifyProof] and passing ''A'' as the public key of the input, ''B'' as ''Bscan'', ''C'' as the value of PSBT_IN_SP_ECDH_SHARE, and ''proof'' as the value of PSBT_IN_SP_DLEQ.
====Computing the Output Scripts====
Compute the PSBT_OUT_SCRIPT using the procedure in [https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#user-content-Creating_outputs BIP352] but substituting ''a·Bscan'' with the PSBT_GLOBAL_SP_ECDH_SHARE for that scan key if available, or the sum of all PSBT_IN_SP_ECDH_SHAREs for that scan key.
If there are multiple silent payment codes with the same scan key, sort the codes lexicographically in ascending order to determine the ordering of the ''k'' value.
If there are multiple silent payment codes with both the same scan and spend keys, sort the subgroup by output index in ascending order.
===Transaction Extractor===
For silent payment capable PSBTs, the transaction extractor should compute all output scripts for silent payment codes and verify they are correct using the ECDH shares and DLEQ proofs, otherwise fail.
==Backwards Compatibility==
Silent payment capable PSBTs are backwards compatible with PSBTv2 once all outputs have PSBT_OUT_SCRIPT set. Otherwise they are not backwards compatible.
==Test Vectors==
Todo
==Rationale==
==Reference implementation==
Todo
================================================
FILE: bip-0379.md
================================================
```
BIP: 379
Layer: Applications
Title: Miniscript
Authors: Pieter Wuille
Andrew Poelstra
Sanket Kanjalkar
Antoine Poinsot
Ava Chow
Status: Draft
Type: Informational
Assigned: 2023-10-10
License: CC0-1.0
Requires: 380
```
## Abstract
This document specifies Miniscript, a language for writing (a subset of) Bitcoin Scripts in a
structured way, enabling analysis, composition, generic signing and more.
## Copyright
This document is licensed under the Creative Commons CC0 1.0 Universal license.
## Motivation
Bitcoin Script is an unusual stack-based language with many edge cases, designed for implementing
spending conditions consisting of various combinations of signatures, hash locks, and time locks.
Yet, despite being limited in functionality, it is still highly nontrivial to:
* Given a combination of spending conditions, finding the most economical script to implement it.
* Given two scripts, construct a script that implements a composition of their spending conditions (e.g. a multisig where one of the "keys" is another multisig).
* Given a script, find out what spending conditions it permits.
* Given a script and access to a sufficient set of private keys, construct a general satisfying witness for it.
* Given a script, be able to predict the cost of spending an output.
* Given a script, know whether particular resource limitations like the ops limit might be hit when spending.
Miniscript functions as a representation for scripts that makes this sort of operations possible.
It has a structure that allows composition. It is very easy to statically analyze for various
properties (spending conditions, correctness, security properties, malleability, ...). It can be
targeted by spending policy compilers. Finally, compatible scripts can easily be converted to
Miniscript form - avoiding the need for additional metadata for e.g. signing devices that support
it.
## Specification
These specifications apply to P2WSH ([BIP 141](bip-0141.mediawiki)) and Tapscript ([BIP 342](bip-0342.mediawiki)) scripts, with only minor
variations between the two. Differences are noted inline. Unless explicitly stated otherwise,
specifications apply to both. P2SH and bare scripts are excluded from this specification.
### Translation Table
Miniscript consists of a set of script *fragments* which are designed to be safely and correctly composable.
This table shows all Miniscript *fragments* and their associated semantics and Bitcoin Script.
Fragments that do not change the semantics of their subexpressions are called *wrappers*. Normal
fragments use a `fragment(arg1,arg2,...)` notation, while wrappers are written using
prefixes separated from other fragments by a colon. The colon is dropped between subsequent
wrappers; e.g. `dv:older(144)` is the `d:` wrapper applied to the
`v:` wrapper applied to the `older` fragment for 144 blocks.
The `pk`, `pkh`, and `and_n` fragments and `t:`,
`l:`, and `u:` wrappers are syntactic sugar for other Miniscripts, as listed
in the table below. Note that `<20>` are in hex representation in this document.
Miniscript fragments are expected to be used in [BIP 382](bip-0382.mediawiki) `wsh()` descriptors
and [BIP 386](bip-0386.mediawiki) `tr()` descriptors. Key expressions are specified in
[BIP 380](bip-0380.mediawiki#user-content-Key_Expressions). Additionally, BIPs 382 and 386 specify
restrictions on key expressions and what they resolve to - these apply to key expressions in
Miniscript. BIP 382's key expression restrictions apply to Miniscript in P2WSH contexts, and BIP
386's key expression restrictions apply to Miniscript in P2TR contexts. From a user's perspective,
Miniscript is not a separate language, but rather a significant expansion of the descriptor language.
| Semantics | Miniscript Fragment | Bitcoin Script
|----------------------------------------------------------|-------------------------------|---------------
| false | `0` | `0`
| true | `1` | `1`
| check(key) | `pk_k(key)` | ``
| | `pk_h(key)` | `DUP HASH160 EQUALVERIFY `
| | `pk(key)` = `c:pk_k(key)` | ` CHECKSIG`
| | `pkh(key)` = `c:pk_h(key)` | `DUP HASH160 EQUALVERIFY CHECKSIG`
| nSequence ≥ n (and compatible) | `older(n)` | ` CHECKSEQUENCEVERIFY`
| nLockTime ≥ n (and compatible) | `after(n)` | ` CHECKLOCKTIMEVERIFY`
| len(x) = 32 and SHA256(x) = h | `sha256(h)` | `SIZE <0x20> EQUALVERIFY SHA256 EQUAL`
| len(x) = 32 and HASH256(x) = h | `hash256(h)` | `SIZE <0x20> EQUALVERIFY HASH256 EQUAL`
| len(x) = 32 and RIPEMD160(x) = h | `ripemd160(h)` | `SIZE <0x20> EQUALVERIFY RIPEMD160 EQUAL`
| len(x) = 32 and HASH160(x) = h | `hash160(h)` | `SIZE <0x20> EQUALVERIFY HASH160 EQUAL`
| (X and Y) or Z | `andor(X,Y,Z)` | `[X] NOTIF [Z] ELSE [Y] ENDIF`
| X and Y | `and_v(X,Y)` | `[X] [Y]`
| | `and_b(X,Y)` | `[X] [Y] BOOLAND`
| | `and_n(X,Y)` = `andor(X,Y,0)` | `[X] NOTIF 0 ELSE [Y] ENDIF`
| X or Z | `or_b(X,Z)` | `[X] [Z] BOOLOR`
| | `or_c(X,Z)` | `[X] NOTIF [Z] ENDIF`
| | `or_d(X,Z)` | `[X] IFDUP NOTIF [Z] ENDIF`
| | `or_i(X,Z)` | `IF [X] ELSE [Z] ENDIF`
| X_1 + ... + X_n = k | `thresh(k,X_1,...,X_n)` | `[X_1] [X_2] ADD ... [X_n] ADD ... EQUAL`
| check(key_1) + ... + check(key_n) = k *(P2WSH only)* | `multi(k,key_1,...,key_n)` | ` ... CHECKMULTISIG`
| check(key_1) + ... + check(key_n) = k *(Tapscript only)* | `multi_a(k,key_1,...,key_n)` | ` CHECKSIG CHECKSIGADD ... CHECKSIGADD NUMEQUAL`
| X (identities) | `a:X` | `TOALTSTACK [X] FROMALTSTACK`
| | `s:X` | `SWAP [X]`
| | `c:X` | `[X] CHECKSIG`
| | `t:X` = `and_v(X,1)` | `[X] 1`
| | `d:X` | `DUP IF [X] ENDIF`
| | `v:X` | `[X] VERIFY (or VERIFY version of last opcode in [X])`
| | `j:X` | `SIZE 0NOTEQUAL IF [X] ENDIF`
| | `n:X` | `[X] 0NOTEQUAL`
| | `l:X` = `or_i(0,X)` | `IF 0 ELSE [X] ENDIF`
| | `u:X` = `or_i(X,0)` | `IF [X] ELSE 0 ENDIF`
### Type System
Not every Miniscript expression can be composed with every other. Some return their result by
putting true or false on the stack; others can only abort or continue. Some require subexpressions
that consume an exactly known number of arguments, while others need a subexpression that has a
nonzero top stack element to satisfy. To model all these properties, we define a correctness type
system for Miniscript.
#### Correctness
Every miniscript expression has one of four basic types: "**B**" (base), "**V**" (verify),
"**K**" (key) and "**W**" (wrapped). Then there are 5 type modifiers that guarantee additional
properties: "**z**" (zero-arg), "**o**" (one-arg), "**n**" (nonzero), "**d**"
(dissatisfiable), and "**u**" (unit).
The following table lists the correctness requirements for each of the Miniscript expressions, and
its type properties in function of those of their subexpressions.
| Miniscript | Requires | Type | Properties
|------------------------------|-------------------------------------------------------|-------------|-----------
| `0` | | B | z; u; d
| `1` | | B | z; u
| `pk_k(key)` | | K | o; n; d; u
| `pk_h(key)` | | K | n; d; u
| `older(n)`, `after(n)` | 1 ≤ n < 231 | B | z
| `sha256(h)` | | B | o; n; d; u
| `ripemd160(h)` | | B | o; n; d; u
| `hash256(h)` | | B | o; n; d; u
| `hash160(h)` | | B | o; n; d; u
| `andor(X,Y,Z)` | X is Bdu; Y and Z are both B, K, or V | same as Y/Z | z=zXzYzZ; o=zXoYoZ or oXzYzZ; u=uYuZ; d=dZ
| `and_v(X,Y)` | X is V; Y is B, K, or V | same as Y | z=zXzY; o=zXoY or zYoX; n=nX or zXnY; u=uY
| `and_b(X,Y)` | X is B; Y is W | B | z=zXzY; o=zXoY or zYoX; n=nX or zXnY; d=dXdY; u
| `or_b(X,Z)` | X is Bd; Z is Wd | B | z=zXzZ; o=zXoZ or zZoX; d; u
| `or_c(X,Z)` | X is Bdu; Z is V | V | z=zXzZ; o=oXzZ
| `or_d(X,Z)` | X is Bdu; Z is B | B | z=zXzZ; o=oXzZ; d=dZ; u=uZ
| `or_i(X,Z)` | both are B, K, or V | same as X/Z | o=zXzZ; u=uXuZ; d=dX or dZ
| `thresh(k,X_1,...,X_n)` | 1 ≤ k ≤ n; X1 is Bdu; others are Wdu | B | z=all are z; o=all are z except one is o; d; u
| `multi(k,key_1,...,key_n)` | 1 ≤ k ≤ n ≤ 20 | B | n; d; u
| `multi_a(k,key_1,...,key_n)` | 1 ≤ k ≤ n | B | d; u
| `a:X` | X is B | W | d=dX; u=uX
| `s:X` | X is Bo | W | d=dX; u=uX
| `c:X` | X is K | B | o=oX; n=nX; d=dX; u
| `d:X` | X is Vz | B | o; n; d; *(Tapscript only)* u
| `v:X` | X is B | V | z=zX; o=oX; n=nX
| `j:X` | X is Bn | B | o=oX; n; d; u=uX
| `n:X` | X is B | B | z=zX; o=oX; n=nX; d=dX; u
#### Timelock Type Mixing
There is one additional correctness property that Miniscript expressions must satisfy:
the four timelock types (absolute time based, absolute height based, relative time based, and
relative height based) must not be mixed in an incompatible way.
Within `and` combinators and the `thresh` combinator where k >= 2, it is illegal for both absolute
height based and time based timelocks to appear, or for both relative height based and time based
timelocks to appear.
For all other combinators, it is legal to mix timelock types. It is also always legal to
mix absolute and relative timelocks (even if one is height based and the other is time based).
#### Malleability
Malleability is the ability for a third party (someone who does *not* hold a participating private
key) to modify an existing satisfaction into another valid satisfaction. To analyze the
malleability guarantees of a script we define three additional type properties: "**s**" (signed),
"**f**" (forced) and "**e**" (expressive).
The following table lists the malleability properties and requirement of each fragment.
| Miniscript | Requires | Properties
|------------------------------|---------------------------------------------------------------------|-----------
| `0` | | s, e
| `1` | | f
| `pk_k(key)` | | s, e
| `pk_h(key)` | | s, e
| `older(n)` | | f
| `after(n)` | | f
| `sha256(h)` | |
| `ripemd160(h)` | |
| `hash256(h)` | |
| `hash160(h)` | |
| `andor(X,Y,Z)` | eX and (sX or sY or sZ) | s=sZ and (sX or sY); f=fZ and (sX or fY); e=eZ and (sX or fY)
| `and_v(X,Y)` | | s=sX or sY; f=sX or fY
| `and_b(X,Y)` | | s=sX or sY; f=fXfY or sXfX or sYfY; e=eXeYsXsY
| `or_b(X,Z)` | eXeZ and (sX or sZ) | s=sXsZ; e
| `or_c(X,Z)` | eX and (sX or sZ) | s=sXsZ; f
| `or_d(X,Z)` | eX and (sX or sZ) | s=sXsZ; f=fZ; e=eZ
| `or_i(X,Z)` | sX or sZ | s=sXsZ; f=fXfZ; e=eXfZ or eZfX
| `thresh(k,X_1,...,X_n)` | all are e; at most k are non-s | s=at most k-1 are non-s; e=all are s
| `multi(k,key_1,...,key_n)` | | s; e
| `multi_a(k,key_1,...,key_n)` | | s; e
| `a:X` | | s=sX; f=fX; e=eX
| `s:X` | | s=sX; f=fX; e=eX
| `c:X` | | s; f=fX; e=eX
| `d:X` | | s=sX; e
| `v:X` | | s=sX; f
| `j:X` | | s=sX; e=fX
| `n:X` | | s=sX; f=fX; e=eX
### Satisfaction
The following table shows all valid satisfactions and dissatisfactions for every Miniscript, using
satisfactions and dissatisfactions of its subexpressions. Multiple possibilities are separated by
semicolons. Some options are inefficient and provably unnecessary to the satisfaction algorithm
described below, but are valid according to script rules and could be used by a malleator or other
non-standard actor. These are called *non-canonical* options, and are listed for completeness, but
~~[struckthrough]~~. The fragments where a satisfaction or dissatisfaction does not exist will
contain *(none)*. The fragments where the satisfaction or dissatisfaction is to provide no data
will contain *(empty)*.
| Miniscript | Dissatisfactions (dsat) | Satisfactions (sat)
|------------------------------|---------------------------------------------------------|--------------------
| `0` | *(empty)* | *(none)*
| `1` | *(none)* | *(empty)*
| `pk_k(key)` | 0 | sig
| `pk_h(key)` | 0 key | sig key
| `older(n)` | *(none)* | *(empty)*
| `after(n)` | *(none)* | *(empty)*
| `sha256(h)` | any 32-byte vector except the preimage | preimage
| `ripemd160(h)` | any 32-byte vector except the preimage | preimage
| `hash256(h)` | any 32-byte vector except the preimage | preimage
| `hash160(h)` | any 32-byte vector except the preimage | preimage
| `andor(X,Y,Z)` | dsat(Z) dsat(X); ~~[dsat(Y) sat(X)]~~ | sat(Y) sat(X); sat(Z) dsat(X)
| `and_v(X,Y)` | *(none)*; ~~[dsat(Y) sat(X)]~~ | sat(Y) sat(X)
| `and_b(X,Y)` | dsat(Y) dsat(X); ~~[sat(Y) dsat(X)]; [dsat(Y) sat(X)]~~ | sat(Y) sat(X)
| `or_b(X,Z)` | dsat(Z) dsat(X) | dsat(Z) sat(X); sat(Z) dsat(X); ~~[sat(Z) sat(X)]~~
| `or_c(X,Z)` | *(none)* | sat(X); sat(Z) dsat(X)
| `or_d(X,Z)` | dsat(Z) dsat(X) | sat(X); sat(Z) dsat(X)
| `or_i(X,Z)` | dsat(X) 1; dsat(Z) 0 | sat(X) 1; sat(Z) 0
| `thresh(k,X_1,...,X_n)` | All dsats; ~~[Sats/dsats with 1 ≤ #(sats) ≠ k]~~ | Sats/dsats with #(sats) = k
| `multi(k,key_1,...,key_n)` | 0 0 ... 0 (k+1 times) | 0 sig ... sig
| `multi_a(k,key_1,...,key_n)` | 0 ... 0 (n times); ~~[sig/0 with #(sig) ≠ k]~~ | sig/0 with #(sig) = k and #(sigs/0) = n
| `a:X` | dsat(X) | sat(X)
| `s:X` | dsat(X) | sat(X)
| `c:X` | dsat(X) | sat(X)
| `d:X` | 0 | sat(X) 1
| `v:X` | *(none)* | sat(X)
| `j:X` | 0; ~~[dsat(X) (if nonzero top stack)]~~ | sat(X)
| `n:X` | dsat(X) | sat(X)
#### Non-malleable Satisfaction Algorithm
In order to produce non-malleable satisfactions we make use of a function that returns the optimal
satisfaction and dissatisfaction for a given expression (if any exist), or a special DONTUSE ("don't use") value,
together with an optional HASSIG ("has signature") marker that tracks whether the solution contains at least one
signature. To implement the function:
* Invoke the function recursively for all subexpressions, obtaining all their satisfactions/dissatisfactions.
* Iterate over all the valid satisfactions/dissatisfactions in the table above (including the non-canonical ones), taking into account:
* The dissatisfactions for `sha256`, `ripemd160`, `hash256`, and `hash160` are always malleable, so instead use DONTUSE there.
* The non-canonical options for `and_b`, `or_b`, and `thresh` are always overcomplete, so instead use DONTUSE there as well (with HASSIG flag if the original non-canonical solution had one).
* The satisfactions for `pk_k`, `pk_h`, and `multi` can be marked HASSIG.
* When constructing solutions by combining results for subexpressions, the result is DONTUSE if any of the constituent results is DONTUSE. Furthermore, the result gets the HASSIG tag if any of the constituents does.
* If among all valid solutions (including DONTUSE ones) more than one does not have the HASSIG marker, return DONTUSE.
* If instead exactly one does not have the HASSIG marker, return that solution.
* If all valid solutions have the HASSIG marker, but all of them are DONTUSE, return DONTUSE-HASSIG. The HASSIG marker is important because while this represents a choice between multiple options that would cause malleability if used, they are not available to the attacker, and we may be able to avoid them entirely still.
* Otherwise, all not-DONTUSE options are valid, so return the smallest one (in terms of witness size).
To produce an overall satisfaction, invoke the function on the toplevel expression. If no valid
satisfaction is returned, or it is DONTUSE, fail. Otherwise, if any timelocking is used in the
script but the result does not have the HASSIG flag, also fail. If the satisfaction is both not
DONTUSE and HASSIG, return it.
## Discussion
## Security
Miniscript primarily aims to provide guarantees on the correctness of a Bitcoin Script. That is, to
guarantee **consensus soundness** and **standardness completeness**. Consensus soundness means
it is not possible to construct a consensus-valid witness for a Bitcoin Script unless the Miniscript
spending conditions are met. Standardness completeness means a standardness-valid witness can be
created for all spending paths of a Miniscript, assuming the resource limits are respected and there
is no timelock mixing.
Additionally, Miniscript can guarantee the non-malleability and maximum size of a witness. These can
assist in assessing the soundness of protocols where transaction fees (and therefore transaction
size) are security-critical parameters.
Hash preimages are constrained to 32 bytes to disallow various forms of griefing, including making
non-standard (un-relayable) transactions, consensus-invalid swaps across blockchains, as well as
ensure that satisfaction cost can be accurately calculated.
In order for these properties to not just apply to script, but to an entire transaction, it's
important that the witness commits to all data relevant for verification. In practice this means
that scripts whose conditions can be met without any digital signature are insecure. Besides being
trivially insecure, note how a transaction lacking a signature check allows an attacker to change
its nLockTime and nSequence fields to meet additional timelock conditions.
### Type System
To statically verify the correctness and malleability guarantees discussed in the previous section,
we define a type system. See the specifications above for a reference of each fragment's
requirements and properties. Here we give more information about each type.
Every expression has one of four basic types:
* "**B**" Base expressions. These take their inputs from the top of the stack. When satisfied, they push a nonzero value of up to 4 bytes onto the stack. When dissatisfied, they push an exact 0 onto the stack (if dissatisfaction without aborting is possible at all). This type is used for most expressions, and required for the top level expression. An example is `older(n)` = ` CHECKSEQUENCEVERIFY`.
* "**V**" Verify expressions. Like "B", these take their inputs from the top of the stack. Upon satisfaction however, they continue without pushing anything. They cannot be dissatisfied (will abort instead). A "V" can be obtained using the `v:` wrapper on a "B" expression, or by combining other "V" expressions using `and_v`, `or_i`, `or_c`, or `andor`. An example is `v:pk(key)` = ` CHECKSIGVERIFY`.
* "**K**" Key expressions. They again take their inputs from the top of the stack, but instead of verifying a condition directly they always push a public key onto the stack, for which a signature is still required to satisfy the expression. A "K" can be converted into a "B" using the `c:` wrapper. An example is `pk_h(key)` = `DUP HASH160 EQUALVERIFY`.
* "**W**" Wrapped expressions. They take their inputs from one below the top of the stack, and push a nonzero (in case of satisfaction) or zero (in case of dissatisfaction) either on top of the stack, or one below. So for example a 3-input "W" would take the stack "A B C D E F" and turn it into "A B F 0" or "A B 0 F" in case of dissatisfaction, and "A B F n" or "A B n F" in case of satisfaction (with n a nonzero value). Every "W" is either `s:B` (SWAP B) or `a:B` (TOALTSTACK B FROMALTSTACK). An example is `s:pk(key)` = `SWAP CHECKSIG`.
Then there are 6 type modifiers, which guarantee additional properties:
* "**z**" Zero-arg: this expression always consumes exactly 0 stack elements.
* "**o**" One-arg: this expression always consumes exactly 1 stack element.
* "**n**" Nonzero: this expression always consumes at least 1 stack element, no satisfaction for this expression requires the top input stack element to be zero.
* "**d**" Dissatisfiable: a dissatisfaction for this expression can unconditionally be constructed. This implies the dissatisfaction cannot include any signature or hash preimage, and cannot rely on timelocks being satisfied.
* "**u**" Unit: when satisfied, this expression will put an exact 1 on the stack (as opposed to any nonzero value).
* "**k**" No timelock mixing. This expression does not contain a mix of heightlock and timelock of the same type. If the miniscript does not have the "k" property, the miniscript template will not match the user expectation of the corresponding spending policy.
Finally to analyze malleability guarantees we introduce 3 new type modifiers:
* "**s**" Signed: satisfying this expression always requires a signature (predicting whether all satisfactions will be HASSIG).
* "**f**" Forced: dissatisfying this expression always requires a signature (predicting whether all dissatisfactions will be HASSIG).
* "**e**" Expressive: this requires a unique unconditional dissatisfaction to exist, and forces all conditional dissatisfactions (if any) to require a signature.
### Malleability
Since Segwit, malleating a transaction no longer breaks the validity of unconfirmed descendant
transactions. However, unintentional malleability may still have a number of much weaker undesirable
effects. If a witness can be stuffed with additional data, the transaction's feerate will go down,
potentially to the point where its ability to propagate and get confirmed is impacted. Additionally,
malleability can be exploited to add roundtrips to BIP152 block propagation, by trying to get
different miners to mine different versions of the same transaction. Finally, malleability may
interfere with the usage of hash locks as a mechanism for publishing preimages.
Using the malleability type properties it is possible to determine statically whether a script can
be non-malleably satisfied under all circumstances. In many cases it is reasonable to only accept
such guaranteed-non-malleable scripts, as unexpected behavior can occur when using other scripts.
For example, when running the non-malleable satisfaction algorithm above, adding available
preimages, or increasing the nLockTime/nSequence values actually may make it fail where it succeeded
before. This is because a larger set of met conditions may mean an existing satisfaction goes from
non-malleable to malleable. Restricting things to scripts that are guaranteed to be satisfiable in a
non-malleable way avoids this problem.
When analysing Miniscripts for resource limits, restricting yourself to just non-malleable solutions
(or even non-malleable scripts) also leads to tighter bounds, as all non-canonical satisfactions and
dissatisfactions can be left out of consideration.
The malleability analysis makes the following assumptions:
* The attacker does not have access to any of the private keys of public keys that participate in the Script. Participants with private keys inherently have the ability to produce different satisfactions by creating multiple signatures. While it is also interesting to study the impact rogue participants can have, we treat it as a distinct problem.
* The attacker only has access to hash preimages that honest users have access to as well. This is a reasonable assumption because hash preimages are revealed once globally, and then available to everyone. On the other hand, making the assumption that attackers may have access to more preimages than honest users makes a large portion of scripts impossible to satisfy in a non-malleable way.
* The attacker gets to see exactly one satisfying witness of any transaction. If he sees multiple, it becomes possible for the attacker to mix and match different satisfactions. This is very hard to reason about.
* We restrict this analysis to scripts where no public key is repeated. If signatures constructed for one part of the script can be bound to other checks in the same script, a variant of the mixing from the previous point becomes available that is equally hard to reason about. Furthermore this situation can be avoided by using separate keys.
* The attacker is constrained by common standardness rules. A miner may be able to malleate a witness considered non-malleable by Miniscript.
#### Non-Malleable Satisfaction
Malleable satisfactions or dissatisfactions appear whenever options are available to attackers distinct from the one taken by honest users. This can happen for multiple reasons:
1. Two or more options for a satisfaction or dissatisfaction are listed in the table above which are both available to attackers directly. Regardless of which option is used in the honest solution, the attacker can change the solution to the other one.
2. Two or more options for a satisfaction or dissatisfaction are listed in the table above, only one of which is available to attackers, but the honest solution uses another one. In that case, the attacker can modify the solution to pick the one available to him.
3. The honest users pick a solution that contains a satisfaction which can be turned into a dissatisfaction without invalidating the overall witness. Those are called overcomplete solutions.
Because we assume attackers never have access to private keys, we can treat any solution that
includes a signature as one that is unavailable to attackers. For others, the worst case is that the
attacker has access to every solution the honest users have, but no others: for preimages this is an
explicit assumption, while timelock availability is determined by the nLockTime and nSequence fields
in the transaction. As long as the overall satisfaction includes at least one signature, those
values are fixed, and timelock availability is identical for attackers and honest users.
The description of the non-malleable satisfaction algorithm can be used to show that no
non-canonical solutions listed in the satisfaction table can occur inside non-malleable
satisfaction:
* Some of the non-canonical options (the `or_b`, `and_b`, and `thresh` ones) are overcomplete, and thus can clearly not appear in non-malleable satisfactions.
* The fact that non-"d" expressions cannot be dissatisfied in valid witnesses rules out the usage of the non-canonical `and_v` dissatisfaction.
* "d" expressions are defined to be unconditionally dissatisfiable, which implies that for those a non-HASSIG dissatisfaction must exist. Non-HASSIG solutions must be preferred over HASSIG ones (reason 2), and when multiple non-HASSIG ones exist, none can be used (reason 1). This lets us rule out the other non-canonical options in the table:
* `j:X` is always "d", its non-HASSIG dissatisfaction "0" always exists, and thus rules out any usage of "dsat(X)".
* If `andor(X,Y,Z)` is "d", a non-HASSIG dissatisfaction "dsat(Z) dsat(X)" must exist, and thus rules out any usage of "dsat(Y) sat(X)".
* If `and_b(X,Y)` is "d", a non-HASSIG dissatisfaction "dsat(Y) dsat(X)" must exist, and thus rules out any usage of "dsat(Y) sat(X)" and "sat(Y) dsat(X)". Those are also overcomplete.
* `thresh(k,...)` is always "d", a non-HASSIG dissatisfaction with just dissatisfactions must exist due to typing rules, and thus rules out usage of the other dissatisfactions. They are also overcomplete.
### Resource Limits
Various types of Bitcoin Scripts have different resource limitations, either through consensus or standardness. Some of them affect otherwise valid Miniscripts:
* In P2WSH, scripts larger than 3600 bytes are invalid by standardness. In Tapscript, scripts are implicitly bounded by the maximum size of a block (1 million virtual bytes).
* In P2WSH, script satisfactions where the total number of non-push opcodes plus the number of keys participating in all executed `CHECKMULTISIG` is above 201 are invalid by consensus.
* In both Tapscript and P2WSH, script satisfactions which make the stack exceed 1000 elements before or during execution are invalid.
* In P2WSH, satisfactions with a witness consisting of over 100 stack elements (excluding the script itself) are invalid by standardness.
A static analysis can be performed on a Miniscript to verify if none, all or any of the spending
paths hit any of the limits.
## Test Vectors
TBD
## Backwards Compatibility
Miniscript's syntax is compatible with BIP 380 Output Script Descriptors, and should be considered
an extension to it that provides a new type of Script expression that is only valid in
`wsh()` and `tr()` contexts. As these are wholly new expressions, they are not
compatible with any existing implementation of descriptors. Additionally, the scripts produced are
unlikely to be standard scripts.
The `pk()`, `pkh()`, `multi()`, and `multi_a()`
fragments overlap with existing descriptors. These parse to the same semantic meanings as those
descriptors and produce the same scripts.
## Reference Implementation
A first reference implementation and documentation for Miniscript in P2WSH was originally published at
https://github.com/sipa/miniscript .
The reference implementation for Miniscript in P2WSH was introduced in Bitcoin Core through PRs
[24147](https://github.com/bitcoin/bitcoin/pull/24147), [24148](https://github.com/bitcoin/bitcoin/pull/24148), and
[24149](https://github.com/bitcoin/bitcoin/pull/24149). The last one to be merged was released in Bitcoin
Core version 25.0.
The reference implementation for Miniscript in Tapscript was introduced in Bitcoin Core in PR
[27255](https://github.com/bitcoin/bitcoin/pull/27255). This PR was merged and released in Bitcoin Core
version 26.0.
================================================
FILE: bip-0380.mediawiki
================================================
==Abstract==
Output Script Descriptors are a simple language which can be used to describe collections of output scripts.
There can be many different descriptor fragments and functions.
This document describes the general syntax for descriptors, descriptor checksums, and common expressions.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
Bitcoin wallets traditionally have stored a set of keys which are later serialized and mutated to produce the output scripts that the wallet watches and the addresses it provides to users.
Typically backups have consisted of solely the private keys, nowadays primarily in the form of BIP 39 mnemonics.
However this backup solution is insufficient, especially since the introduction of Segregated Witness which added new output types.
Given just the private keys, it is not possible for restored wallets to know which kinds of output scripts and addresses to produce.
This has lead to incompatibilities between wallets when restoring a backup or exporting data for a watch only wallet.
Further complicating matters are BIP 32 derivation paths.
Although BIPs 44, 49, and 84 have specified standard BIP 32 derivation paths for different output scripts and addresses, not all wallets support those derivation paths nor use them.
The lack of derivation path information in these backups and exports leads to further incompatibilities between wallets.
Current solutions to these issues have not been generic and can be viewed as being layer violations.
Solutions such as introducing different version bytes for extended key serialization both are a layer violation (key derivation should be separate from script type meaning) and specific only to a particular derivation path and script type.
Output Script Descriptors introduce a generic solution to these issues.
Script types are specified explicitly through the use of Script Expressions.
Key derivation paths are specified explicitly in Key Expressions.
These allow for creating wallet backups and exports which specify the exact scripts, subscripts (redeemScript, witnessScript, etc.), and keys to produce.
With the general structure specified in this BIP, new Script Expressions can be introduced as new script types are added.
Lastly, the use of common terminology and existing standards allow for Output Script Descriptors to be engineer readable so that the results can be understood at a glance.
==Specification==
Descriptors consist of several types of expressions.
The top level expression is a SCRIPT.
This expression may be followed by #CHECKSUM, where CHECKSUM is an 8 character alphanumeric descriptor checksum.
Although the checksum is optional for parsing, applications may choose to reject descriptors that do not contain a checksum.
===Script Expressions===
Script Expressions (denoted SCRIPT) are expressions which correspond directly with a Bitcoin script.
These expressions are written as functions and take arguments.
Such expressions have a script template which is filled with the arguments correspondingly.
Expressions are written with a human readable identifier string with the arguments enclosed with parentheses.
The identifier string should be alphanumeric and may include underscores.
The arguments to a script expression are defined by that expression itself.
They could be a script expression, a key expression, or some other expression entirely.
===Key Expressions===
A common expression used as an argument to script expressions are key expressions (denoted KEY).
These represent a public or private key and, optionally, information about the origin of that key.
Key expressions can only be used as arguments to script expressions.
Key expressions consist of:
* Optionally, key origin information, consisting of:
** An open bracket [
** Exactly 8 hex characters for the fingerprint of the key where the derivation starts (see BIP 32 for details)
** Followed by zero or more /NUM or /NUMh path elements to indicate the unhardened or hardened derivation steps between the fingerprint and the key that follows.
** A closing bracket ]
* Followed by the actual key, which is either:
** A hex encoded public key, which depending on the script expression, may be either:
*** 66 hex character string beginning with 02 or 03 representing a compressed public key
*** 130 hex character string beginning with 04 representing an uncompressed public key
** A [[https://en.bitcoin.it/wiki/Wallet_import_format|WIF]] encoded private key
** xpub encoded extended public key or xprv encoded extended private key (as defined in BIP 32)
*** Followed by zero or more /NUM or /NUMh path elements indicating BIP 32 derivation steps to be taken after the given extended key.
*** Optionally followed by a single /* or /*h final step to denote all direct unhardened or hardened children.
If the KEY is a BIP 32 extended key, before output scripts can be created, child keys must be derived using the derivation information that follows the extended key.
When the final step is /* or /*', an output script will be produced for every child key index.
The derived key must be not be serialized as an uncompressed public key.
Script Expressions may have further requirements on how derived public keys are serialized for script creation.
In the above specification, the hardened indicator h may be replaced with alternative hardened indicator of '.
====Normalization of Key Expressions with Hardened Derivation====
When a descriptor is exported without private keys, it is necessary to do additional derivation to remove any intermediate hardened derivation steps for the exported descriptor to be useful.
The exporter should derive the extended public key at the last hardened derivation step and use that extended public key as the key in the descriptor.
The derivation steps that were taken to get to that key must be added to the previous key origin information.
If there is no key origin information, then one must be added for the newly derived extended public key.
If the final derivation is hardened, then it is not necessary to do additional derivation.
===Character Set===
The expressions used in descriptors must only contain characters within this character set so that the descriptor checksum will work.
The allowed characters are:
Note that on the last line is a space character.
This character set is written as 3 groups of 32 characters in this specific order so that the checksum below can identify more errors.
The first group are the most common "unprotected" characters (i.e. things such as hex and keypaths that do not already have their own checksums).
Case errors cause an offset that is a multiple of 32 while as many alphabetic characters are in the same group while following the previous restrictions.
===Checksum===
Following the top level script expression is a single octothorpe (#) followed by the 8 character checksum.
The checksum is an error correcting checksum similar to bech32.
The checksum has the following properties:
* Mistakes in a descriptor string are measured in "symbol errors". The higher the number of symbol errors, the harder it is to detect:
** An error substituting a character from 0123456789()[],'/*abcdefgh@:$%{} for another in that set always counts as 1 symbol error.
*** Note that hex encoded keys are covered by these characters. Extended keys (xpub and xprv) use other characters too, but also have their own checksum mechanism.
*** SCRIPT expression function names use other characters, but mistakes in these would generally result in an unparsable descriptor.
** A case error always counts as 1 symbol error.
** Any other 1 character substitution error counts as 1 or 2 symbol errors.
* Any 1 symbol error is always detected.
* Any 2 or 3 symbol error in a descriptor of up to 49154 characters is always detected.
* Any 4 symbol error in a descriptor of up to 507 characters is always detected.
* Any 5 symbol error in a descriptor of up to 77 characters is always detected.
* Is optimized to minimize the chance of a 5 symbol error in a descriptor up to 387 characters is undetected
* Random errors have a chance of 1 in 240 of being undetected.
The checksum itself uses the same character set as bech32: qpzry9x8gf2tvdw0s3jn54khce6mua7l
Valid descriptor strings with a checksum must pass the criteria for validity specified by the Python3 code snippet below.
The function descsum_check must return true when its argument s is a descriptor consisting in the form SCRIPT#CHECKSUM.
INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "
CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
GENERATOR = [0xf5dee51989, 0xa9fdca3312, 0x1bab10e32d, 0x3706b1677a, 0x644d626ffd]
def descsum_polymod(symbols):
"""Internal function that computes the descriptor checksum."""
chk = 1
for value in symbols:
top = chk >> 35
chk = (chk & 0x7ffffffff) << 5 ^ value
for i in range(5):
chk ^= GENERATOR[i] if ((top >> i) & 1) else 0
return chk
def descsum_expand(s):
"""Internal function that does the character to symbol expansion"""
groups = []
symbols = []
for c in s:
if not c in INPUT_CHARSET:
return None
v = INPUT_CHARSET.find(c)
symbols.append(v & 31)
groups.append(v >> 5)
if len(groups) == 3:
symbols.append(groups[0] * 9 + groups[1] * 3 + groups[2])
groups = []
if len(groups) == 1:
symbols.append(groups[0])
elif len(groups) == 2:
symbols.append(groups[0] * 3 + groups[1])
return symbols
def descsum_check(s):
"""Verify that the checksum is correct in a descriptor"""
if s[-9] != '#':
return False
if not all(x in CHECKSUM_CHARSET for x in s[-8:]):
return False
symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]]
return descsum_polymod(symbols) == 1
This implements a BCH code that has the properties described above.
The entire descriptor string is first processed into an array of symbols.
The symbol for each character is its position within its group.
After every 3rd symbol, a 4th symbol is inserted which represents the group numbers combined together.
This means that a change that only affects the position within a group, or only a group number change, will only affect a single symbol.
To construct a valid checksum given a script expression, the code below can be used:
def descsum_create(s):
"""Add a checksum to a descriptor without"""
symbols = descsum_expand(s) + [0, 0, 0, 0, 0, 0, 0, 0]
checksum = descsum_polymod(symbols) ^ 1
return s + '#' + ''.join(CHECKSUM_CHARSET[(checksum >> (5 * (7 - i))) & 31] for i in range(8))
==Test Vectors==
The following tests cover the checksum and character set:
* Valid checksum: raw(deadbeef)#89f8spxm
* No checksum: raw(deadbeef)
* Missing checksum: raw(deadbeef)#
* Too long checksum (9 chars): raw(deadbeef)#89f8spxmx
* Too short checksum (7 chars): raw(deadbeef)#89f8spx
* Error in payload: raw(deedbeef)#89f8spxm
* Error in checksum: raw(deedbeef)##9f8spxm
* Invalid characters in payload: raw(Ü)#00000000
The following tests cover key expressions:
Valid expressions:
* Compressed public key: 0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Uncompressed public key: 04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235
* Public key with key origin: [deadbeef/0h/0h/0h]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Public key with key origin (' as hardened indicator): [deadbeef/0'/0'/0']0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Public key with key origin (mixed hardened indicator): [deadbeef/0'/0h/0']0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* WIF uncompressed private key 5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss
* WIF compressed private key L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1
* Extended public key: xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL
* Extended public key with key origin: [deadbeef/0h/1h/2h]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL
* Extended public key with derivation: [deadbeef/0h/1h/2h]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/4/5
* Extended public key with derivation and children: [deadbeef/0h/1h/2h]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/4/5/*
* Extended public key with hardened derivation and unhardened children: xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3h/4h/5h/*
* Extended public key with hardened derivation and children: xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3h/4h/5h/*h
* Extended public key with key origin, hardened derivation and children: [deadbeef/0h/1h/2]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3h/4h/5h/*h
* Extended private key: xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc
* Extended private key with key origin: [deadbeef/0h/1h/2h]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc
* Extended private key with derivation: [deadbeef/0h/1h/2h]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/4/5
* Extended private key with derivation and children: [deadbeef/0h/1h/2h]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/4/5/*
* Extended private key with hardened derivation and unhardened children: xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3h/4h/5h/*
* Extended private key with hardened derivation and children: xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3h/4h/5h/*h
* Extended private key with key origin, hardened derivation and children: [deadbeef/0h/1h/2]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3h/4h/5h/*h
Invalid expression:
* Children indicator in key origin: [deadbeef/0h/0h/0h/*]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Trailing slash in key origin: [deadbeef/0h/0h/0h/]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Too short fingerprint: [deadbef/0h/0h/0h]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Too long fingerprint: [deadbeeef/0h/0h/0h]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Invalid hardened indicators: [deadbeef/0f/0f/0f]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Invalid hardened indicators: [deadbeef/-0/-0/-0]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Invalid hardened indicators: [deadbeef/0H/0H/0H]0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600
* Invalid hardened indicators: [deadbeef/0h/1h/2]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3H/4h/5h/*H
* Private key with derivation: L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1/0
* Private key with derivation children: L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1/*
* Derivation index out of range: xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483648
* Invalid derivation index: xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1aa
* Multiple key origins: [aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0
* Missing key origin start: aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0
* Non hex fingerprint: [gaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0
* Key origin with no public key: [deadbeef]
==Backwards Compatibility==
Output script descriptors are an entirely new language which is not compatible with any existing software.
However many components of the expressions reuse encodings and serializations defined by previous BIPs.
Output script descriptors are designed for future extension with further fragment types and new script expressions.
These will be specified in additional BIPs.
==Reference Implementation==
Descriptors have been implemented in Bitcoin Core since version 0.17.
==Appendix A: Index of Expressions==
Future BIPs may specify additional types of expressions.
All available expression types are listed in this table.
{|
! Name
! Denoted As
! BIP
|-
| Script
| SCRIPT
| 380
|-
| Key
| KEY
| 380
|-
| Tree
| TREE
| [[bip-0386.mediawiki|386]]
|}
==Appendix B: Index of Script Expressions==
Script expressions will be specified in additional BIPs.
This Table lists all available Script expressions and the BIPs specifying them.
{|
! Expression
! BIP
|-
| pk(KEY)
| [[bip-0381.mediawiki|381]]
|-
| pkh(KEY)
| [[bip-0381.mediawiki|381]]
|-
| sh(SCRIPT)
| [[bip-0381.mediawiki|381]]
|-
| wpkh(KEY)
| [[bip-0382.mediawiki|382]]
|-
| wsh(SCRIPT)
| [[bip-0382.mediawiki|382]]
|-
| multi(NUM, KEY, ..., KEY)
| [[bip-0383.mediawiki|383]]
|-
| sortedmulti(NUM, KEY, ..., KEY)
| [[bip-0383.mediawiki|383]]
|-
| combo(KEY)
| [[bip-0384.mediawiki|384]]
|-
| raw(HEX)
| [[bip-0385.mediawiki|385]]
|-
| addr(ADDR)
| [[bip-0385.mediawiki|385]]
|-
| tr(KEY), tr(KEY, TREE)
| [[bip-0386.mediawiki|386]]
|-
| musig(KEY, KEY, ..., KEY)
| [[bip-0390.mediawiki|390]]
|-
| sp(KEY), sp(KEY, KEY)
| [[bip-0392.mediawiki|392]]
|}
================================================
FILE: bip-0381.mediawiki
================================================
==Abstract==
This document specifies pk(), pkh(), and sh() output script descriptors.
pk() descriptors take a key and produces a P2PK output script.
pkh() descriptors take a key and produces a P2PKH output script.
sh() descriptors take a script and produces a P2SH output script.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
Prior to the activation of Segregated Witness, there were 3 main standard output script formats: P2PK, P2PKH, and P2SH.
These expressions allow specifying those formats as a descriptor.
==Specification==
Three new script expressions are defined: pk(), pkh(), and sh().
===pk()===
The pk(KEY) expression can be used in any context or level of a descriptor.
It takes a single key expression as an argument and produces a P2PK output script.
Depending on the higher level descriptors, there may be restrictions on the type of public keys that can be included.
Such restrictions will be specified by those descriptors.
The output script produced is:
OP_CHECKSIG
===pkh()===
The pkh(KEY) expression can be used as a top level expression, or inside of either a sh() or wsh() descriptor.
It takes a single key expression as an argument and produces a P2PKH output script.
Depending on the higher level descriptors, there may be restrictions on the type of public keys that can be included.
Such restrictions will be specified by those descriptors.
The output script produced is:
OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
===sh()===
The sh(SCRIPT) expression can only be used as a top level expression.
It takes a single script expression as an argument and produces a P2SH output script.
sh() expressions also create a redeemScript which is required in order to spend outputs which use its output script.
This redeemScript is the output script produced by the SCRIPT argument to sh().
The output script produced is:
OP_HASH160 OP_EQUAL
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, 1st, and 2nd scripts listed.
* pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)
** 2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac
* pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
** 2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac
* pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)
** 76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac
* pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
** 76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac
* pkh([deadbeef/1/2h/3/4h]03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
** 76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac
* pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)
** 4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac
* pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
** 4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac
* pkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)
** 76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac
* pkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
** 76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac
* sh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))
** a9141857af51a5e516552b3086430fd8ce55f7c1a52487
* sh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
** a9141857af51a5e516552b3086430fd8ce55f7c1a52487
* sh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))
** a9141a31ad23bf49c247dd531a623c2ef57da3c400c587
* sh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
** a9141a31ad23bf49c247dd531a623c2ef57da3c400c587
* pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)
** 76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac
* pkh([bd16bee5/2147483647h]xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0)
** 76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac
* pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)
** 210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac
* pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)
** 210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac
Invalid descriptors
* pk() only accepts key expressions: pk(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* pkh() only accepts key expressions: pkh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* sh() only accepts script expressions: sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
* sh() is top level only: sh(sh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))
==Backwards Compatibility==
pk(), pkh(), and sh() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As these are wholly new descriptors, they are not compatible with any implementation.
However the scripts produced are standard scripts so existing software are likely to be familiar with them.
==Reference Implementation==
pk(), pkh(), and sh() descriptors have been implemented in Bitcoin Core since version 0.17.
================================================
FILE: bip-0382.mediawiki
================================================
==Abstract==
This document specifies wpkh(), and wsh() output script descriptors.
wpkh() descriptors take a key and produces a P2WPKH output script.
wsh() descriptors take a script and produces a P2WSH output script.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
Segregated Witness added 2 additional standard output script formats: P2WPKH and P2WSH.
These expressions allow specifying those formats as a descriptor.
==Specification==
Two new script expressions are defined: wpkh(), and wsh().
===wpkh()===
The wpkh(KEY) expression can be used as a top level expression, or inside of a sh() descriptor.
It takes a single key expression as an argument and produces a P2WPKH output script.
Only keys which are/have compressed public keys can be contained in a wpkh() expression.
The output script produced is:
OP_0
===wsh()===
The wsh(SCRIPT) expression can be used as a top level expression, or inside of a sh() descriptor.
It takes a single script expression as an argument and produces a P2WSH output script.
wsh() expressions also create a witnessScript which is required in order to spend outputs which use its output script.
This redeemScript is the output script produced by the SCRIPT argument to wsh().
Any key expression found in any script expression contained by a wsh() expression must only produce compressed public keys.
The output script produced is:
OP_0
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, 1st, and 2nd scripts listed.
* wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)
** 00149a1c78a507689f6f54b847ad1cef1e614ee23f1e
* wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
** 00149a1c78a507689f6f54b847ad1cef1e614ee23f1e
* wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/0)
** 0014326b2249e3a25d5dc60935f044ee835d090ba859
* wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)
** 0014326b2249e3a25d5dc60935f044ee835d090ba859
** 0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7
** 00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27
* sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))
** a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87
** a914bed59fc0024fae941d6e20a3b44a109ae740129287
** a9148483aa1116eb9c05c482a72bada4b1db24af654387
* sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*h))
** a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87
** a914bed59fc0024fae941d6e20a3b44a109ae740129287
** a9148483aa1116eb9c05c482a72bada4b1db24af654387
* wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))
** 0020338e023079b91c58571b20e602d7805fb808c22473cbc391a41b1bd3a192e75b
* wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
** 0020338e023079b91c58571b20e602d7805fb808c22473cbc391a41b1bd3a192e75b
* wsh(pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))
** 00202e271faa2325c199d25d22e1ead982e45b64eeb4f31e73dbdf41bd4b5fec23fa
* wsh(pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
** 00202e271faa2325c199d25d22e1ead982e45b64eeb4f31e73dbdf41bd4b5fec23fa
* sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))
** a914b61b92e2ca21bac1e72a3ab859a742982bea960a87
* sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))
** a914b61b92e2ca21bac1e72a3ab859a742982bea960a87
Invalid descriptors with descriptions
* Uncompressed public key in wpkh(): wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)
* Uncompressed public key in wpkh(): sh(wpkh(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))
* Uncompressed public key in wpkh(): wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
* Uncompressed public key in wpkh(): sh(wpkh(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))
* Uncompressed public keys under wsh(): wsh(pk(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))
* Uncompressed public keys under wsh(): wsh(pk(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))
* wpkh() nested in wsh(): wsh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* wsh() nested in wsh(): wsh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))
* wsh() nested in wsh(): sh(wsh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))))
* Script in wpkh(): wpkh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))
* Key in wsh(): wsh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
==Backwards Compatibility==
wpkh(), and wsh() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As these are a wholly new descriptors, they are not compatible with any implementation.
However the scripts produced are standard scripts so existing software are likely to be familiar with them.
==Reference Implementation==
wpkh(), and wsh() descriptors have been implemented in Bitcoin Core since version 0.17.
================================================
FILE: bip-0383.mediawiki
================================================
==Abstract==
This document specifies multi(), and sortedmulti() output script descriptors.
Both functions take a threshold and one or more public keys and produce a multisig output script.
multi() specifies the public keys in the output script in the order given in the descriptor while sortedmulti() sorts the public keys lexicographically when the output script is produced.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
The most common complex script used in Bitcoin is a threshold multisig.
These expressions allow specifying multisig scripts as a descriptor.
==Specification==
Two new script expressions are defined: multi(), and sortedmulti().
Both expressions produce the scripts of the same template and take the same arguments.
They are written as multi(k,KEY_1,KEY_2,...,KEY_n).
k is the threshold - the number of keys that must sign the input for the script to be valid.
KEY_1,KEY_2,...,KEY_n are the key expressions for the multisig. k must be less than or equal to n.
multi() and sortedmulti() expressions can be used as a top level expression, or inside of either a sh() or wsh() descriptor.
Depending on the higher level descriptors, there may be restrictions on the type of public keys that can be included.
Depending on the higher level descriptors, there are also restrictions on the number of keys that can be present, i.e. the maximum value of n.
When used at the top level, there can only be at most 3 keys.
When used inside of a sh() expression, there can only be most 15 compressed public keys (this is limited by the P2SH script limit).
Otherwise the maximum number of keys is 20.
The output script produced will be
k KEY_1 KEY_2 ... KEY_n n OP_CHECKMULTISIG
The values k and n must be minimally encoded integers.
For values less than or equal to 16, they must be encoded using OP_0 through OP_16.
For values greater than 16, they must be a push of the signed little endian encoded value without padding.
===sortedmulti()===
The only change for sortedmulti() is that the keys are sorted lexicographically prior to the creation of the output script.
This sorting is on the keys that are to be put into the output script, i.e. after all extended keys are derived.
===Multiple Extended Keys===
When one or more the key expressions in a multi() or sortedmulti() expression are extended keys, the derived keys use the same child index.
This changes the keys in lockstep and allows for output scripts to be indexed in the same way that the derived keys are indexed.
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, 1st, and 2nd scripts listed.
* multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)
** 512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae
* multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
** 512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae
* sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
** 512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae
* sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))
** a91445a9a622a8b0a1269944be477640eedc447bbd8487
* sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)
** 5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae
** 52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae
** 5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae
* wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))
** 0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f
** 002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203
** 0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c
* sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))
** a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87
* wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv))
** 0020376bd8344b8b6ebe504ff85ef743eaa1aa9272178223bcb6887e9378efb341ac
* sh(wsh(multi(20,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9,KzRedjSwMggebB3VufhbzpYJnvHfHe9kPJSjCU5QpJdAW3NSZxYS,Kyjtp5858xL7JfeV4PNRCKy2t6XvgqNNepArGY9F9F1SSPqNEMs3,L2D4RLHPiHBidkHS8ftx11jJk1hGFELvxh8LoxNQheaGT58dKenW,KyLPZdwY4td98bKkXqEXTEBX3vwEYTQo1yyLjX2jKXA63GBpmSjv)))
** a914c2c9c510e9d7f92fd6131e94803a8d34a8ef675e87
Invalid descriptors
* More than 15 keys in P2SH multisig: sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))
* Invalid threshold: multi(a,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
* Threshold of 0: multi(0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
* Threshold larger than keys: multi(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)
==Backwards Compatibility==
multi(), and sortedmulti() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As these are a wholly new descriptors, they are not compatible with any implementation.
However the scripts produced are standard scripts so existing software are likely to be familiar with them.
==Reference Implementation==
multi(), and sortedmulti() descriptors have been implemented in Bitcoin Core since version 0.17.
================================================
FILE: bip-0384.mediawiki
================================================
==Abstract==
This document specifies combo() output script descriptors.
These take a key and produce P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH output scripts if applicable to the key.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
In order to make the transition from traditional key based wallets to descriptor based wallets easier, it is useful to be able to take a key and produce the scripts which have traditionally been produced by wallet software.
==Specification==
A new top level script expression is defined: combo(KEY).
This expression can only be used as a top level expression.
It takes a single key expression as an argument and produces either 2 or 4 output scripts, depending on the key.
A combo() expression always produces a P2PK and P2PKH script, the same as putting the key in both a pk() and a pkh() expression.
If the key is/has a compressed public key, then P2WPKH and P2SH-P2WPKH scripts are also produced, the same as putting the key in both a wpkh() and sh(wpkh()) expression.
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, and 1st scripts in additional sub-bullets.
* combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)
** 2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac
** 76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac
** 00149a1c78a507689f6f54b847ad1cef1e614ee23f1e
** a91484ab21b1b2fd065d4504ff693d832434b6108d7b87
* combo(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
** 4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235ac
** 76a914b5bd079c4d57cc7fc28ecf8213a6b791625b818388ac
* combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)
** 2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac
** 76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac
** 001431a507b815593dfc51ffc7245ae7e5aee304246e
** a9142aafb926eb247cb18240a7f4c07983ad1f37922687
* combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)
** Child 0
*** 2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac
*** 76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac
*** 0014f90e3178ca25f2c808dc76624032d352fdbdfaf2
*** a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087
** Child 1
*** 21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac
*** 76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac
*** 0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7
*** a91473e39884cb71ae4e5ac9739e9225026c99763e6687
Invalid descriptors
* combo() in sh : sh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* combo() in wsh : wsh(combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* Script in combo(): combo(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
==Backwards Compatibility==
combo() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As this is a wholly new descriptor, it is not compatible with any implementation.
However the scripts produced are standard scripts so existing software are likely to be familiar with them.
==Reference Implementation==
combo() descriptors have been implemented in Bitcoin Core since version 0.17.
================================================
FILE: bip-0385.mediawiki
================================================
==Abstract==
This document specifies raw() and addr() output script descriptors.
raw() encapsulates a raw script as a descriptor.
addr() encapsulates an address as a descriptor.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
In order to make descriptors maximally compatible with scripts in use today, it is useful to be able to wrap any arbitrary output script or an address into a descriptor.
==Specification==
Two new script expressions are defined: raw() and addr().
===raw()===
The raw(HEX) expression can only be used as a top level descriptor.
As the argument, it takes a hex string representing a Bitcoin script.
The output script produced by this descriptor is the script represented by HEX.
===addr()===
The addr(ADDR) expression can only be used as a top level descriptor.
It takes an address as its single argument.
The output script produced by this descriptor is the output script produced by the address ADDR.
==Test Vectors==
Valid descriptors followed by the scripts they produce.
* raw(deadbeef)
** deadbeef
* raw(512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae)
** 512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae
* raw(a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87)
** a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87
* addr(3PUNyaW7M55oKWJ3kDukwk9bsKvryra15j)
** a914eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee87
Invalid descriptors
* Non-hex script: raw(asdf)
* Invalid address: addr(asdf)
* raw nested in sh: sh(raw(deadbeef))
* raw nested in wsh: wsh(raw(deadbeef))
* addr nested in sh: sh(addr(3PUNyaW7M55oKWJ3kDukwk9bsKvryra15j))
* addr nested in wsh: wsh(addr(3PUNyaW7M55oKWJ3kDukwk9bsKvryra15j))
==Backwards Compatibility==
raw() and addr() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As this is a wholly new descriptor, it is not compatible with any implementation.
The reuse of existing Bitcoin addresses allows for this to be more easily implemented.
==Reference Implementation==
raw() and addr() descriptors have been implemented in Bitcoin Core since version 0.17.
================================================
FILE: bip-0386.mediawiki
================================================
==Abstract==
This document specifies tr() output script descriptors.
tr() descriptors take a key and optionally a tree of scripts and produces a P2TR output script.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
Taproot added one additional standard output script format: P2TR.
These expressions allow specifying those formats as a descriptor.
==Specification==
A new script expression is defined: tr().
A new expression is defined: Tree Expressions
===Tree Expression===
A Tree Expression (denoted TREE) is an expression which represents a tree of scripts.
The way the tree is represented in an output script is dependent on the higher level expressions.
A Tree Expression is:
* Any Script Expression that is allowed at the level this Tree Expression is in.
* A pair of Tree Expressions consisting of:
** An open brace {
** A Tree Expression
** A comma ,
** A Tree Expression
** A closing brace }
===tr()===
The tr(KEY) or tr(KEY, TREE) expression can only be used as a top level expression.
All key expressions under any tr() expression must create x-only public keys.
tr(KEY) takes a single key expression as an argument and produces a P2TR output script which does not have a script path.
Each key produced by the key expression is used as the internal key of a P2TR output as specified by [[bip-0341.mediawiki#cite_ref-22-0|BIP 341]].
Specifically, "If the spending conditions do not require a script path, the output key should commit to an unspendable script path instead of having no script path.
This can be achieved by computing the output key point as ''Q = P + int(hashTapTweak(bytes(P)))G''."
tr(KEY, TREE) takes a key expression as the first argument, and a tree expression as the second argument and produces a P2TR output script which has a script path.
The keys produced by the first key expression are used as the internal key as specified by [[bip-0341.mediawiki#Constructing_and_spending_Taproot_outputs|BIP 341]].
The Tree expression becomes the Taproot script tree as described in BIP 341.
A merkle root is computed from this tree and combined with the internal key to create the Taproot output key.
===Modified Key Expression===
Key Expressions within a tr() expression must only create x-only public keys.
Uncompressed public keys are not allowed, but compressed public keys would be implicitly converted to x-only public keys.
The keys derived from extended keys must be serialized as x-only public keys.
An additional key expression is defined only for use within a tr() descriptor:
* A 64 hex character string representing an x-only public key
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, 1st, and 2nd scripts listed.
* tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)
** 512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11
* tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)
** 512077aab6e066f8a7419c5ab714c12c67d25007ed55a43cadcacb4d7a970a093f11
* tr(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/0/*,pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/1/*))
** 512078bc707124daa551b65af74de2ec128b7525e10f374dc67b64e00ce0ab8b3e12
** 512001f0a02a17808c20134b78faab80ef93ffba82261ccef0a2314f5d62b6438f11
** 512021024954fcec88237a9386fce80ef2ced5f1e91b422b26c59ccfc174c8d1ad25
* tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))
** 512017cf18db381d836d8923b1bdb246cfcd818da1a9f0e6e7907f187f0b2f937754
* tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,{pk(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0),{{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL),pk(02df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076)},pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)}})
** 512071fff39599a7b78bc02623cbe814efebf1a404f5d8ad34ea80f213bd8943f574
Invalid Descriptors
* Uncompressed private key: tr(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)
* Uncompressed public key: tr(04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)
* tr() nested in wsh: wsh(tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* tr() nested in sh: sh(tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* pkh() nested in tr: tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd, pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))
==Backwards Compatibility==
tr() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As these are a set of wholly new descriptors, they are not compatible with any implementation.
However the scripts produced are standard scripts so existing software are likely to be familiar with them.
Tree Expressions are largely incompatible with existing script expressions due to the restrictions in those expressions.
As of 2021-06-27, the only allowed script expression that can be used in a tree expression is pk().
However there will be future BIPs that specify script expressions that can be used in tree expressions.
==Reference Implementation==
tr() descriptors have been implemented in Bitcoin Core since version 22.0.
================================================
FILE: bip-0387.mediawiki
================================================
==Abstract==
This document specifies multi_a() and sortedmulti_a() output script descriptors.
Like BIP 383's multi() and sortedmulti(), both functions take a threshold and one
or more public keys and produce a multisig script. The primary distinction is that multi_a()
and sortedmulti_a() only produce tapscripts and are only allowed in a tapscript context.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
The most common complex script used in Bitcoin is a threshold multisig.
These expressions allow specifying multisig scripts as a descriptor.
==Specification==
Two new script expressions are defined: multi_a() and sortedmulti_a().
Both expressions produce the scripts of the same template and take the same arguments.
They are written as multi_a(k,KEY_1,KEY_2,...,KEY_n).
k is the threshold - the number of keys that must sign the input for the script to be valid.
KEY_1,KEY_2,...,KEY_n are the key expressions for the multisig. k must be less than or equal to n.
multi_a() and sortedmulti_a() expressions can only be used inside of a tr() descriptor.
The maximum number of keys is 999.
The output script produced also depends on the value of k. If k is less than or equal to 16:
KEY_1 OP_CHECKSIG KEY_2 OP_CHECKSIGADD ... KEY_n OP_CHECKSIGADD k OP_NUMEQUAL
===sortedmulti_a()===
The only change for sortedmulti_a() is that the x-only public keys are sorted lexicographically prior to the creation of the output script.
This sorting is on the keys that are to be put into the output script, i.e. after all extended keys are derived.
===Multiple Extended Keys===
When one or more of the key expressions in a multi_a() or sortedmulti_a() expression are extended keys, the derived keys use the same child index.
This changes the keys in lockstep and allows for output scripts to be indexed in the same way that the derived keys are indexed.
==Test Vectors==
Valid descriptors followed by the scripts they produce. Descriptors involving derived child keys will have the 0th, 1st, and 2nd scripts listed.
* tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,multi_a(1,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy))
** 5120eb5bd3894327d75093891cc3a62506df7d58ec137fcd104cdd285d67816074f3
* tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,multi_a(1,669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))
** 5120eb5bd3894327d75093891cc3a62506df7d58ec137fcd104cdd285d67816074f3
* tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,multi_a(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))
** 51202eea93581594a43c0c8423b70dc112e5651df63984d108d4fc8ccd3b63b4eafa
* tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,sortedmulti_a(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))
** 512016fa6a6ba7e98c54b5bf43b3144912b78a61b60b02f6a74172b8dcb35b12bc30
* tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,sortedmulti_a(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*))
** 5120abd47468515223f58a1a18edfde709a7a2aab2b696d59ecf8c34f0ba274ef772
** 5120fe62e7ed20705bd1d3678e072bc999acb014f07795fa02cb8f25a7aa787e8cbd
** 51201311093750f459039adaa2a5ed23b0f7a8ae2c2ffb07c5390ea37e2fb1050b41
* tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,multi_a(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))
** 5120e4c8f2b0a7d3a688ac131cb03248c0d4b0a59bbd4f37211c848cfbd22a981192
** 5120827faedaa21e52fca2ac83b53afd1ab7d4d1e6ce67ff42b19f2723d48b5a19ab
** 5120647495ed09de61a3a324704f9203c130d655bf3141f9b748df8f7be7e9af55a4
Invalid descriptors
* Unsupported top level: multi_a(1,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0)
* Unsupported sh() context: sh(multi_a(1,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))
* Unsupported wsh() context: wsh(multi_a(1,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0))
* Invalid threshold: tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,multi_a(a,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* Threshold of 0: tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,multi_a(0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))
* Uncompressed pubkey: tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,multi_a(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235))
* Threshold larger than keys: tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,multi_a(3,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss))
==Backwards Compatibility==
multi_a() and sortedmulti_a() descriptors use the format and general operation specified in [[bip-0380.mediawiki|380]].
As these are wholly new descriptors, they are not compatible with any implementation.
However, the scripts produced are standard scripts, so existing software are likely to be familiar with them.
==Reference Implementation==
multi_a() and sortedmulti_a() descriptors were implemented in Bitcoin Core in https://github.com/bitcoin/bitcoin/pull/24043 and have been available since version 24.0.
================================================
FILE: bip-0388/wallet_policies.py
================================================
#!/usr/bin/env python3
from typing import Iterable, List, Mapping, Tuple, Generator
def find_all(text: str, pattern: str, start: int = 0) -> Generator[int, None, None]:
"""Generates all the positions of `pattern` as a substring of `text`, starting from index at least `start`."""
while True:
start = text.find(pattern, start)
if start == -1:
return
yield start
start += len(pattern)
def find_first(text: str, start_pos: int, patterns: Iterable[str]) -> int:
"""Returns the position of the first occurrence of any of the elements in `patterns` as a substring of `text`,
or -1 if none of the patterns is found."""
matches = (text.find(x, start_pos) for x in patterns)
return min((x for x in matches if x != -1), default=-1)
def find_key_end_position(desc: str, start_pos: int) -> int:
"""Assuming that `start_pos` is the beginning of a KEY expression (and not musig), finds the position of the end
of the key expression, excluding (if present) the final derivation steps after an xpub. This is the information
that goes into an entry of the vector of key information of the wallet policy."""
has_orig_info = True if desc[start_pos] == '[' else False
if has_orig_info:
closing_bracket_pos = desc.find("]", start_pos)
if closing_bracket_pos == -1:
raise Exception("Invalid descriptor: could not find closing ']'")
key_pos_start = closing_bracket_pos + 1
else:
key_pos_start = start_pos
# find the earliest occurrence of ",", a ")" or a "/" (it must find at least 1)
end_pos = find_first(desc, key_pos_start, [",", ")", "/"])
if end_pos == -1:
raise Exception(
"Invalid descriptor: cannot find the end of key expression")
return end_pos
class WalletPolicy(object):
"""Simple class to represent wallet policies. This is a toy implementation that does not parse the descriptor
template. A more robust implementation would build the abstract syntax tree of the template and of the descriptor,
allowing one to detect errors, and manipulate it semantically instead of relying on string manipulation."""
def __init__(self, descriptor_template: str, keys_info: List[str]):
self.descriptor_template = descriptor_template
self.keys_info = keys_info
def to_descriptor(self) -> str:
"""Converts a wallet policy into the descriptor (with the / syntax, if present)."""
desc = self.descriptor_template
# replace each "/**" with "/<0;1>/*"
desc = desc.replace("/**", "/<0;1>/*")
# process all the @N expressions in decreasing order. This guarantees that string replacements
# works as expected (as any prefix expression is processed after).
for i in reversed(range(len(self.keys_info))):
desc = desc.replace(f"@{i}", self.keys_info[i])
# there should not be any remaining "@" expressions
if desc.find("@") != -1:
raise Exception("Invalid descriptor template: contains invalid key index")
return desc
@classmethod
def from_descriptor(cls, descriptor: str) -> 'WalletPolicy':
"""Converts a "reasonable" descriptor (with the / syntax) into the corresponding wallet policy."""
# list of pairs of integers, where the tuple (m,n) with m < n means a key expression starts at
# m (inclusive) and at n (exclusive)
key_expressions: List[Tuple[int, int]] = []
key_with_orig_pos_start = None
def parse_key_expressions(only_first=False, handle_musig=False):
# Starting at the position in `key_with_orig_pos_start`, parses a number of key expressions, and updates
# the `key_expressions` array accordingly.
# If `only_first` is `True`, it stops after parsing a single key expression.
# If `handle_musig` is `True`, and a key expression is a `musig` operator, it recursively parses
# the keys in the musig expression. `musig` inside `musig` is not allowed.
nonlocal key_with_orig_pos_start
if key_with_orig_pos_start is None:
raise Exception("Unexpected error")
while True:
if handle_musig and descriptor[key_with_orig_pos_start:].startswith("musig"):
closing_parenthesis_pos = find_first(
descriptor, key_with_orig_pos_start, [")"])
if closing_parenthesis_pos == -1:
raise Exception(
"Invalid descriptor: musig without closing parenthesis")
key_with_orig_pos_start = key_with_orig_pos_start + \
len("musig(")
parse_key_expressions(
only_first=False, handle_musig=False)
key_pos_end = closing_parenthesis_pos + 1
else:
key_pos_end = find_key_end_position(
descriptor, key_with_orig_pos_start)
key_expressions.append(
(key_with_orig_pos_start, key_pos_end))
if descriptor[key_pos_end] == '/':
# find the actual end (comma or closing parenthesis)
key_pos_end = find_first(
descriptor, key_pos_end, [",", ")"])
if key_pos_end == -1:
raise Exception(
"Invalid descriptor: unterminated key expression")
if descriptor[key_pos_end] == ',':
# There is another key expression, repeat from after the comma
key_with_orig_pos_start = key_pos_end + 1
else:
break
if only_first:
break
# operators for which the KEY is the first argument
operators_key_first = ["pk", "pkh", "pk_h", "pk_k", "tr"]
# operators for which the KEY is everything except the first argument
operators_key_all_but_first = [
"multi", "sortedmulti", "multi_a", "sortedmulti_a"]
for op in operators_key_first + operators_key_all_but_first:
for op_pos_start in find_all(descriptor, op + "("):
# ignore if not a whole word (otherwise "sortedmulti" would be found inside "multi")
if op_pos_start > 0 and 'a' <= descriptor[op_pos_start - 1] <= 'z':
continue
if op in operators_key_all_but_first:
# skip the first argument (we know it's not a KEY expression, so it does not have a comma)
first_comma_pos = descriptor.find(",", op_pos_start)
if first_comma_pos == -1:
raise Exception(
"Invalid descriptor: multi, sortedmulti, multi_a and sortedmulti_a must have at least two arguments")
key_with_orig_pos_start = 1 + first_comma_pos
else:
# other operators, the first argument is already a KEY expression
key_with_orig_pos_start = op_pos_start + len(op) + 1
only_first = op in operators_key_first
parse_key_expressions(
only_first=only_first, handle_musig=True)
result: List[str] = []
keys: List[str] = []
keys_to_idx: Mapping[str, int] = {}
prev_end = 0
for start, end in sorted(key_expressions):
result.append(descriptor[prev_end:start])
key = descriptor[start:end]
if key not in keys_to_idx:
idx = len(keys)
keys.append(key)
keys_to_idx[key] = idx
else:
idx = keys_to_idx[key]
result.append(f"@{idx}")
prev_end = end
result.append(descriptor[prev_end:])
return cls("".join(result), keys)
if __name__ == "__main__":
descriptors = [
"pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/**)",
"wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/**,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/**))",
"tr([12345678/44'/0'/0']xpub6BVZ6JrGsWsUbpP74S8rnz13hVFDtYtKyuTTEYPNSF6GFpDFpL1YXWg3BpwpUWAnsZZ7Qe3XKz7GL3BEx3RQVq61cxqSkjceq25S1xFKFVa,{pk(xpub6AGdromjXf5yf3m7ndaCoR9Ac3UjwTvQ7QQkZoyoh2vfGE9i1AwB2vCbvjTpBL1KRERUsGszg63SVNXsHZU3CiykQqtZPrdXKMdaG2vs6uu),pk(xpub6AnhdkteWC4kPQvkY3QQXGmDCMfmFoYzEQ7FwRFa4BQ1a22k4VL4BD3Jdcog2Sf2KzBscXXAdPRMgjCBDeq6bAryqnMaWX2FaVUGPxWMLDh)})",
"tr(xpub6AEWqA1MNRzBBXenkug4NtNguDKTNcXoKQj8fU9VQyid38yikruFRffjoDm9UEaHGEJ6jQxjYdWWZRxR7Xy5ePrQNjohXJuNzkRNSiiBUcE,sortedmulti_a(2,[11223344/44'/0'/0']xpub6AyJhEKxcPaPnYNuA7VBeUQ24v6mEzzPSX5AJm3TSyg1Zsti7rnGKy1Hg6JAdXKF4QUmFZbby9p97AjBNm2VFCEec2ip5C9JntyxosmCeMW,xpub6AQVHBgieCHpGo4GhpGAo4v9v7hfr2Kr4D8ZQJqJwbEyZwtW3pWYSLRQyrNYbTzpoq6XpFtaKZGnEGUMtiydCgqsJDAZNqs9L5QDNKqUBsV))",
"tr([11111111/44'/0'/0']xpub6CLZSUDtcUhJVDoPSY8pSRKi4W1RSSLBgwZ2AYmwTH9Yv5tPVFHZxJBUQ27QLLwHej6kfo9DQQbwaHmpXsQq59CjtsE2gNLHmojwgMrsQNe/**,{and_v(v:pk([22222222/44'/0'/0']xpub6CiztfGsUxmpwkWe6gvz8d5VHyFLDoiPpeUfWmQ2vWAhQL3Z1hhEc6PE4irFs4bzjS7dCB4yyinaubrCpFJq4bcKGCD4jjqTxaWiKAJ7mvJ/**),older(52596)),multi_a(2,[33333333/44'/0'/0']xpub6DTZd6od7is2wxXndmE7zaUifzFPwVKshVSGEZedfTJtUjfLyhy4hgCW15hvxRpGaDmtiFoJKaCEaSRfXrQBuYRx18zwquy46dwBsJnsrz2/**,[44444444/44'/0'/0']xpub6BnK4wFbPeLZM4VNjoUA4yLCru6kCT3bhDJNBhbzHLGp1fmgK6muz27h4drixJZeHG8vSS5U5EYyE3gE8ozG94iNg3NDYE8M5YafvhzhMR9/**)})",
"tr(musig([33333333/44'/0'/0']xpub6DTZd6od7is2wxXndmE7zaUifzFPwVKshVSGEZedfTJtUjfLyhy4hgCW15hvxRpGaDmtiFoJKaCEaSRfXrQBuYRx18zwquy46dwBsJnsrz2,[44444444/44'/0'/0']xpub6BnK4wFbPeLZM4VNjoUA4yLCru6kCT3bhDJNBhbzHLGp1fmgK6muz27h4drixJZeHG8vSS5U5EYyE3gE8ozG94iNg3NDYE8M5YafvhzhMR9)/**,{and_v(v:pk([22222222/44'/0'/0']xpub6CiztfGsUxmpwkWe6gvz8d5VHyFLDoiPpeUfWmQ2vWAhQL3Z1hhEc6PE4irFs4bzjS7dCB4yyinaubrCpFJq4bcKGCD4jjqTxaWiKAJ7mvJ/**),older(52596)),pk([11111111/44'/0'/0']xpub6CLZSUDtcUhJVDoPSY8pSRKi4W1RSSLBgwZ2AYmwTH9Yv5tPVFHZxJBUQ27QLLwHej6kfo9DQQbwaHmpXsQq59CjtsE2gNLHmojwgMrsQNe/**)})",
]
for desc in descriptors:
# Demoes the conversion from a "sane" descriptor to a wallet policy
print(f"Descriptor:\n{desc}")
wp = WalletPolicy.from_descriptor(desc)
print(f"Policy descriptor template:\n{wp.descriptor_template}")
print(f"Keys:\n{wp.keys_info}")
print("======================================================\n")
# Converting back to descriptors also works, as long as we take care of /**
assert wp.to_descriptor().replace("/<0;1>/*", "/**") == desc
================================================
FILE: bip-0388.mediawiki
================================================
== Abstract ==
Software wallets and hardware signing devices typically partition funds into separate "accounts". When signing or visualizing a transaction, aggregate flows of funds of all accounts affected by the transaction may (and should) be displayed to the user.
Wallet policies build on top of output script descriptors to represent such accounts in a compact, reviewable way.
An account encompasses a logical group of receive and change addresses, and each wallet policy represents all descriptors necessary to describe an account in its entirety.
We simplify the language to suit devices with limited memory, where even keeping the entire descriptor in memory could be a major hurdle, by reducing the generality of descriptors to just the essential features and by separating the extended pubkeys and other key information from the descriptor.
This results in a more compact representation and simplifies the inspection of the policy by the user.
The compilation of wallet policies to the corresponding descriptor is trivial, and the reverse process is easy for supported descriptors, because the language is kept similar to that of output script descriptors.
== Copyright ==
This BIP is licensed under the BSD 2-clause license.
== Motivation ==
''[[bip-0380.mediawiki|Output Script Descriptors]]'' were introduced in Bitcoin Core as a way to represent collections of output scripts. It is a general and flexible language, designed to catch all the possible use-cases of bitcoin wallets (that is, if you know the script and you have the necessary keys, it will be possible to sign transactions with any descriptor-based software wallet).
Unfortunately, descriptors are not a perfect match for the typical usage of hardware signing devices (often also called ''hardware wallets''). Most of them have some of the following limitations when compared to a general-purpose machine running Bitcoin Core:
* they are embedded devices with limited RAM and computational power;
* they cannot import additional private keys (that is, they can only sign with keys derived from a single seed via [[bip-0032.mediawiki|BIP-32]]);
* they have limited storage, or they might not have persistent storage at all (''stateless design'').
Moreover, other limitations like the limited size of the screen might affect what design choices are available in practice. Therefore, minimizing the amount of information shown on-screen is important for a good user experience. The ability for the user to completely validate on-screen the kind of script used (and each of the involved keys) is crucial for secure usage, as the machine that is interacting with the hardware signer (and running the software wallet) is considered untrusted.
A more native, compact representation of the wallet receive and change addresses might also benefit the UX of software wallets when they use descriptors (possibly with miniscript) for representing complex locking conditions.
We remark that wallet policies are not related to the ''policy'' language, a higher level language that can be compiled to [[bip-0379.md|miniscript]].
=== Security, privacy and UX concerns for hardware signing devices ===
The usage of complex scripts presents challenges in terms of both security and user experience for a hardware signing device.
==== Security issues ====
Hardware signing devices strive to guarantee that no action can be performed without the user’s consent as long as the user correctly verifies the information that is shown on the device’s screen before approving.
This must hold even in scenarios where the attacker has full control of the machine that is connected to the signing device, and can execute arbitrary requests, or tamper with the legitimate user's requests.
Therefore, it is not at all trivial to allow complex scripts, especially if they contain keys that belong to third parties.
The hardware signing device must guarantee that the user knows precisely what "policy" is being used to spend the funds, and that any "unspent" funds (if any) that is sent to a change address will be protected by the same policy.
This makes it impossible for an attacker to surreptitiously modify the policy, therefore stealing or burning the user's funds.
==== Avoiding key reuse ====
Reusing public keys within a script is a source of malleability when using miniscript policies, which has potential security implications.
Reusing keys across different UTXOs harms user privacy by allowing external parties to link these UTXOs to the same entity once they are spent.
By constraining the derivation path patterns to have a uniform structure, wallet policies prevent key reuse among the same or different UTXOs of the same account.
It is strongly recommended to avoid key reuse across accounts. Distinct public keys per account can be guaranteed by using distinct hardened derivation paths. This specification does not mandate hardened derivation in order to maintain compatibility with existing deployments that do not adhere to this recommendation.
It is out of scope for this document to guarantee that users do not reuse extended public keys among different wallet accounts. This is still very important, but the responsibility is left to the users and their software wallet.
==== UX issues ====
Miniscript (and taproot trees) allow substantially more complex spending policies. It is a challenge to ensure that the user can practically verify such spending policies on the screen.
We set two fundamental design goals:
* Minimize the amount of information that is shown on screen - so that the user can actually validate it.
* Minimize the number of times the user has to validate such information.
Designing a secure protocol for the coordination of a descriptor wallet among distant parties is also a challenging problem that is out of the scope of this document. See [[bip-0129.mediawiki|BIP-129 (Bitcoin Secure Multisig Setup)]] for an approach designed for multisig wallets. Regardless of the approach, the ability for the user to carefully verify all the details of the spending policies using the hardware signer's screen is a prerequisite for security in adversarial environments.
=== Policy registration as a solution ===
A solution to address the security concerns, and part of the UX concerns, is to have a registration flow for the wallet policy in the hardware signing device. The ''wallet policy'' must contain enough information to generate all the relevant addresses/scripts, and for the hardware signing device to identify the keys that it controls and that are needed to spend the funds sent to those addresses.
Before a new policy is used for the first time, the user will register a wallet policy into the hardware device. While the details of the process are out of scope in this document, the flow should be something similar to the following:
# The software wallet initiates a ''wallet policy registration'' on the hardware signing device; the information should include the wallet policy, but also a unique ''name'' that identifies the policy.
# The device shows the wallet policy to the user using the secure screen.
# After inspecting the policy and comparing it with a trusted source (for example a printed backup), the user approves the policy.
# If stateful, the hardware signing device persists the policy in its permanent memory; if stateless, it returns a "proof of registration".
The '''proof of registration''' will allow the hardware signer to verify that a certain policy was indeed previously approved by the user, and is therefore safe to use without repeating the expensive user verification procedure. The details of how to create a proof of registration are out of scope for this document; using a Message Authentication Code on a hash committing to the wallet policy, its name and any additional metadata is an effective solution if correctly executed.
Once a policy is registered, the hardware signing device can perform the typical operations securely:
* generating receive and change addresses;
* showing addresses on the secure screen;
* sign transactions spending from a wallet, while correctly identifying change addresses and computing the transaction fees.
Before any of the actions mentioned above, the hardware signing device will retrieve the policy from its permanent storage if stateful; if stateless it will validate the proof of registration before using the wallet policy provided by the client.
Once the previously registered policy is correctly identified and approved by the user (for example by showing its name), and as long as the policy registration was executed securely, hardware signing devices can provide a user experience similar to the usual one for single-signature transactions.
=== Avoiding blowup in descriptor size ===
While reusing a pubkey in different branches of a miniscript is explicitly forbidden by miniscript (as it has certain negative security implications), it is still reasonable to reuse the same xpub in multiple places, albeit with different final steps of derivation (so that the actual pubkeys that are used in the script are indeed different).
In fact, there are many reasonable spending policies with a quadratic size in the number of participants. For example, using Taproot, a 3-of-5 threshold wallet could use:
* a key path with a 5-of-5 [[bip-0327.mediawiki|MuSig2]] aggregated key
* a script tree with 11 leaves:
** 10 different scripts using a 3-of-3 MuSig2 aggregated key, plus
** a final leaf with a fallback 3-of-5 multisig using multi_a (in case interactive signing is not available).
With each xpub being 118 bytes long, the repetition of xpubs makes the descriptor become extremely large.
Replacing the common part of the key with a short key placeholder and organizing all the key expressions in a separate list helps to keep the size of the wallet policy small, which is crucial to allow human inspection during the registration flow.
== Specification ==
This section formally defines wallet policies, and how they relate to output script descriptors.
=== Formal definition ===
A ''wallet policy'' is composed of a ''wallet descriptor template'', together with a vector of ''key information items''.
==== Wallet descriptor template ====
A ''wallet descriptor template'' is a SCRIPT expression.
SCRIPT expressions:
* sh(SCRIPT) (top level only): P2SH embed the argument.
* wsh(SCRIPT) (top level or inside sh only): P2WSH embed the argument.
* pkh(KEY) (not inside tr): P2PKH output for the given public key.
* wpkh(KEY) (top level or inside sh only): P2WPKH output for the given compressed pubkey.
* multi(k,KEY_1,KEY_2,...,KEY_n) (inside sh or wsh only): ''k''-of-''n'' multisig script.
* sortedmulti(k,KEY_1,KEY_2,...,KEY_n) (inside sh or wsh only): ''k''-of-''n'' multisig script with keys sorted lexicographically in the resulting script.
* tr(KEY) or tr(KEY,TREE) (top level only): P2TR output with the specified key as internal key, and optionally a tree of script paths.
* any valid miniscript template (inside wsh or tr only).
See [[bip-0379.md|BIP-379]] for a precise specification of all the valid miniscript SCRIPT expressions.
TREE expressions:
* any SCRIPT expression
* An open brace {, a TREE expression, a comma ,, a TREE expression, and a closing brace }KEY expressions consist of
* a KP expression
* ''always'' followed by either:
** the string /**, or
** a string of the form //*, for two distinct decimal numbers NUM representing unhardened derivations, or
** any of the additional, implementation-specific valid derivation path patterns (see [[#optional-derivation-paths|Optional derivation paths]] below).
KP expressions (key placeholders) consist of either:
* a KI (key index) expression, or
* (only inside tr): musig(KI_1,KI_2,...,KI_n)
A KI (key index) expression consists of:
* a single character @
* followed by a non-negative decimal number, with no leading zeros (except for @0)
The /** in the placeholder template represents commonly used paths for receive/change addresses, and is equivalent to /<0;1>/*.
Note that while [[bip-0389.mediawiki|BIP-389]] allows multipath / expressions with an arbitrary number of options, this specification restricts it to exactly 2 choices (with the typical meaning of receive/change addresses).
SCRIPT, TREE and KEY expressions map directly to the corresponding concepts defined in [[bip-0380.mediawiki|BIP-380]] for output script descriptors.
Each KEY expression always corresponds to a precise public key in the final bitcoin Script. Therefore, all the derivation steps in the BIP-32 hierarchy are included in a KEY expression.
Each KP (key placeholder) expression, on the other hand, maps to the root of all the corresponding public keys for all the possible UTXOs that belong to the account represented in the wallet policy. Therefore, no derivation steps are allowed in a KP expression.
A KI (key index) @i for some number ''i'' represents the ''i''-th key in the vector of key information items (which must be of size at least ''i + 1'', or the wallet policy is invalid).
Note: while descriptor templates for miniscript are not formally defined in this version of the document (pending standardization), it is straightforward to adapt this approach by adding additional SCRIPT expressions.
==== Key information vector ====
Each element of the key origin information vector is a KEY_INFO expression, containing an extended public key, and (optionally) its key origin.
* Optionally, key origin information, consisting of:
** An open bracket [
** Exactly 8 hex characters for the fingerprint of the master key from which this key is derived from (see [[bip-0032.mediawiki|BIP-32]] for details)
** Followed by zero or more /NUM' or /NUM path elements to indicate hardened or unhardened derivation steps between the fingerprint and the xpub that follows
** A closing bracket ]
* Followed by the actual key, which is a serialized extended public key (as defined in [[bip-0032.mediawiki|BIP-32]]).
==== Additional rules ====
A wallet policy must have at least one key placeholder and the corresponding key.
The public keys obtained by deserializing elements of the key information vector must be pairwise distinct'''Why must public keys be distinct?''' Reusing pubkeys could be insecure in the context of wallet policies containing [https://bitcoin.sipa.be/miniscript/ miniscript]. Avoiding repeated public keys altogether avoids the problem at the source..
If two KEY are KP//* and KP/
/* for the same key placeholder KP, then the sets {M, N} and {P, Q} must be disjoint. Two musig key placeholders are the same if they have exactly the same set of key indexes (regardless of the order).
Repeated KI expressions are not allowed inside a musig placeholder.
The key information vector should be ordered so that placeholder @i never appears for the first time before an occurrence of @j for some j < i; for example, the first placeholder is always @0, the next one is @1, etc.
=== Descriptor derivation ===
From a wallet descriptor template (and the associated vector of key information items), one can therefore obtain the corresponding multipath descriptor by:
* replacing each key placeholder with the corresponding key origin information;
* replacing every /** with /<0;1>/*.
For example, the wallet descriptor pkh(@0/**) with key information
["[d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"]
produces the following multipath descriptor:
pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<0;1>/*)
=== Implementation guidelines ===
It is acceptable to implement only a subset of the possible wallet policies defined by this standard. It is recommended that any limitations are clearly documented.
Implementations can add additional metadata that is stored together with the wallet policy for the purpose of wallet policy registration and later usage. Metadata can be vendor-specific and is out of the scope of this document.
Any implementation in a software wallet that allows wallet policies not matching any of the specifications in [[bip-0044.mediawiki|BIP-44]], [[bip-0049.mediawiki|BIP-49]], [[bip-0084.mediawiki|BIP-84]], [[bip-0086.mediawiki|BIP-86]] (especially if involving external cosigners) should put great care into a process for backing up the wallet policy that represents the account. In fact, unlike standard single-signature scenarios, the seed alone is no longer enough to discover wallet policies with existing funds, and the loss of the backup is likely to lead to permanent loss of funds. Unlike the seed, leaking such backups only affects the privacy of the user, but it does not allow the attacker to steal funds.
=== Optional derivation paths ===
In order to allow supporting legacy derivation schemes (for example, using simply /* instead of the more common //* scheme most software wallets use today), or other schemes that are not covered in this document, implementations might choose to permit additional derivation patterns for the key placeholder (KP) expressions.
However, care needs to be taken in view of the following considerations:
* Allowing derivation schemes with a different length or cardinality in the same wallet policy would make it difficult to guarantee that there are no repeated pubkeys for every possible address generated by the policy. For example, @0/<0;1>/* and @1/* would generate the same pubkeys if the second public key in the key information vector is one of the first two unhardened children of the first public key. This could cause malleability with potential security implications (for example, in policies containing miniscript).
* Allowing naked pubkeys with no /* suffix (for example a descriptor template like wsh(multi(2,@0,@1/<0;1>/*))) would cause a pubkey to be repeated in every output generated from the policy, which would result in a total loss of privacy.
== Examples ==
In the examples in this section, the vector of key information items is omitted. See the test vectors below for complete examples.
Common single-signature account patterns:
* pkh(@0/**) (legacy).
* wpkh(@0/**) (native segwit).
* sh(wpkh(@0/**)) (nested segwit).
* tr(@0/**) (taproot single-signature account).
Common multisig schemes:
* wsh(multi(2,@0/**,@1/**)) - SegWit 2-of-2 multisig, keys in order.
* sh(sortedmulti(2,@0/**,@1/**,@2/**)) - Legacy 2-of-3 multisig, sorted keys.
* tr(musig(@0,@1)/**) - MuSig2 2-of-2 in the taproot keypath
Some miniscript policies in wsh:
* wsh(and_v(v:pk(@0/**),or_d(pk(@1/**),older(12960)))) - Trust-minimized second factor, degrading to a single signature after about 90 days.
* wsh(thresh(3,pk(@0/**),s:pk(@1/**),s:pk(@2/**),sln:older(12960))) - A 3-of-3 wallet that becomes a 2-of-3 if coins are not spent for about 90 days.
* wsh(or_d(pk(@0/**),and_v(v:multi(2,@1/**,@2/**,@3/**),older(65535)))) - A singlesig wallet with automatic inheritance to a timelocked 2-of-3 multisig of family members.
== Test Vectors ==
=== Valid policies ===
[[bip-0044.mediawiki|BIP-44]], first account
Descriptor template: pkh(@0/**)
Keys info: ["[6738736c/44'/0'/0']xpub6Br37sWxruYfT8ASpCjVHKGwgdnYFEn98DwiN76i2oyY6fgH1LAPmmDcF46xjxJr22gw4jmVjTE2E3URMnRPEPYyo1zoPSUba563ESMXCeb"]
Descriptor: pkh([6738736c/44'/0'/0']xpub6Br37sWxruYfT8ASpCjVHKGwgdnYFEn98DwiN76i2oyY6fgH1LAPmmDcF46xjxJr22gw4jmVjTE2E3URMnRPEPYyo1zoPSUba563ESMXCeb/<0;1>/*)
[[bip-0049.mediawiki|BIP-49]], second account
Descriptor template: sh(wpkh(@0/**))
Keys info: ["[6738736c/49'/0'/1']xpub6Bex1CHWGXNNwGVKHLqNC7kcV348FxkCxpZXyCWp1k27kin8sRPayjZUKDjyQeZzGUdyeAj2emoW5zStFFUAHRgd5w8iVVbLgZ7PmjAKAm9"]
Descriptor: sh(wpkh([6738736c/49'/0'/1']xpub6Bex1CHWGXNNwGVKHLqNC7kcV348FxkCxpZXyCWp1k27kin8sRPayjZUKDjyQeZzGUdyeAj2emoW5zStFFUAHRgd5w8iVVbLgZ7PmjAKAm9/<0;1>/*))
[[bip-0084.mediawiki|BIP-84]], third account
Descriptor template: wpkh(@0/**)
Keys info: ["[6738736c/84'/0'/2']xpub6CRQzb8u9dmMcq5XAwwRn9gcoYCjndJkhKgD11WKzbVGd932UmrExWFxCAvRnDN3ez6ZujLmMvmLBaSWdfWVn75L83Qxu1qSX4fJNrJg2Gt"]
Descriptor: wpkh([6738736c/84'/0'/2']xpub6CRQzb8u9dmMcq5XAwwRn9gcoYCjndJkhKgD11WKzbVGd932UmrExWFxCAvRnDN3ez6ZujLmMvmLBaSWdfWVn75L83Qxu1qSX4fJNrJg2Gt/<0;1>/*)
[[bip-0086.mediawiki|BIP-86]], first account
Descriptor template: tr(@0/**)
Keys info: ["[6738736c/86'/0'/0']xpub6CryUDWPS28eR2cDyojB8G354izmx294BdjeSvH469Ty3o2E6Tq5VjBJCn8rWBgesvTJnyXNAJ3QpLFGuNwqFXNt3gn612raffLWfdHNkYL"]
Descriptor: tr([6738736c/86'/0'/0']xpub6CryUDWPS28eR2cDyojB8G354izmx294BdjeSvH469Ty3o2E6Tq5VjBJCn8rWBgesvTJnyXNAJ3QpLFGuNwqFXNt3gn612raffLWfdHNkYL/<0;1>/*)
[[bip-0048.mediawiki|BIP-48]] P2WSH multisig
Descriptor template: wsh(sortedmulti(2,@0/**,@1/**))
Keys info: ["[6738736c/48'/0'/0'/2']xpub6FC1fXFP1GXLX5TKtcjHGT4q89SDRehkQLtbKJ2PzWcvbBHtyDsJPLtpLtkGqYNYZdVVAjRQ5kug9CsapegmmeRutpP7PW4u4wVF9JfkDhw", "[b2b1f0cf/48'/0'/0'/2']xpub6EWhjpPa6FqrcaPBuGBZRJVjzGJ1ZsMygRF26RwN932Vfkn1gyCiTbECVitBjRCkexEvetLdiqzTcYimmzYxyR1BZ79KNevgt61PDcukmC7"]
Descriptor: wsh(sortedmulti(2,[6738736c/48'/0'/0'/2']xpub6FC1fXFP1GXLX5TKtcjHGT4q89SDRehkQLtbKJ2PzWcvbBHtyDsJPLtpLtkGqYNYZdVVAjRQ5kug9CsapegmmeRutpP7PW4u4wVF9JfkDhw/<0;1>/*,[b2b1f0cf/48'/0'/0'/2']xpub6EWhjpPa6FqrcaPBuGBZRJVjzGJ1ZsMygRF26RwN932Vfkn1gyCiTbECVitBjRCkexEvetLdiqzTcYimmzYxyR1BZ79KNevgt61PDcukmC7/<0;1>/*))
Miniscript: A 3-of-3 that becomes a 2-of-3 after 90 days
Descriptor template: wsh(thresh(3,pk(@0/**),s:pk(@1/**),s:pk(@2/**),sln:older(12960)))
Keys info: ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", "[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js", "[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2"]
Descriptor: wsh(thresh(3,pk([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<0;1>/*),s:pk([b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js/<0;1>/*),s:pk([a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2/<0;1>/*),sln:older(12960)))
Miniscript: A singlesig wallet with automatic inheritance to a timelocked 2-of-3 multisig
Descriptor template: wsh(or_d(pk(@0/**),and_v(v:multi(2,@1/**,@2/**,@3/**),older(65535))))
Keys info: ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", "[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js", "[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2", "[bb641298/44'/0'/0'/100']xpub6Dz8PHFmXkYkykQ83ySkruky567XtJb9N69uXScJZqweYiQn6FyieajdiyjCvWzRZ2GoLHMRE1cwDfuJZ6461YvNRGVBJNnLA35cZrQKSRJ"]
Descriptor: wsh(or_d(pk([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<0;1>/*),and_v(v:multi(2,[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js/<0;1>/*,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2/<0;1>/*,[bb641298/44'/0'/0'/100']xpub6Dz8PHFmXkYkykQ83ySkruky567XtJb9N69uXScJZqweYiQn6FyieajdiyjCvWzRZ2GoLHMRE1cwDfuJZ6461YvNRGVBJNnLA35cZrQKSRJ/<0;1>/*),older(65535))))
Taproot wallet policy with sortedmulti_a and a miniscript leaf
Descriptor template: tr(@0/**,{sortedmulti_a(1,@0/<2;3>/*,@1/**),or_b(pk(@2/**),s:pk(@3/**))})
Keys info: ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", "xpub6Fc2TRaCWNgfT49nRGG2G78d1dPnjhW66gEXi7oYZML7qEFN8e21b2DLDipTZZnfV6V7ivrMkvh4VbnHY2ChHTS9qM3XVLJiAgcfagYQk6K", "xpub6GxHB9kRdFfTqYka8tgtX9Gh3Td3A9XS8uakUGVcJ9NGZ1uLrGZrRVr67DjpMNCHprZmVmceFTY4X4wWfksy8nVwPiNvzJ5pjLxzPtpnfEM", "xpub6GjFUVVYewLj5no5uoNKCWuyWhQ1rKGvV8DgXBG9Uc6DvAKxt2dhrj1EZFrTNB5qxAoBkVW3wF8uCS3q1ri9fueAa6y7heFTcf27Q4gyeh6"]
Descriptor: tr([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<0;1>/*,{sortedmulti_a(1,[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa/<2;3>/*,xpub6Fc2TRaCWNgfT49nRGG2G78d1dPnjhW66gEXi7oYZML7qEFN8e21b2DLDipTZZnfV6V7ivrMkvh4VbnHY2ChHTS9qM3XVLJiAgcfagYQk6K/<0;1>/*),or_b(pk(xpub6GxHB9kRdFfTqYka8tgtX9Gh3Td3A9XS8uakUGVcJ9NGZ1uLrGZrRVr67DjpMNCHprZmVmceFTY4X4wWfksy8nVwPiNvzJ5pjLxzPtpnfEM/<0;1>/*),s:pk(xpub6GjFUVVYewLj5no5uoNKCWuyWhQ1rKGvV8DgXBG9Uc6DvAKxt2dhrj1EZFrTNB5qxAoBkVW3wF8uCS3q1ri9fueAa6y7heFTcf27Q4gyeh6/<0;1>/*))})
Taproot MuSig2 3-of-3 in the key path, with three 2-of-2 MuSig2 recovery paths after 90 days in the script paths
Descriptor template: tr(musig(@0,@1,@2)/**,{and_v(v:pk(musig(@0,@1)/**),older(12960)),{and_v(v:pk(musig(@0,@2)/**),older(12960)),and_v(v:pk(musig(@1,@2)/**),older(12960))}})
Keys info: ["[6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa", "[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js", "[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2"]
Descriptor: tr(musig([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa,[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2)/<0;1>/*,{and_v(v:pk(musig([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa,[b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js)/<0;1>/*),older(12960)),{and_v(v:pk(musig([6738736c/48'/0'/0'/100']xpub6FC1fXFP1GXQpyRFfSE1vzzySqs3Vg63bzimYLeqtNUYbzA87kMNTcuy9ubr7MmavGRjW2FRYHP4WGKjwutbf1ghgkUW9H7e3ceaPLRcVwa,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2)/<0;1>/*),older(12960)),and_v(v:pk(musig([b2b1f0cf/44'/0'/0'/100']xpub6EYajCJHe2CK53RLVXrN14uWoEttZgrRSaRztujsXg7yRhGtHmLBt9ot9Pd5ugfwWEu6eWyJYKSshyvZFKDXiNbBcoK42KRZbxwjRQpm5Js,[a666a867/44'/0'/0'/100']xpub6Dgsze3ujLi1EiHoCtHFMS9VLS1UheVqxrHGfP7sBJ2DBfChEUHV4MDwmxAXR2ayeytpwm3zJEU3H3pjCR6q6U5sP2p2qzAD71x9z5QShK2)/<0;1>/*),older(12960))}})
=== Invalid policies ===
The following descriptor templates are invalid:
* pkh(@0): Key placeholder with no path following it
* pkh(@0/0/**): Key placeholder with an explicit path present
* sh(multi(1,@1/**,@0/**)): Key placeholders out of order
* sh(multi(1,@0/**,@2/**)): Skipped key placeholder @1
* sh(multi(1,@0/**,@0/**)): Repeated keys with the same path expression
* sh(multi(1,@0/<0;1>/*,@0/<1;2>/*)): Non-disjoint multipath expressions (@0/1/* appears twice)
* sh(multi(1,@0/**,xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU/<0;1>/*)): Expression with a non-KP key present
* pkh(@0/<0;1;2>/*): Allowed cardinality > 2
* tr(musig(@0/**,@1/**)): Derivation before aggregation is not allowed in wallet policies (despite being allowed in [[bip-0390.mediawiki|BIP-390]])
Remark: some of the examples of invalid descriptor templates may be valid via optional extensions.
== Backwards Compatibility ==
The @ character used for key placeholders is not part of the syntax of output script descriptors, therefore any valid descriptor with at least one KEY expression is not a valid descriptor template. Vice versa, any descriptor template with at least one key placeholder is not a valid output script descriptor.
Adoption of wallet policies in software and hardware wallets is opt-in. Conversion from wallet policies to the corresponding descriptors is programmatically extremely easy, and conversion from descriptors to wallet policies (when respecting the required patterns) can be automated. See the reference implementation below for some examples of conversion.
Software wallets are recommended to allow exporting plain descriptors for the purposes of interoperability with software not using wallet policies.
== Reference Implementation ==
Wallet policies are implemented in
* the [https://github.com/LedgerHQ/app-bitcoin-new Ledger bitcoin application] since version 2.1.0;
* the [https://github.com/digitalbitbox/bitbox02-firmware BitBox02 firmware] since version v9.15.0;
* [https://github.com/Blockstream/Jade Blockstream Jade] since version v1.0.24, via [https://github.com/ElementsProject/libwally-core libwally-core] v1.0.0.
* [https://github.com/btcpayserver/btcpayserver BTCPay Server] from version [https://github.com/btcpayserver/btcpayserver/pull/6684 v2.1.1]. (Currently only a limited subset of singlesig and multisig policies)
* [https://github.com/MetacoSA/NBitcoin/ NBitcoin] through Miniscript.Parse.
For development and testing purposes, we provide a [[bip-0388/wallet_policies.py|Python 3.7 reference implementation]] of simple classes to handle wallet policies, and the conversion to/from output script descriptors.
The reference implementation is for demonstration purposes only and not to be used in production environments.
== Change Log ==
* '''1.1.0''' (2024-11):
** Added support for musig key placeholders in descriptor templates.
* '''1.0.0''' (2024-05):
** Initial version.
== Footnotes ==
== Acknowledgments ==
The authors would like to thank the people who provided feedback in the bitcoin-dev list, and in person.
================================================
FILE: bip-0389.mediawiki
================================================
==Abstract==
This document specifies a modification to Key Expressions of Descriptors that are described in BIP 380.
This modification allows Key Expressions to indicate BIP 32 derivation path steps that can have multiple values.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
Descriptors can describe the scripts that are used in a wallet, but wallets often require at least two descriptors for all of the scripts that they watch for.
Wallets typically have one descriptor for producing receiving addresses, and the other for change addresses.
These descriptors are often extremely similar - they produce the same types of scripts, derive keys from the same master key, and use derivation paths that are almost identical.
The only differences are in the derivation path where one of the steps will be different between the descriptors.
Thus it is useful to have a notation to represent both descriptors as a single descriptor where one of the derivation steps is a pair of values.
==Specification==
For extended keys and their derivations paths in a Key Expression, BIP 380 states:
* xpub encoded extended public key or xprv encoded extended private key (as defined in BIP 32)
** Followed by zero or more /NUM or /NUMh path elements indicating BIP 32 derivation steps to be taken after the given extended key.
** Optionally followed by a single /* or /*h final step to denote all direct unhardened or hardened children.
This is modified to state:
* xpub encoded extended public key or xprv encoded extended private key (as defined in BIP 32)
** Followed by zero or more /NUM (may be followed by h, H, or ' to indicate a hardened step) path elements indicating BIP 32 derivation steps to be taken after the given extended key.
** Followed by zero or one / (each NUM may be followed by h, H, or ' to indicate a hardened step) path element indicating a tuple of BIP 32 derivation steps to be taken after the given extended key.
*** Followed by zero or more ;NUM (may be followed by h, H, or ' to indicate a hardened step) additional tuple values of BIP 32 derivation steps
*** Followed by a single >/
** Followed by zero or more /NUM (may be followed by h, H, or ' to indicate a hardened step) path elements indicating BIP 32 derivation steps to be taken after the given extended key.
** Optionally followed by a single /* (may be followed by h, H, or ' to indicate a hardened step) final step to denote all direct unhardened or hardened children.
When a / is encountered, parsers should account for a presence of multiple descriptors where the first descriptor uses the first NUM, and a second descriptor uses the second NUM, and so on, until each NUM is accounted for in the production of public keys, scripts, and addresses, as well as descriptor import and export operations.
Descriptors that contain multiple Key Expressions that each have a / must have tuples of exactly the same length so that they are derived in lockstep in the same way that /* paths in multiple Key expressions are handled.
Duplicate NUMs within a tuple are not allowed.
The common use case for this is to represent descriptors for producing receiving and change addresses.
When interpreting for this use case, wallets should use the first descriptor for producing receiving addresses, and the second descriptor for producing change addresses.
For this use case, the element will commonly be the value /<0;1>
Note that only one / specifier is allowed in a Key Expression.
==Test Vectors==
Valid multipath descriptors followed by the descriptors they expand into as sub-bullets
* pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/<0;1>)
** pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)
** pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/1)
* pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<2147483647h;0>/0)
** pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647h/0)
** pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/0/0)
* wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/<1;3>/2/*
** wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)
** wpkh([ffffffff/13h]xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/3/2/*)
* multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2>/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/<3;4>/0/*)
** multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/3/0/*)
** multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/4/0/*)
* pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;1;2>)
** pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0)
** pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1)
** pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2)
* sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*))
** sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/3/*))
** sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/2/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/4/*))
** sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/0/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/*,xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/5/*))
Invalid descriptors
* Multiple multipath specifiers: pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/<0;1>/<2;3>)
* Multipath specifier in origin: pkh([deadbeef/<0;1>]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0)
* Multipath specifiers of mismatched lengths: tr(xpub661MyMwAqRbcF3yVrV2KyYetLMYA5mCbv4BhrKwUrFE9LZM6JRR1AEt8Jq4V4C8LwtTke6YEEdCZqgXp85YRk2j74EfJKhe3QybQ9kcUjs4/<6;7;8;9>/*,{pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<1;2;3>/0/*),pk(xpub661MyMwAqRbcGDZQUKLqmWodYLcoBQnQH33yYkkF3jjxeLvY8qr2wWGEWkiKFaaQfJCoi3HeEq3Dc5DptfbCyjD38fNhSqtKc1UHaP4ba3t/0/0/<3;4;5>/*)})
* Multipath specifiers of mismatched lengths: sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/<1;2;3>/0/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/*,xprv9s21ZrQH143K3jUwNHoqQNrtzJnJmx4Yup8NkNLdVQCymYbPbJXnPhwkfTfxZfptcs3rLAPUXS39oDLgrNKQGwbGsEmJJ8BU3RzQuvShEG4/0/0/<3;4>/*))
* Empty multipath specifier: wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<>/*)
* Missing multipath start: wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/0>/*)
* Missing multipath end: wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0/*)
* Missing index in multipath specifier: wpkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/<0;>/*)
==Backwards Compatibility==
This is an addition to the Key Expressions defined in BIP 380.
Key Expressions using the format described in BIP 380 are compatible with this modification and parsers that implement this will still be able to parse such descriptors.
However as this is an addition to Key Expressions, older parsers will not be able to understand such descriptors.
This modification to Key Expressions uses two new characters: < and ;.
These are part of the descriptor character set and so are covered by the checksum algorithm.
As these are previously unused characters, old parsers will not accidentally mistake them for indicating something else.
This proposal is in contrast to similar proposals such as BIP 88 which allow for multiple derivation indexes in a single element.
This limitation exists in order to reduce the number of descriptors that are expanded, avoid confusion about how to expand the descriptor, and avoid having expanded descriptors that users are not expecting.
==Reference Implementation==
https://github.com/bitcoin/bitcoin/pull/22838
================================================
FILE: bip-0390.mediawiki
================================================
==Abstract==
This document specifies a musig() key expression for output script descriptors.
musig() expressions take multiple keys and produce an aggregate public key using [[bip-0327.mediawiki|BIP-327]].
==Copyright==
This BIP is licensed under the Creative Commons CC0 1.0 Universal license.
==Motivation==
[[bip-0327.mediawiki|BIP-327]] introduces the MuSig2 Multi-Signature scheme. It is useful to have a way for keys to be used
in a MuSig2 aggregate key to be expressed in descriptors so that wallets can more easily use MuSig2.
==Specification==
A new key expression is defined: musig().
In the following sections, the term KEY refers to key expressions as defined in [[bip-0380.mediawiki|BIP-380]]
and [[bip-0389.mediawiki|BIP-389]].
===musig(KEY, KEY, ..., KEY)===
The musig(KEY, KEY, ..., KEY) expression can only be used inside of a tr(), rawtr()
or sp() expression as a key expression. It additionally cannot be nested within another musig()
expression. Participant public keys may be repeated. The aggregate public key is produced
by using the KeyAgg algorithm on all KEYs specified in the expression after performing all
specified derivation. As with script expressions, KEY can contain child derivation specified by
/*. A new aggregate public key will be computed for each child index. Keys must be sorted
with the KeySort algorithm after all derivation and prior to aggregation'''Why must
the keys be sorted prior to aggregation?''' Although the descriptor's written form sets an order
for the keys that could be used for aggregation, the order should not matter as MuSig2 philosophically
operates over a set of keys, with the order merely being an implementation detail in aggregation
itself. Requiring sorting of keys prior to aggregation enforces this philosophy as keys can be
written in the descriptor in any order with the end result still being the same. Furthermore, this
aids with recovery where the descriptor was not backed up as users will not need to also have
backed up, or guess, the correct order of keys..
===musig(KEY, KEY, ..., KEY)/NUM/.../*===
musig(KEY, KEY, ..., KEY)/NUM/.../* expressions are also allowed if no KEY expression
contains child derivation as specified by /* or multipath as specified with
/, in addition to the same usage restrictions as in the previous section. The KEY expressions
additionally must be xpubs or derived from xpubs. The aggregate public key is first computed as
described above, with the keys also being sorted after all derivation and prior to aggregation.
Then further [[bip-0032.mediawiki|BIP-32]] derivation will be performed on the aggregate public key as described in
[[bip-0328.mediawiki|BIP-328]]. The /NUM/.../* following the musig() specifies
the derivation path to be used when deriving from the aggregate public key. /* is also
optional. As there is no aggregate private key, only unhardened derivation from the aggregate public
key is allowed. Thus these derivation steps cannot contain /NUMh or /NUM'
nor can child derivation be specified as /*h, or /*'.
==Test Vectors==
Valid descriptors containing followed by the scripts they produce. Descriptors involving derived child keys
will have the 0th, 1st, and 2nd scripts listed.
* rawtr(musig(KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU74sHUHy8S,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
** 5120789d937bade6673538f3e28d8368dda4d0512f94da44cf477a505716d26a1575
* tr(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
** 512079e6c3e628c9bfbce91de6b7fb28e2aec7713d377cf260ab599dcbc40e542312
* rawtr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0/*)
** 51209508c08832f3bb9d5e8baf8cb5cfa3669902e2f2da19acea63ff47b93faa9bfc
** 51205ca1102663025a83dd9b5dbc214762c5a6309af00d48167d2d6483808525a298
** 51207dbed1b89c338df6a1ae137f133a19cae6e03d481196ee6f1a5c7d1aeb56b166
* tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0/*,pk(f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9))
** 51201d377b637b5c73f670f5c8a96a2c0bb0d1a682a1fca6aba91fe673501a189782
** 51208950c83b117a6c208d5205ffefcf75b187b32512eb7f0d8577db8d9102833036
** 5120a49a477c61df73691b77fcd563a80a15ea67bb9c75470310ce5c0f25918db60d
* tr(f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,pk(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0/*))
** 512068983d461174afc90c26f3b2821d8a9ced9534586a756763b68371a404635cc8
** 5120368e2d864115181bdc8bb5dc8684be8d0760d5c33315570d71a21afce4afd43e
** 512097a1e6270b33ad85744677418bae5f59ea9136027223bc6e282c47c167b471d5
* tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1)/2)
** 5120a17ceacd6422bd5ffd9f165807b254b7d68ad39f179cc4f11545a6835227e97c
Invalid descriptors
* musig() is not allowed in top-level pk(): pk(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
* musig() is not allowed in top-level pkh(): pkh(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
* musig() is not allowed in wpkh(): wpkh(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
* musig() is not allowed in combo(): combo(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
* musig() is not allowed in sh(wpkh()): sh(wpkh(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66)))
* musig() is not allowed in sh(wsh()): sh(wsh(pk(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))))
* musig() is not allowed in wsh(): wsh(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
* musig() is not allowed in sh(): sh(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66))
* Ranged musig() requires all participants to be xpubs: tr(musig(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9,03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66)/0/0)
* Cannot have ranged participants if musig() is also ranged: tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0/*)
* Cannot have multipath participants if musig() is also multipath: tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/<0;1>,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/<2;3>)
* musig() cannot have hardened derivation steps: tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0h/*)
* musig() cannot have hardened child derivation: tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y)/0/*h)
* musig() cannot have participants with child derivation when musig() has derivation steps: tr(musig(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/*)/1/2
==Backwards Compatibility==
musig() expressions use the format and general operation specified in
[[bip-0380.mediawiki|BIP-380]]. As these are a set of wholly new expressions, they are not compatible
with any implementation. However the keys are produced using a standard process so existing software
are likely to be familiar with them.
==Rationale==
==Reference Implementation==
The reference implementation is available in Bitcoin Core [[https://github.com/bitcoin/bitcoin/pull/31244|PR #31244]].
==Changelog==
* __0.2.0__ (2026-03-04) - Allow musig() inside sp() expressions.
* __0.1.0__ (2025-12-08) - Allow musig() inside rawtr() expressions.
==Acknowledgements==
Thanks to Pieter Wuille, Andrew Poelstra, Sanket Kanjalkar, Salvatore Ingala, and all others who
participated in discussions on this topic.
================================================
FILE: bip-0392.mediawiki
================================================
==Abstract==
This document specifies sp() output script descriptors for silent payments.
sp() descriptors take silent payment key material and describe P2TR outputs when combined with sender input public keys as defined in BIP352.
==Copyright==
This BIP is licensed under the BSD 2-clause license.
==Motivation==
BIP352 defines silent payments, a protocol for static payment addresses without on-chain linkability.
This descriptor provides a standardized way to represent silent payment outputs within the output descriptor framework, enabling wallet interoperability and backup/recovery using existing descriptor-based infrastructure.
==Specification==
A new top level script expression is defined: sp().
===Key Expressions===
Two new key expression types are defined for use with sp() descriptors:
====spscan====
The spscan key expression encodes the scan private key and spend public key.
It is a [https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki Bech32m] encoding of:
* The human-readable part "spscan" for mainnet, "tspscan" for testnets
* The data-part values:
** The character "q", to represent silent payments version 0
** The payload: ser256(bscan) || serP(Bspend)
====spspend====
The spspend key expression encodes both the scan and spend private keys.
It is a [https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki Bech32m] encoding of:
* The human-readable part "spspend" for mainnet, "tspspend" for testnets
* The data-part values:
** The character "q", to represent silent payments version 0
** The payload: ser256(bscan) || ser256(bspend)
Note: The serialization of ser256(p) and serP(P) follows the definition in BIP352.
===sp()===
The sp(KEY) or sp(KEY,KEY) expression can only be used as a top level descriptor.
sp(KEY) takes a single key expression as an argument, which must be either an spscan or spspend encoded key, optionally with key origin information.
If included, the key origin information specifies the fingerprint and derivation path to the depth from which the scan and spend keys are derived using the child paths recommended in BIP352 (1h/0 for scan, 0h/0 for spend).
sp(KEY,KEY) takes two key expressions.
The first key expression represents the scan key and must be a single private key (e.g. a WIF compressed private key or xprv extended private key).
The second key expression represents the spend key and may be any key expression as defined in BIP380 or other key expression BIPs (e.g. musig() as defined in BIP390) that represents a single key, public or private.
Note however that uncompressed keys are not allowed under any sp() expression, as BIP352 only permits compressed public keys.
When combined with sender input public keys, the descriptor produces P2TR output scripts describing silent payments made to wallets represented by the key expression(s).
The output scripts produced are BIP341 taproot outputs as specified in BIP352.
==Examples==
Valid descriptors:
* sp(spscan1q...) - Using spscan encoded key (watch-only)
* sp([deadbeef/352h/0h/0h]spscan1q...) - With key origin
* sp(spspend1q...) - Using spspend encoded key (full wallet)
* sp(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600) - WIF scan key with compressed public spend key (watch-only)
* sp([deadbeef/352h/0h/0h]xprv.../0h,xpub.../0h) - Extended private scan key with extended public spend key (watch-only)
* sp([deadbeef/352h/0h/0h]xprv.../0h,xprv.../0h) - Extended private keys for both scan and spend (full wallet)
* sp(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,musig(03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66)) - WIF scan key with MuSig2 aggregate spend key (watch-only)
Invalid descriptors:
* sp() requires at least one key expression
* sp(xpub...) single argument form requires spscan or spspend encoded key
* sp(xpub...,xpub...) two argument form requires private scan key (e.g. WIF or xprv)
* sp(spscan1q...,spscan1q...) two argument form requires single key expressions
* sp(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600) uncompressed private key
* sh(sp(spscan1q...)) sp() is top level only
* wsh(sp(spscan1q...)) sp() is top level only
==Usage Notes==
For watch-only wallets, use spscan encoding or the two argument form with a public spend key.
For full wallets that can both scan and spend, use spspend encoding or the two argument form with a private spend key.
When using the two argument form, the scan key must be private (e.g. WIF or xprv) since scanning requires the private scan key.
==Backwards Compatibility==
sp() descriptors use the format and general operation specified in BIP380.
As this is a wholly new descriptor, it is not compatible with any prior implementation.
The scripts produced are BIP341 taproot outputs, making them indistinguishable from other taproot outputs on-chain.
==Reference Implementation==
TBD
==Test Vectors==
TBD
================================================
FILE: bip-0431.mediawiki
================================================
==Abstract==
This document describes pinning problems that can arise from limitations in mempool policy.
It also describes a type of policy with adjusted topology limits which, combined with other policy rules, helps minimize the potential pinning problems. These restrictions simplify the assessment of incentive compatibility of accepting or replacing such transactions, thus helping ensure any replacements are more profitable for the node. Within the context of nodes that implement this policy, fee-bumping is more reliable for users.
==Motivation==
Mempools typically accept and relay transactions that spend outputs from other unconfirmed transactions, but restrict package sizes through ancestor and descendant limits
https://github.com/bitcoin/bitcoin/blob/632a2bb731804dffe52bd4cbd90bfee352d25ede/doc/policy/mempool-limits.md
to limit the computational complexity of mempool operations and mitigate Denial of Service attacks.
Users may also create unconfirmed transactions that conflict with -- or are "double spends" of -- each other by spending the same input(s) in both.
Instead of always keeping the first-seen transaction, many mempools also have some kind of Replace by Fee (RBF) policy
[https://github.com/bitcoin/bitcoin/blob/632a2bb731804dffe52bd4cbd90bfee352d25ede/doc/policy/mempool-replacements.md Bitcoin Core's RBF policy] at the time of writing. It is slightly different from what is described in BIP 125.
to keep the more incentive compatible transaction, i.e. one that would earn a miner more fees. Users utilize these rules when they create higher feerate double-spends (replacements) to expedite confirmation of their transactions.
However, these policies make imperfect trade-offs between incentive compatibility and DoS-resistance. For example, malicious actors may sometimes exploit limitations to prevent incentive-compatible transactions from being accepted or fee-bumped (''pinning'').
Pinning is consequential to contracting protocols in which untrusted parties construct and sign time-sensitive transactions to be broadcast on-chain later
Posts about pinning in LN and LN-Symmetry:
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-May/020458.html "Bringing a nuke to a knife fight: Transaction introspection to stop RBF pinning"]
* [https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-April/002639.html "RBF Pinning with Counterparties and Competing Interest"]
* [https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-June/002758.html "Pinning : The Good, The Bad, The Ugly"]
* [https://github.com/t-bast/lightning-docs/blob/master/pinning-attacks.md "Pinning Attacks"]
* [https://gist.github.com/instagibbs/60264606e181451e977e439a49f69fe1 "Eltoo Pinning"]
.
When the funds available to be redeemed by each party depend on a transaction confirming within a specific time window, a malicious party may be able to steal money if the honest party cannot get their transaction confirmed. As such, the ability to fee-bump a transaction to entice miners to include it in their blocks is crucial to the security of the protocol.
===RBF pinning through absolute fees===
Imagine that counterparties Alice and Mallory have transactions (or packages) A and B, respectively, which conflict with each other. Alice broadcasts A and Mallory broadcasts B. RBF rules require the replacement transaction pay a higher absolute fee than the aggregate fees paid by all original transactions ([https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy "Rule 3"]). This means Mallory may increase the fees required to replace B beyond what Alice was planning to pay for A's fees.
1. Adding transaction(s) that descend from B and pay a low feerate (too low to fee-bump B through CPFP)Example: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-December/022216.html.
2. Adding a high-fee descendant of B that also spends from another large, low-feerate mempool transaction (where the fee of the descendant is too low to fee-bump both B and its other parent through CPFP)Example: https://github.com/bitcoin/bitcoin/pull/25038#issuecomment-1320295394.
===RBF pinning through number of conflicts===
RBF rules require that no replacement trigger the removal of more than 100 transactions ([https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy "Rule 5"]). This number includes the descendants of the conflicted mempool transactions. Mallory can make it more difficult to replace transactions by attaching lots of descendants to them. For example, if Alice wants to batch-replace 5 transactions but each has 21 descendants, her replacement will be rejected regardless of its fees.
===RBF incentive compatibility requirements===
There is currently no effective rule to enforce that a replacement transaction would be more incentive compatible to keep in the mempool. It is difficult to quantify the incentive compatibility of a set of transactions, especially in comparison with another set of transactionshttps://delvingbitcoin.org/t/mempool-incentive-compatibility/553, but the requirement of a feerate increase ([https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy "Rule 6"]) is far too simplistic.
For example, a user could create a replacement transaction that pays more fees and is higher feerate, but has a low feerate ancestor and would confirm slower than the original transaction. As a result, all transactions signed with SIGHASH_ANYONECANPAY are vulnerable to being replaced by a transaction that will confirm later than the originalhttps://github.com/bitcoin/bitcoin/pull/23121#pullrequestreview-766271585.
===Child fees don't count towards RBF rules===
A transaction must meet all fee-related requirements (Rules 3, 4, 6) alone; its child's fees cannot be used. A ''Package RBF'' policy would allow a transaction's child to be used for its RBF requirements.
In LN Penalty, conflicting commitment transactions signed with the same fees cannot replace each other, even if accompanied by a fee-bumping child. This limitation necessitates the presence of two anchor outputs, allowing both parties to fee-bump either commitment transaction that enters their mempool.
===Package limit pinning and replacing CPFP Carve Out===
Mempool policies limit the number and total virtual size of an unconfirmed transaction's descendants. A fee-bumping child of an unconfirmed transaction (CPFP) may be rejected for exceeding the descendant limit. When a transaction has multiple outputs owned by different parties, a malicious party can prevent the other(s) from CPFPing their transaction by attaching enough descendants to monopolize the descendant limit (''package limit pinning'').
LN commitment transactions rely on CPFP carve out [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html "CPFP Carve-Out for Fee-Prediction Issues in Contracting Applications (eg Lightning)"] to avoid package limit pinning.
There are weaknesses with this approach of using 2 anchors and CPFP Carve Out. This proposal helps address a few of them (see Related Work for how other weaknesses are addressed):
* Cluster Mempool necessitates the removal of CPFP Carve Out https://delvingbitcoin.org/t/an-overview-of-the-cluster-mempool-proposal/393#the-cpfp-carveout-rule-can-no-longer-be-supported-12.
* CPFP Carve Out only allows ''one more'' child to be added to the transaction. This means it cannot guarantee the ability to CPFP for more than 2 parties of a shared transaction.
==Topologically Restricted Until Confirmation==
This section describes one approach for opt-in policy rules that can realistically be deployed today and is useful to today's applications.
It is based on the idea that most limitations stem from existing ancestor/descendant package limits being too permissive for the majority of use cases.
The scope of the policy's anti-pinning benefits is limited to the individual node's mempool, and the degree to which a user's transaction is safe from pinning depends how much of the network has adopted this policy.
Similarly, there are multiple approaches to creating a policy to minimize pinning, more may become available over time (see Related Work section), and the details of this approach can be tweaked if conditions change. For example, if loosening one of the topology restrictions enables a new use case while still providing acceptable pinning bounds, it can be changed.
===Specification===
Senders can signal that they want a transaction to be Topologically Restricted Until Confirmation (TRUC). Specifically, set nVersion=3.
A node that implements this policy would apply their existing standardness and policy rules, along with the following set of rules, to TRUC transactions:
1. A TRUC transaction signals replaceability, even if it does not signal BIP125 replaceability.
2. Any TRUC transaction's unconfirmed ancestors must all be TRUC. Any descendant of an unconfirmed TRUC transaction must also be TRUC.
Rationale:
* Requiring packages to be all-or-none TRUC makes it possible to enforce the topology limits. For example, the TRUC descendant limit would not be very meaningful if it could be bypassed by creating a non-TRUC child.
* Combined with Rule 1, this requirement creates "inherited signaling" when descendants of unconfirmed transactions are created. Checking whether a transaction signals replaceability this way does not require mempool traversal, and does not change based on what transactions are mined.
Note: A TRUC transaction can spend outputs from ''confirmed'' non-TRUC transactions. A non-TRUC transaction can spend outputs from ''confirmed'' TRUC transactions.
3. An unconfirmed TRUC transaction cannot have more than 1 unconfirmed ancestor. An unconfirmed TRUC transaction cannot have more than 1 unconfirmed descendant. CPFP Carve Out is not granted to TRUC transactions.
Rationale:
* The larger the descendant limit, the more transactions may need to be replaced. See #1 in Rule 3 Pinning section above. This also makes pinning using Rule 5 more difficult, since a directly conflicting transaction has fewer possible descendants.
* These two limits (ancestor count 2, descendant count 2) effectively create a cluster limit using the existing ancestor and descendant limits. Increasing them to 3 would imply an infinite cluster count limit.
* This 1-parent-1-child topology makes it possible to use ancestor score (minimum of ancestor feerate and individual feerate) as a measure of incentive compatibility.
Q: Why not allow multiple parents to enable batched fee-bumping?
To mitigate pinning through absolute fees, we need to prevent a child of an unconfirmed TRUC transaction from bringing in more unconfirmed ancestors. See #2 in "RBF pinning through absolute fees" section above.
Q: Why not allow another child?
Allowing another child disables the ability to use ancestor score to measure incentive compatibility. Imagine the original transaction, A, has a child B and co-parent C (i.e. B spends from A and C). C also has another child, D. B is one of the original transactions and thus its ancestor feerate must be lower than the package's feerate. However, this may be an underestimation because D can bump C without B's help. This is resolved if TRUC transactions can only have TRUC ancestors, as then C cannot have another child.
Q: Why allow any descendants at all?
At least 1 descendant is required to allow CPFP of the presigned transaction. Without package RBF, multiple anchor outputs would be required to allow each counterparty to fee-bump any presigned transaction. With package RBF, since the presigned transactions can replace each other, 1 anchor output is sufficient.
4. A TRUC transaction cannot have a sigop-adjusted virtual size larger than 10,000 vB.
Rationale: Limit the amount of virtual bytes (and thus fees) that may need to be replaced, while leaving a comfortable amount of space for payments, HTLCs, or other uses of the transaction. Generally, having a smaller maximum size helps to better define bounds for algorithms and memory usage, and the existing limit of 100,000 vB seems much larger than necessary.
5. A TRUC transaction that has an unconfirmed TRUC ancestor cannot have a sigop-adjusted virtual size larger than 1000 vB.
Rationale: Limit the amount of virtual bytes (and thus fees) that may need to be replaced, while leaving a comfortable amount of space for inputs to fund the transaction.
Q: Why not bigger?
The larger the descendant size limit, the more vbytes may need to be replaced. With default limits, if the child is e.g. 100,000 vB, that might be an additional 100,000 sats (at 1 sat/vbyte) or more, depending on the feerate. Restricting all children to 1000 vB reduces the upper bound of the additional fees by a factor of 100.
This rule is also easily tacked on to existing logic for policy and wallets. A maximum size standard transaction (100 kvB) can have up to 1000 vB of descendants to be within the default descendant limit (101 kvB).
Q: Why not smaller?
The smaller this limit, the fewer UTXOs a child may use to fund this fee-bump. For example, only allowing the TRUC child to have 2 inputs would require wallets to maintain a pool of high-value confirmed UTXOs. However, as the fee-bumping child only needs to fund fees (as opposed to payments), just a few UTXOs should suffice. With a limit of 1000 vB and usage of taproot outputs, the child can have 15 inputs and 2 outputs (calculated using [https://bitcoinops.org/en/tools/calc-size/ this tool]).
6. An individual TRUC transaction is permitted to be below the mempool min relay feerate, assuming it is considered within a package that meets the mempool's feerate requirements.
Rationale: This allows contracting protocols to create presigned transactions with 0 fees and fee-bump them using CPFP at broadcast time.
====Implementation====
* https://github.com/bitcoin/bitcoin/pull/28948
* https://github.com/bitcoin/bitcoin/pull/29873
* https://github.com/bitcoin/bitcoin/pull/29496
====Related Work====
This 1-parent-1-child (aka cluster size 2) topology restriction makes the transactions much easier to reason about, which enables additional features like
feerate diagram comparisons
[https://github.com/bitcoin/bitcoin/pull/29242 this PR] implements feerate diagram creation and comparison for sets of transactions in which the maximum cluster size is 2, e.g. all TRUC transactions.
,
package RBF
[https://github.com/bitcoin/bitcoin/pull/28984 this PR] implements package RBF, enforcing incentive compatibility by comparing the feerate diagrams of the mempool before and after replacement. The feerate diagrams are easy to build when the relevant clusters are of size 2 and below, so package RBF is restricted to those scenarios. As TRUC transactions always have this property, package RBF is enabled for TRUC transactions.
,
and sibling eviction
[https://github.com/bitcoin/bitcoin/pull/29306 This PR] implements sibling eviction for TRUC transactions: if a new transaction would exceed a transaction's descendant limit, it considers evicting the existing descendant using replacement rules. Sibling eviction is feasible for TRUC transactions because there is no difficulty in identifying which descendant to evict (there can only be 1).
.
The [https://github.com/bitcoin/bips/pull/1524 Ephemeral Anchors] proposal builds on top of this one to add more features.
It changes the anchor script to be anyone can spend, allowing anybody to add fees and reducing the onchain footprint and fee costs.
It also allows anchor outputs to have 0 value, eliminating the need to deduct value from the input amount in order to create anchors.
The [https://delvingbitcoin.org/t/an-overview-of-the-cluster-mempool-proposal/393/7 Cluster Mempool] proposal makes fundamental changes to mempool structure and policy rules, enabling the accurate assessment of the incentive compatibility of accepting or removing a transaction, among other things. Notably, Cluster Mempool introduces a limit to all transactions' cluster size to make incentive compatibility calculations feasible. This cluster limit is similar to TRUC limits in that it bounds computation to enable improved policies, but is applied to all transactions (not just ones that opt in) and is much less restrictive than TRUC limits.
Cluster Mempool provides a more holistic solution to some of the problems listed (such as adding an incentive compatibility requirement to RBF and safely enabling package RBF for more complex topologies). However, it does not help resolve all problems (such as RBF Pinning through absolute fees and number of conflicts). Also, since Cluster Mempool is incompatible with CPFP Carve Outhttps://delvingbitcoin.org/t/an-overview-of-the-cluster-mempool-proposal/393#the-cpfp-carveout-rule-can-no-longer-be-supported-12, TRUC with sibling eviction and package RBF provide an alternative solution to applications that rely on it.
Building on top of Cluster Mempool, there are also various ideas for extending TRUC transactions and creating another anti-pinning policy
https://delvingbitcoin.org/t/v3-and-some-possible-futures/523/3.
[https://bitcoinops.org/en/topics/package-relay Package Relay] includes changes in p2p protocol, transaction relay logic, and mempool policy to enable nodes to accept and relay packages of transactions. Much of this proposal's utility relies on the existence of package relay for 1-parent-1-child packages (the topology TRUC supports).
====Backward Compatibility====
Transactions with nVersion=3 were previously nonstandard. There are no known conflicts with previous usage.
====Intended Usage====
Generally, users with no interest in spending unconfirmed outputs from a transaction can make them TRUC transactions for more robust RBF abilities.
This proposal allows for a different solution to fee-bumping in LN, in which commitment transactions are signed with 0 fees and include a single anchor that can later be used to add fees at broadcast time
Proposals for changes to LN commitment transaction format using TRUC and a single anchor:
* [https://delvingbitcoin.org/t/lightning-transactions-with-v3-and-ephemeral-anchors/418 "Lightning transactions with v3 and ephemeral anchors"]
* [https://github.com/instagibbs/bolts/commits/zero_fee_commitment bolts proposal branch]
* See "Intended usage for LN" section in [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-September/020937.html "New transaction policies (nVersion=3) for contracting protocols"]
.
A similar fee-bumping model can also be used in other contracting protocols
Examples of non-LN protocols that have shown interest in, designed, or built fee-bumping using TRUC:
* A LN-Symmetry implementation using TRUC and ephemeral anchors: [https://delvingbitcoin.org/t/ln-symmetry-project-recap/359 LN-Symmetry Project Recap] [https://github.com/instagibbs/lightning/tree/eltoo_support branch]
* See "Managing Fees Safely" mentioning ephemeral anchors in [https://jameso.be/vaults.pdf "Vaults and Covenants"]
.
==Alternatives==
Various alternatives for RBF
Proposals and discussions dedicated to improving RBF:
* [https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff "RBF Improvements"]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-January/019817.html "Improving RBF Policy"]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-June/016998.html "[PROPOSAL] Emergency RBF (BIP 125)"]
and new fee-bumping mechanisms
Proposals and discussions dedicated to improving or creating new fee-bumping mechanisms:
* [https://github.com/lightning/bolts/pull/1036 "Add option to sign commitments at various feerates"]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-July/019243.html "A Stroll through Fee-Bumping Techniques : Input-Based vs Child-Pay-For-Parent"]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-September/018168.html "A Replacement for RBF and CPFP: Non-Destructive TXID Dependencies for Fee Sponsoring"]
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-February/019879.html "Thoughts on fee bumping"]
have been proposed across multiple discussion threads.
Most alternatives do not conflict with TRUC, and some work in conjunction with this proposal - see Related Work.
A few popular ideas that were not incorporated into this work are summarized here.
===Alternatives: add static incentive compatibility rule in RBF policy===
Add incentive compatibility requirement to RBF policy using some existing score or static calculation
Examples of incentive compatibility score proposals and suggestions:
* [https://github.com/bitcoin/bitcoin/pull/23121 "check ancestor feerate in RBF, remove BIP125 Rule2"]
* [https://github.com/bitcoin/bitcoin/pull/26451 "Enforce incentive compatibility for all RBF replacements"]
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-January/019841.html
* https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff?permalink_comment_id=4081349#gistcomment-4081349
.
As the incentive compatibility "score" of a transaction must be dynamically calculated given the structure of mempools today, there is no satisfactory solution. A full calculation is too computationally expensive. Static values can overestimate or underestimate, leading to more pinning problems Four examples of static calculations and an example in which they are all inaccurate: https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff#mining-score-of-a-mempool-transaction.
The ability to calculate incentive compatibility scores efficiently is a primary feature and motivation for both TRUC transactions and Cluster Mempool.
===Alternatives: replace by feerate===
"Instead of using Rule 3 and/or 4 (requiring an increase in absolute fees), allow replacements with a higher feerate."
One variation of this proposal is to apply this rule in certain exceptional scenarios or when the replacement would confirm "soon"
Examples of Replace by Feerate proposals and suggestions:
* [https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-June/016998.html "[PROPOSAL] Emergency RBF (BIP 125)"]
* [https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff#fees-in-next-block-and-feerate-for-the-rest-of-the-mempool]
* [https://petertodd.org/2024/one-shot-replace-by-fee-rate "One-Shot Replace-by-Fee-Rate"]
.
The primary problem with these proposals is the potential for free relay and DDoS attacks.
Removing Rule 3 and 4 in general would allow free relay
Examples of free relay with the removal of Rule 3 and/or 4:
Consider a rule where the fee can be decreased (remove Rule 3 and 4) but the feerate must double. In this scenario, a 100 kvB transaction can be replaced by a 100 vB transaction paying 200 sats. That's 200 sats to relay 100,200 vB of transaction data, which is less than 0.002 sat/vB. It becomes quite cheap to replace large portions of the mempool, decreasing both its average feerate and total absolute fees.
Consider a rule where the fee can stay the same (keep Rule 3 but drop Rule 4) but the feerate must double. The attacker can start out with 100 kvB transaction, paying 1 sat/vB. A user can reduce its size over and over again, doubling the feerate each time until it gets too small, and end up paying 100 ksat for 100 kvB(1 + 1/2 + 1/4 + ... + log2(mintxsize)) -> approaches 200 kvB. This means the attacker pays a rate of 0.5 sat/vB to relay transactions, which is below our "free relay" threshold of 1 sat/vB.
.
Another issue is the complexity of defining and implementing a "would confirm soon" or "is in the top N portion of the mempool." These proposals require an efficient way to assess the incentive compatibility score of a transaction and where it ranks amongst the other mempool transactions. This isn't feasible without something like cluster mempool (also see the "add static incentive compatibility rule in RBF policy" section above)
Concerns about Replace by Feerate proposals
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-June/017020.html
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-June/017002.html
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-February/019879.html
* https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff?permalink_comment_id=4044451#gistcomment-4044451
.
===Alternatives: implement rate-limiting without fee rules===
"Since Rule 3 and 4 (requiring an increase in absolute fees) are for rate-limiting, replace them with a mempool-wide or per-peer rate limits on replacements by outpoint and/or bandwidth
Examples of general rate-limiting proposals and suggestions:
* https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff?permalink_comment_id=4081349#gistcomment-4081349
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-January/019820.html
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-June/017024.html
Related proposal for changing the amount of bandwidth that replacement transactions use:
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-January/019820.html
."
A problem with any global rate limit is that, in the absence of reputation or identities, the limit could be exhausted by an attacker, thus restricting replacements for honest users. For example, an outpoint-based rate limit could be exhausted by one dishonest participant of a shared transaction, preventing the other participants from making any replacements. There are also other concerns about implementation complexity, free relay issues, and other unresolved edge cases
Concerns
* https://gist.github.com/glozow/25d9662c52453bd08b4b4b1d3783b9ff?permalink_comment_id=4081559#gistcomment-4081559
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-February/019921.html
* https://docs.google.com/document/d/1LpYF17HdbXPGHKSl3WYdxG4XTJBNJKSn-c2UJ2yphhE/edit?usp=sharing
.
==Acknowledgements==
Thank you to everyone who contributed to this proposal and document, including
Jon Atack,
Matt Corallo,
Suhas Daftuar,
Mark Erhardt,
Antoine Poinsot,
Antoine Riard,
Gregory Sanders,
and Bastien Teinturier.
==References and Rationale==
================================================
FILE: bip-0433.mediawiki
================================================