Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 122 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

BRC

Loading...

Contribute

Example

Loading...

Apps

Loading...

Wallet

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Transactions

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Scripts

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Tokens

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Overlays

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Payments

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Peer-to-Peer

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Key Derivation

Loading...

Loading...

Loading...

Loading...

Simplified Payment Verification

Ty Everett ([email protected])

Abstract

The BRC-9 specification defines a process for Simplified Payment Verification (SPV) that allows payment recipients to verify the validity of a transaction without downloading and verifying the entire blockchain. The process involves verifying the headers and proofs of a BRC-8 Transaction Envelope, ensuring that all SPV proofs link back to the genesis block and the chain with the most proof of-work, and confirming that the transaction is valid according to the rules of Bitcoin. This standard aims to facilitate fast, secure, and efficient payment processing for merchants and users.

Motivation

The Bitcoin blockchain is a decentralized, distributed ledger that records every transaction on the network. However, downloading and verifying the entire blockchain can be time-consuming and resource-intensive, making it impractical for users who want to make quick, simple transactions. Simplified Payment Verification (SPV) provides a way for payment recipients to verify the validity of a transaction without the need for a full blockchain download. This protocol is essential for enabling fast and efficient payment processing, especially for small, casual transactions.

Specification

The steps for verifying the validity of a payment transaction using the BRC-9 SPV protocol are as follows:

  1. Ensure that the received Envelope is in the correct format

  2. Add any previously-unknown headers provided in the Envelope to the chain of headers

  3. Ensure that all SPV proofs link back to the genesis block and the chain with the most proof of-work

The above steps ensure that the transaction is valid and secure according to the Bitcoin protocol. Merchants may take additional measures to increase security, such as subscribing to mAPI status updates and double spend notifications, verifying the identity of the sender, waiting for confirmations, or using an escrow service.

Implementation

Any wallet that has access to a source of block headers is capable of verifying merkle proofs, and any computer with the resources needed to execute the Bitcoin script programs from the chain of spends is capable of verifying the chain of custody. This means that almost any modern digital computer can easily perform Simplified Payment Verification by following the steps outlined in this document.

P Baskets: Allowing Future Wallet Basket and Digital Asset Permission Schemes

Ty Everett ([email protected])

Abstract

The BRC-46 architecture for digital assets stored within wallet baskets enables a wide range of use cases. However, it lacks support for more than a rudimentary permission system. Wallets can grant applications blanket access to basketed assets, or deny access entirely, but cannot make insightful decisions based on the specific assets stored, their output scripts, or the tokenized value they represent. To support the future development of new permission schemes covering fungible and non-fungible digital assets within wallets, we propose reserving certain basket identifiers to prevent their use by applications and ensure compatibility with future standards.

Motivation

The motivation for this proposal is to future-proof the architecture by enabling the seamless integration of new permission schemes applicable to assets stored in or retrieved from wallet-managed UTXO baskets. By specifying reserved identifiers, we can ensure that new security and permission paradigms can be implemented without conflicts or unintended behavior.

Specification

To accommodate future basket permission schemes, wallets must reject any operation requests made under basket IDs beginning with p (a lowercase “p” followed by a space).

Future Scheme Identifiers

Future permission schemes must define their ID formats, as follows:

  • The scheme IDs cannot contain spaces.

  • The basket IDs must start with p , followed by the scheme ID, a space, and the rest of the basket identifier.

Example Format

A basket ID such as p dollarToken xxxxx could represent a specific token type (e.g., tokenized dollars), where:

  • p designates an alternative permission scheme.

  • dollarToken identifies the permission scheme.

  • xxxxx forms the basket ID under the alternative scheme.

Basket ID Parsing and Rules

Wallets must differentiate between standard and alternative permission schemes by recognizing the p prefix followed by a distinct, space-free scheme ID. To ensure unambiguous parsing.

Upon recognizing a basket ID structured as p <scheme ID> <rest of the ID>, wallets may apply the specific rules defined by the scheme associated with the scheme ID. These rules could define:

  • Constraints based on specific locking scripts or script templates of UTXOs.

  • The conditions under which operations can be executed.

  • Mechanisms for allowing applications to access only a certain set number of only a specific asset type, according to the rules of some tokenization protocol, overlay service or script template.

  • Specific counterparty requirements and other customizable permission attributes.

Reserved Structure

To maintain clarity and prevent conflicts:

  • Basket IDs beginning with p must be reserved for future use.

  • Wallets must reject operations involving such IDs unless they explicitly support the scheme ID.

  • A space must immediately follow the scheme ID to separate it from other elements.

Extensibility Beyond Current Paradigms

This specification allows future permission schemes to extend beyond current models (e.g. paradigms), enabling flexible and innovative wallet permissions that evolve with user and application needs.

For example, a wallet could allow access to a maximum of 10 dollars of tokenized fiat money per month within an application.

Conclusion

By reserving basket IDs starting with p and specifying rules for future permission schemes,this specification ensures forward compatibility and robust wallet permission functionalities. It enables seamless integration of new schemes without disrupting existing applications or introducing parsing ambiguities.

Banana-Powered Bitcoin Wallet Control Protocol

Jane Doe ([email protected])

Abstract

This proposal introduces an absurd, humorously impractical method for controlling embedded Bitcoin wallets in web-based applications using the power of bananas.

The Abstract section should concisely describe your proposal at a high-level.

Motivation

The purpose of this proposal is to provide a lighthearted example of how to create a standard that adheres to the BRC format while sparking laughter and enjoyment among readers.

The Motivation section should let people know the context for your proposal, and why it was written.

Specification

  1. Wallets must be embedded within a real banana fruit, using cutting-edge bio-organic engineering techniques.

  2. Web-based applications must communicate with the banana-embedded wallet using a Banana Communication Protocol (BCP) involving a series of gentle squeezes.

  3. Squeezes will be translated into binary code, with a short squeeze representing '0' and a long squeeze representing '1'.

The Specification section of your proposal should stipulate all information needed to implement the standard, and make up the bulk of the document. Generally, people should be able to create a compatible implementation with only the specification.

Implementations

  1. Wallet developers must carefully select the finest bananas available, ensuring they are both ripe and durable.

  2. A custom JavaScript library, BananaJS, must be developed for web-based applications to interact with the wallet using the BCP.

  3. Wallet applications must include a sophisticated squeeze detection system to ensure accurate communication.

  4. Wallet developers must implement a "peel screech" alarm system for added security.

The Implementations section should contain information about places where the standard is implemented, or examples of its implementation.

References

  • 1: Doe, J. (2023). Banana-Powered Bitcoin Wallet Control Protocol: A Humorous Guide. Bananaverse Press.

  • 2: Smith, T. (2022). The Art of Banana Communication (Volume IV): Avoiding Single Points of Failure in Banana Communications. FruitTech Publishing.

The References section should contain any footnotes used throughout the document.

Pay to Push Drop

Ty Everett ([email protected])

Abstract

This standard provides a script template that enables data-rich tokens on the Bitcoin SV blockchain, while still allowing for the representation of transfers of ownership. By pushing arbitrary data into stack elements and subsequently dropping them, followed by adding a simple P2PK lock, this script template allows for the creation of tokens with metadata, which can be exchanged on overlay networks. This standard facilitates improved scalability by representing tokens as UTXOs, which can be easily modeled and used in graph structures.

Motivation

The need for this standard arises from the growing demand for data-rich tokens in the ecosystem. Current tokenization methods such as OP_RETURN lack output spendability and representation of ownership, making them unsuitable for many use cases. This standard allows developers to push arbitrary data onto the stack, while still enabling ownership transfer with a simple P2PK lock. This feature facilitates improved scalability by representing tokens as UTXOs, which can be more easily modeled and used in graph structures. Use-cases for these tokens are numerous, ranging from deeds to cars to metadata-rich digital assets. While it does not purport to solve every use-case, such as those requiring complicated spending constraints, this standard is a crucial step in the direction of enabling more sophisticated data-rich tokenization on the Bitcoin network.

Specification

We specify that output scripts must first push data onto the stack, followed by using OP_DROP and OP_2DROP to drop the pushed data. Next, the public key of the owner of the token is pushed, followed by OP_CHECKSIG. The unlocking script comprises a digital signature from the owner's public key, which facilitates spending of the token. Each token output must contain at least one satoshi. This standard does not define specific forms of tokens or specific requirements for higher-order overlays with validation rules for their transfer and conveyance.

Example Output Script:

The following is an example output script for a token as defined by this standard:

Implementations

This script template has been implemented within the .

How it Works

This script template enables tokenization on the Bitcoin SV blockchain by providing a simple and effective way to create data-rich tokens that are still spendable and locked to their owners. This is achieved by pushing arbitrary data onto the stack, dropping it with OP_DROP or OP_2DROP, and then adding a simple P2PK lock with a public key and OP_CHECKSIG.

When a token is created using this template, it is represented as an unspent transaction output (UTXO) that contains at least one satoshi. This UTXO can then be transferred to another user by creating a transaction that spends the UTXO and includes the owner's digital signature in the unlocking script.

The template facilitates tokenization by allowing developers to specify any number of stack elements with arbitrary data, representing tokens on overlays, while still enabling spending and ownership with simple locks. This makes it easier to model and use tokens in graph structures, improving scalability and enabling a wide range of use-cases.

Simplified Payment Verification

Abstract

Defining Simplified Payment Verification (SPV) without external reference for sake of clarity.

Motivation

Token Exchange Protocol for UTXO-based Overlay Networks

Ty Everett ([email protected])

Abstract

We propose a peer-to-peer token exchange protocol under which two parties can securely exchange digital tokens (assets) within Bitcoin SV's BRC-22 UTXO-based Overlay Networks.

There is no BRC-20

Ty Everett ([email protected])

Abstract

This document serves to clarify that there is no BRC-20 standard for tokenization on Bitcoin SV. While Ethereum has the ERC-20 standard for account-based tokens, there is no equivalent for UTXO-based systems such as Bitcoin SV. In order to avoid confusion and prevent people from conflating ERC-20 with BRC-20, it is necessary to clarify that BRC-20 does not exist on Bitcoin SV. Instead, proposals for tokenization should be judged on their own merits. Being associated with ERC-20 will not make any specific tokenization proposal better, and there is not a desire to confer greater legitimacy to one proposal or another.

Merkle proof standardised format

Abstract

This BRC serves as a reference point for the TSC Merkle Proof Standardized Format. It is identified as BRC-10 and is used to avoid ambiguity in referring to the TSC standard, just like other proposals like (which revise or extend this proposal) are referenced by their BRC numbers.

Private Overlays with P2PKH Transactions

Ty Everett ([email protected])

Abstract

In BRC-22 overlay networks, various forms of state tracking for UTXOs can be incorporated. Servers can track UTXOs according to many criteria, enabling many use-cases. There is no fundamental requirement that a server relies on strictly on-chain data for these operations. In this document, we explore the use of off-chain secrets and offset values, enabling private overlay networks to be tracked among transactions that, on the surface, appear only to be normal P2PKH spends. Various models will be explored, from overlay network secrets to data linkages revealed off-chain. All of these methodologies rely on the isomorphic properties of the curve, enabling the owners of the UTXOs to retain spendability rights even when the P2PKH outputs also contain other information stored within offsets from the root key. This information is used to make on-chain record of private, off-chain data, which can later be revealed.

Motivation

The motivation behind this protocol is the need for an efficient and secure mechanism to exchange different types of tokenized assets on top of overlay networks between two parties in the BSV ecosystem.

Specification

The protocol is initiated when two parties, Alice and Bob, desire to conduct an asset exchange. It assumes that both parties are online. We specify this protocol conceptually, by example:

  1. Offer Initiation: Alice wants to sell 5 apples for 3 USD. She creates a new transaction moving her 5 apples into a new output. This output includes her exchange request, peer-to-peer contact information (such as BRC-33), and the asset ID for the asset she would like to exchange, reflected in a new transaction on the overlay network.

  2. Revocation by the Initiator: If Alice decides to cancel her proposition, she can spend the offer output and move her apples back, retracting the offer.

  3. Offer Acceptance: Bob is looking to purchase 5 apples for his 3 USD. He sees Alice's offer, verifying her offered UTXO(s) are registered on the overlay. Bob creates a new transaction, conditionally signing his USD over to Alice using SIGHASH_SINGLE. He ensures the signature is only valid over all the inputs from both Alice and Bob. The single output which he signs pays himself the 5 apples from Alice's inputs.

  4. Offer Presentation: Bob contacts Alice, identifies himself and shares the transaction and signature with her.

  5. Verification: Alice verifies the information and conducts due diligence to confirm Bob's outpoints on the overlay network. She verifies the signature and the validity of the transaction. If she decides not to proceed, she can simply do nothing or send Bob a rejection message.

  6. Transaction Settlement: Alice responds by signing her inputs with a SIGHASH_ALL signature, spending her inputs, and adding an output that pays her Bob's 3 USD. She adds her signature to the transaction, and broadcasts it to Bob and the overlay network. Once her transaction reaches the overlay network, Alice now possesses Bob's 3 USD and Bob is the owner of Alice's 5 apples.

Implementation

This Token Exchange Protocol can be implemented on any UTXO-based overlay network adhering to BRC-59, BRC-45, BRC-22 and BRC-24. This protocol has security built-in, stipulating both SIGHASH type usage and broadcasting and topical membership verification methods.

Future work

In general, overlay network recovery mechanisms for uncooperative participant handling (non-registration or improper broadcast of transactions) need to be defined as part of future specifications. Further tooling and guidance for developers would expand adoption.

Motivation

As the Bitcoin ecosystem continues to mature and grow, there is an increasing desire to create standards for tokenization. However, it is important to recognize that the architecture of Bitcoin is fundamentally different from that of Ethereum. While Ethereum is an account-based system, Bitcoin is a UTXO-based system. This means that there is no direct equivalent for something like ERC-20, which defines account-based tokens on top of Ethereum. The goal of this document is to prevent unnecessary confusion.

Arguments

  • UTXO-based systems are fundamentally different from account-based systems. While Ethereum has the ERC-20 standard for account-based tokens, there is no equivalent for UTXO-based systems such as Bitcoin. Tokenization will necessarily require a different approach, one which should not be conflated.

  • Avoiding confusion is essential. If there were a BRC-20 standard for Bitcoin SV, it would likely be confused with the ERC-20 standard on Ethereum. This could lead to a lack of clarity and understanding among developers and users, which could ultimately harm the growth and adoption of tokenization in both Bitcoin and Ethereum.

  • Proposals for tokenization should be judged on their own merits. The absence of a BRC-20 standard on Bitcoin SV does not mean that tokenization is not possible. Instead, proposals for tokenization should be evaluated based on their own technical merits and practical considerations. A proposal called BRC-20 will not be better on account of its name.

In summary, there is no BRC-20 standard for tokenization on Bitcoin SV. While there may be a desire to create such a standard, it is important to recognize that the architecture of Bitcoin is fundamentally different from that of Ethereum. Instead of trying to emulate the ERC-20 standard, proposals for tokenization should be evaluated based on their own technical merits and practical considerations. This approach will ultimately lead to a more mature and professional ecosystem for tokenization.

As with any other BRC, tokenization proposals will be assigned sequential numbering.

Use Case #1 — Network Access Secrets

In the first use-case, a user sends a transaction to an overlay. The transaction pays some Bitcoins to a P2PKH address. The user reveals the public key to the overlay node at time of transaction submision. The user has computed the pblic key used as follows:

  • Take off-chain data (d) and hash it to get h

  • Add the hash to the actual recipient key to obtain the final public key

Now the user can also reveal to the overlay node the value for d which produced h, and can identify the party who is receiving it.

Ensure that all signatures on provided mAPI responses are valid
  • Ensure that all specified minerID public keys have endorsed all mAPI responses

  • Ensure that, if only confirmed inputs were allowed, every specified input transaction is directly proven with an SPV proof rather than relying on a chain of mAPI responses

  • Ensure that the transaction is valid according to the rules of Bitcoin (sum of input amounts is greater than or equal to the sum of output amounts)

  • Ensure that the lock time of the transaction is as requested in the invoice

  • Ensure that, if the lock time is in the future, all sequence numbers are UINT_MAX, unless you are working with an application that supports continuously-updating payment channel transactions and expect to get another updated transaction later

  • Ensure that evaluating the locking scripts from the input transactions and then the unlocking scripts provided in each input is successful, thus ensuring that all inputs were properly spent

  • Ensure that the transaction was properly signed

  • Ensure that the transaction contains the output scripts and amounts that were requested in the invoice

  • Ensure that the transaction pays a sufficient fee according to the rules of the fee model you are using

  • BRC-8
    BRC-8
    BRC-46
    BRC-46
    BRC-73
    To ensure wallet security, any unauthorized squeezes will cause the banana to emit a loud, defensive "peel screech" to deter potential attackers.
  • Wallets will be recharged by leaving them in direct sunlight for a minimum of 2 hours per day.

  • The protocol must support a minimum of 2 bananas connected simultaneously to avoid a single point of failure2.

  • Web-based applications must visually display the connection and energy status of each banana wallet.

  • 1
    Motivation

    To avoid ambiguity in referring to the TSC Merkle Proof Standardized Format, it is important to have a specific identifier. The use of BRC-10 as a reference point allows for clear and unambiguous communication among developers and the community. The BRC-10 designation is similar to other proposals, such as BRC-32, which are also referenced by their BRC numbers.

    Specification

    You can read the TSC standard on the website.

    Discussion

    As with any other BRC, feel free to open issues in the BRC repository that discuss extensions of BRC-10.

    BRC-11

    Overlay Network Transaction History Tracking

    Ty Everett ([email protected])

    Abstract

    This document proposes a solution for tracking transaction histories within UTXO-based overlay networks by extending the BRC-22 standard to include transaction inputs and the BRC-24 standard's query responses to include such data in extended BRC-36 input envelopes. By associating previous transaction inputs with topic-specific UTXOs and facilitating history traversal, it allows network participants to access a more complete record of UTXO histories. This standard outlines the parameters and steps needed to capture, maintain, and access historical transactional data in overlay networks.

    Motivation

    BRC-22 successfully enables the tracking and synchronization of UTXOs across various topics in overlay networks, yet it does not accommodate the preservation of UTXO histories which can hold valuable network data. Transaction histories are key to understanding the full lifecycle of UTXOs, acting as a crucial component for certain applications in areas like network analysis and auditability. The absence of a history tracking standard leads to information gaps, preventing a comprehensive understanding of network state changes. This document presents a solution to this problem by providing a clear and standardized mechanism for maintaining and accessing transaction histories in UTXO-based overlay networks.

    Specification

    We introduce extensions to the BRC-22 and BRC-24 standards to encapsulate the input history of network transactions. Topic managers in BRC-22 can now prescribe which transaction inputs should be conserved and linked with the admitted transaction outputs, designating inputs that are pertinent for tracking. The BRC-24 standard, meanwhile, is adjusted to support the retrieval of past renditions of UTXOs.

    Changes to the BRC-22 Standard

    Topic managers in overlay networks now perform the following additional steps:

    • Verify the inputs from the transaction tagged with their topic labels to determine their relevance.

    • Provide a return value back to the Confederacy node directing it to retain these relevant transaction inputs, so that the node can maintain them alongside admitted transaction outputs for the specified topic.

    • Relative location metadata and other associated data should be stored by the Confederacy node along with these inputs, enabling efficient topic-specific historical data retrieval.

    Changes to the BRC-24 Standard

    The lookup services specified under BRC-24 can now:

    • Accept queries for the previous renditions of specific UTXOs (formats for these queries depend on the specific lookup service).

    • Assemble and return a responsive list comprising of the series of transactions that involve the queried UTXOs along their states across the network's history.

    • Extend the BRC-36 envelope return format, including transactions as inputs when they contribute to the history of the queried UTXOs.

    Implementation

    Developers should adapt their existing BRC-22 based systems to collect and preserve pertinent transaction inputs when admitting new transaction outputs. Lookup services following the BRC-24 standard must be updated to handle queries for prior renditions of UTXOs and effectively traverse transactional histories, extending their BRC-36 envelope returns to incorporate key transaction input data for the queried UTXOs. By adhering to the changes specified in this document, network participants can ensure interoperability, efficient data access and complete historical tracking of UTXOs across overlay networks.

    Diverse Facilitators and URL Protocols for SHIP and SLAP Overlay Advertisements

    Ty Everett ([email protected])

    Currently, there are only HTTPS URLs within SHIP and SLAP advertisements

    This https: scheme indicates that, according to pre-defined rules (like headers and the /submit or /lookup paths), submission or lookups are facilitated over the HTTPS protocol.

    However, sometimes we want to do things like:

    • Authenticate users before accepting transactions or facilitating lookup

    • Charge a payment for transaction submission, or pay the sender if a transaction is accepted

    • Charge a payment for lookup queries

    • Submit private or off-chain values alongside a transaction

    • Submit non-final transactions that deal with interim states

    • Facilitate real-time lookups with WebSocket or based on live / non-final transactions

    • Advertise certain IPv6 capabilities and bridges

    • Advertise non-HTTPS or non-internet communications systems like radio / JS8 Call

    In these scenarios, other schemes can be used within the "protocol" portion of the URL.

    For example, current SHIP/SLAP only contemplates URL schemes like https://example.com.

    However, a new URL might be something like:

    SHIP https+bsvauth+smf://example.com (HTTPS with BSV Auth and Service Monetization Framework enabled)

    SHIP https+bsvauth+scrypt-offchain://example.com (HTTPS with BSV Auth and sCrypt off-chain values for transaction submission)

    SHIP https+rtt://example.com (HTTPS with real-time transacting support, e.g. non-finals accepted)

    SLAP wss://example.com (real-time event-listening live web-socket lookup response streaming)

    SLAP js8c+bsvauth+smf:?lat=40&long=130&freq=40meters&radius=1000miles (lookup is advertised using JS8 Call protocol at a given set of GPS coordinates, a given frequency and radius, with BSV Auth and Service Monetization Framework enabled.

    These new SHIP and SLAP schemes allow for the advertisement of new Overlay Services that have more advanced capabilities, including real-time updates from lookup services, non-final transaction submission, mutual authentication, payment, off-chain / private value submission, non-HTTP transport mechanisms, and much more.

    Compared to plain HTTPS, they make a significant improvement. Facilitators for each of these custom "protocol" fields in the advertised SHIP/SLAP URLs can be implemented into standard libraries, the associated lookup services can be updated to facilitate querying by them, and new default SLAP trackers can be added so that users are able to stay connected in more ways than one.

    PushDrop JavaScript library
    <arbitrary data> <arbitrary data> <arbitrary data> OP_DROP OP_2DROP <public key> OP_CHECKSIG
    Bitcoin's security model is built upon the idea of widespread distribution of blockheaders, where applications run SPV. This ensures that anyone can easily identify any attempt to commit fraud using tampered data. To ascertain the validity of data received from peers, any client on the network can employ Simplified Payment Verification. We require a clear and definitive reference that outlines the specific criteria. This way, implementations with variations in finer details can always refer back to the fundamental principles that remain constant over time.

    Certain checks that are unique to each implementation, such as detecting encoding errors or malformed transactions, are not covered here. Although these checks are essential, they vary according to the implementation and are not included in the definitive list presented below.

    Verification Steps

    Checks made on receipt of a transaction from a counterparty:

    1. Script evaluation of each unlocking script results in TRUE.

    2. The sum of the satoshis-in must be greater than the sum of the satoshis-out.

    3. Each input must be associated with a Merkle path to a block.

    4. nLocktime, and nSequence of each input are set to the expected values.

    Script Evaluation

    Often this is referred to as "check the signatures" which is indeed usually the case but it is possible to have transactions which do not require signatures so for the sake of technical exactitude - running script evaluation is really what is happening here. The interpretation requires that each input unlocking script is concatenated with the previous locking script and the interpreter runs given that input. The result should be a truthy value left on the stack after execution, otherwise the predicate has failed and the utxo has not been unlocked.

    Check Fees

    Each input is a pointer to a previous output, each output has a satoshi value. Therefore to calculate the input satoshis we must have details of the previous transactions from which we are spending utxos. We use this information to determine the fees paid by the transaction. We compare these fees with the size of the Tx in bytes to arrive at a rate: sats/byte. The acceptable rate is well known, various services publish this information. At the time of publishing this rate is equivalent to 1 satoshi for a standard transaction, therefore the check could simply be:

    Merkle Path

    If all inputs come from Transactions which are mined in a block, then the associated Merkle path is one which leads that txid to a Merkle root. If some inputs are not in a block then we must include previous transaction data, and follow the history of all inputs until we arrive at a point where all inputs are associated with previous inputs which appear in a mined block. Various formats will handle this differently, but the universal rule is that SPV requires that we prove that all inputs come from legitimate transactions.

    In a long chain of transactions conducted while not connected to the internet, each new transaction is appended to the end of the SPV data such that all prior transaction ancestry is propagated to all counterparties, until they are broadcasted. So we would expect large SPV data payloads only when many transactions happen offline, which in today's age will be extremely rare.

    all inputs lead to a block

    Locktime and Sequence

    The nLocktime default is 00000000, and nSequence default is FFFFFFFF. If these values are not default then there is a naunced condition to the transaction which is explained here.

    Input Redemption

    Ty Everett ([email protected])

    Abstract

    We define a mechanism by which BRC-1 applications can denote UTXOs to be unlocked and redeemed by wallets as part of new Bitcoin transactions. We extend the message format defined by BRC-1 with information about the inputs requested by the application, including all information needed for a wallet to check the veracity of any inputs being redeemed.

    Motivation

    defines a mechanism for an application to request the creation of a Bitcoin transaction by a wallet, but it is incomplete without a way for applications to consume and use tokens that previously existed. Allowing applications to unlock and redeem inputs as part of their transactions also facilitates their ability to update, extend or delete assets that are tokenized within Bitcoin UTXOs.

    Specification

    We extend the Transaction Creation Request message with an additional field, the inputs field. This is an object whose keys are the TXIDs of transactions that contain outputs which are to be spent as part of this transaction, and whose values comprise extended transaction envelopes.

    In addition to the normal envelope fields, we specify that these input envelopes contain an additional field called outputsToRedeem, which is an array of objects. Each of the objects comprises an output from the subject transaction that is to be redeemed and used as input to the transaction being requested by the application.

    We specify that each of the objects in the array contains index and unlockingScript. The index value is an integer that denotes which output to redeem from the transaction, and the unlockingScript comprises a hex-formatted input script.

    We further specify that each of the elements in each of the outputsToRedeem arrays may contain an additional spendingDescription string that describes the redemption of the tokens being used.

    Example

    Here is an example of a Transaction Creation Request object that contains an input:

    Implementations

    This functionality has been implemented as part of the , in the createAction function.

    Transaction Labels and List Actions

    • Ty Everett ([email protected])

    Abstract

    BRC-65 extends the functionality of BRC-56 by introducing the ability to label Bitcoin transactions when they are created using the BRC-1 Transaction Creation Request. This extension allows applications to organize and categorize transactions for different purposes. BRC-65 also introduces the capability to list labeled transactions, providing applications with an easy way to retrieve specific sets of transactions based on their labels. This standardization improves interoperability between wallets and applications and enhances the user experience by enabling the display of transaction lists relevant to specific categories or actions.

    Motivation

    The motivation behind BRC-65 is to enhance the functionality of the Bitcoin wallet messaging layer defined in BRC-56 by introducing the ability to label transactions. This functionality allows applications to categorize and organize transactions based on specific criteria. By labeling transactions, applications can easily retrieve and display transaction lists that are relevant to specific actions or categories. This simplifies the user experience and enables users to quickly find, review, and analyze specific sets of transactions.

    By defining a standard mechanism for labeling transactions and listing labeled transactions, BRC-65 promotes interoperability between wallets and applications. With this standardization, applications can expect consistent behavior across different wallets, making it easier for developers to create Bitcoin-powered applications without having to build custom wallet functionality. Furthermore, users can switch between wallets seamlessly without losing access to their labeled transactions.

    Specification

    BRC-65 extends the functionality of BRC-56 by introducing the concept of transaction labels and the ability to list labeled transactions. This extension adds two new features to the wallet-to-application messaging layer: labeling transactions at the point of creation and retrieving labeled transactions.

    Transaction Labels

    The labels field is introduced as an optional parameter next to the outputs array and description of the BRC-1 Transaction Creation Request in BRC-56. This field allows applications to label transactions. Each label must be no longer than 300 characters and can only contain letters, numbers, and underscores.

    The updated Transaction Creation Request with the labels field is as follows:

    In this example, the application is creating a transaction with the labels "payment" and "personal". These labels can be used to categorize and organize the transaction in a way that is meaningful to the application.

    List Actions

    BRC-65 introduces the listActions message (the Actions List Request) to retrieve a list of Bitcoin transactions based on their labels. The Actions List Request message takes the following parameters:

    Field
    Description

    The Actions List Request message retrieves Bitcoin transactions that have been labeled with the specified label. The skip parameter allows applications to retrieve a subset of transactions by skipping a certain number of transactions from the beginning of the list. The limit parameter defines the maximum number of transactions to return. If skip and limit are not provided, the request will return all transactions with the specified label.

    The Actions List Response comprises an array of BRC-8 Transaction Envelopes as defined in BRC-56, representing the labeled transactions, along with a totalActions field denoting the total number of transactions with the specified label.

    An example Actions List Request message with the label "payment" and a limit of 10 transactions is as follows:

    The corresponding Actions List Response would contain an array of BRC-8 Transaction Envelopes as well as the totalActions field:

    In this example, the actions list response includes an array of BRC-8 Transaction Envelopes representing the labeled transactions with the label "payment". The totalActions field indicates that there are a total of 42 transactions with the "payment" label.

    Implementations

    Implementations of this specification will need to extend the existing wallet software in order to support the labeling of transactions and the listing of labeled transactions. Wallets will need to ensure that they can create transactions with labeled outputs and store the labels for future retrieval. Applications will need to handle the labeling of transactions and make use of the Actions List Request to retrieve labeled transactions.

    Some existing implementations of BRC-56 may already support the labeling and listing of transactions, while others may need to update their software to include this additional functionality. The Babbage MetaNet Client, for example, has already implemented the Transaction Labels and List Actions functionality.

    Definition of UTXOs as Bitcoin Tokens

    Ty Everett ([email protected])

    Abstract:

    This document proposes an examination of Unspent Transaction Outputs (UTXOs) as the central framework of tokenization in Bitcoin, justifying their usage based on their inherent simplicity, efficiency, and secure transfer processes. Through UTXOs, Bitcoin allows the delineation of rules governing the transfer of valuable tokens via scripting. In contrast to alternative tokenization proposals, UTXOs render the need for comprehensive, trusted indexing and chain scanning systems obsolete. Instead, transaction parties require only to validate transactions pertinent to them, employing miners to mitigate double-spend attempts, thus achieving tokenization of assets at scale.

    Background:

    Tokenization, in the realm of digital assets, represents the process of substituting valuable, real-world assets with digital tokens on a blockchain. Within the context of Bitcoin, tokenization predominantly revolves around Unspent Transaction Outputs (UTXOs).

    Unspent Transaction Outputs (UTXOs) are remnants of Bitcoin transactions yet to be spent or used as inputs for newer transactions. Each UTXO in Bitcoin can be seen as a distinct token. Unlike other tokenization methods, UTXOs are directly transferred from sender to recipient, the legitimacy of which can be independently verified, thus significantly reducing computational and time complexities.

    Scripts in Bitcoin define the conditions under which UTXOs can be spent. These conditions form the essence of token transfer rules, ensuring secure transactions of digital tokens.

    Simplified Payment Verification (SPV) is a method used in Bitcoin for lightweight clients to verify transactions without requiring the entire blockchain's download. The process for SPV enables recipients to verify transfers quickly.

    Argument: Benefits of UTXOs as the Fundamental Unit of Tokenization:

    UTXOs offer a unique advantage as the foundational unit of tokenization in Bitcoin due to their inherent characteristics and the robustness they bring to the transaction system:

    1. Decentralization and Trust Minimization: With UTXOs, parties need only to validate transactions that concern them, eliminating the necessity for a trusted intermediary to index and scan every transaction on the blockchain. This process enhances the decentralized nature of Bitcoin and minimizes trust requirements.

    2. Scalability: By treating UTXOs as the base unit of tokenization, we can facilitate efficient asset tokenization at scale. With direct transfers, the UTXO model bypasses complex indexing systems, thus reducing computational overhead and increasing transaction speed.

    3. Double-Spend Protection: Miners play an integral role in UTXO transactions by preventing double-spending. As each UTXO can only be spent once, miners verify and confirm that no UTXO is duplicated or spent twice, preserving the security of the blockchain.

    In summary, the UTXO model provides an efficient and scalable framework for tokenization in Bitcoin, while upholding the principles of decentralization and trust minimization. Its distinctive attributes such as direct transfer, double-spend prevention, and simplified verification lend themselves to a secure and streamlined tokenization process, validating the assertion that UTXOs are the fundamental unit of tokenization in Bitcoin.

    Pay to False Return

    Abstract

    The OP_FALSE OP_RETURN script template is a method for storing data on the Bitcoin SV blockchain. It creates a non-spendable output and appends the desired data to the end of the script for storage. This standard aims to define the rules and best practices for using this script template.

    Motivation

    The low transaction fees and high capacity of the Bitcoin SV network make it an attractive option for storing data on the blockchain. The OP_FALSE OP_RETURN script template is a widely used method for achieving this goal due to its simplicity and ease-of-use.

    Specification

    To use the OP_FALSE OP_RETURN script template, an output must be included in a Bitcoin transaction with a locking script comprising OP_FALSE followed by OP_RETURN, followed by the data to store in the script. The data can be pushed into one or multiple stack elements after the OP_RETURN opcode.

    For example:

    Implementations

    Several implementations and protocols make use of the OP_RETURN script template, including the and .

    Limitations

    The main limitation of using OP_FALSE OP_RETURN is the non-spendability of these outputs and their ability to be pruned by miners. They are records rather than tokens. Artefacts predominantly as a proof of existence of data at a certain time - timestamped by the Bitcoin system as a hash with a merkleproof to a block, even if miners themselves prune the data.

    Output Basket Removal and Certificate Deletion

    • Ty Everett ([email protected])

    Abstract

    This BRC extends by adding the ability to remove specific outputs from a basket and delete digital certificates that are no longer required. Applications can request that a wallet remove outputs from a basket by providing the transaction ID (txid) and the output index (vout

    BEEF V2 Txid Only Extension

    Tone Engel ([email protected])

    Abstract

    The BEEF serialization format (as defined in ) is essentially two things:

    1. An array of mined transaction proof validation data (BUMPS )

    Graph Aware Sync Protocol

    Ragnar Friedman

    Abstract

    GASP is designed to synchronize transaction data between two parties in a blockchain environment. It ensures the legitimacy and completeness of transaction data using a recursive reconciliation method.

    Raw Transaction Format

    Abstract

    This BRC specifies the format used for raw hex Bitcoin transactions, which are a widely-used way of representing Bitcoin transactions on the network. The specification includes details on the layout and various fields within Bitcoin transactions.

    Motivation

    Bitcoin Script Binary, Hex and ASM Formats

    Ty Everett ([email protected])

    Abstract

    Bitcoin uses scripts to control transactions, and three of the most common ways to represent a script are binary, hexadecimal, and ASM. This standard aims to provide a detailed description of these formats to facilitate their use in BSV transactions.

    Universal Hash Resolution Protocol

    Ty Everett ([email protected])

    Abstract

    This document describes the Universal Hash Resolution Protocol (UHRP), a standard framework for content availability advertisement implemented with a UTXO-based overlay network. UHRP enables content hosts to advertise the availability of a particular file by creating a UTXO-based advertisement token, which is then submitted to the UHRP overlay and tracked by overlay network nodes. UHRP provides resilience to single points of failure and ensures content accessibility even if one host is offline, because multiple entities can be paid by content providers to keep content available.

    Paymail BEEF Transaction

    Deggen ([email protected])

    Abstract

    We specify a paymail capability extension which supports the passing of BEEF Transactions between hosts. The procedure for service discovery and requesting outputs is not detailed, rather this proposal contains only a recommendation to replace hex data with hex data.

    Standardized Naming Conventions for BRC-22 Topic Managers and BRC-24 Lookup Services

    Ty Everett ([email protected])

    Abstract

    This document proposes standardized naming conventions for topic managers in BRC-22 and lookup services in BRC-24 to ensure clarity, interoperability, and uniformity across different implementations. The goal is to provide consistent and easily understandable names that facilitate efficient communication and integration between overlay network nodes and services within the BSV ecosystem.

    Bare Multi-Signature

    Abstract

    This BRC standard outlines the implementation and use of bare multi-signature (multi-sig) transaction output scripts within the Bitcoin SV digital asset ecosystem. By employing OP_MULTISIG opcodes directly, this approach offers simplicity and ease of implementation while providing enhanced security and access control for transactions. However, it also highlights the trade-offs in terms of privacy for participants. The standard comprises a motivation section, detailing the benefits of bare multi-sig transactions; a specification section, explaining the structure of these transactions; an example section, demonstrating a 2-of-3 multi-signature locking and unlocking script; and a "how it works" section, delving into the fundamentals of bare multi-sig transactions and their role in the Bitcoin SV ecosystem.

    Pay to True Return

    Ty Everett ([email protected])

    Abstract

    In one view of Bitcoin, only spendable output scripts with satoshis attached constitute valid Bitcoin tokens, because Bitcoin tokens are UTXOs. Since traditional scripts are not compatible with this view, we propose a methodology for creating OP_RETURN scripts that are spendable and contain satoshis. This provides a way for software to automatically convert non-compliant OP_RETURNs into proper Bitcoin tokens while encouraging developers to consider the spendability constraints that govern their tokens.

    Defining a Scalable IPv6 Multicast Protocol for Blockchain Transaction Broadcast and Update Delivery

    Ty Everett ([email protected])

    Abstract

    This document builds upon the insights of and proposes a scalable, efficient IPv6 multicast protocol specifically designed for the broadcast of blockchain transactions and the delivery of transaction status updates, such as merkle proofs and double-spend attempt notifications. Recognizing the limitations of existing IPv6 multicast protocols, including Multicast Listener Discovery (MLD), this protocol addresses the needs for massive scalability, efficient data delivery, and economic sustainability required by modern blockchain networks. This protocol employs a layered approach using MLDv2 at the edges, multicast Border Gateway Protocol (mBGP) at the core, and introduces an intermediate aggregation/summarization layer to ensure global scalability and efficiency.

    This document is intended for network engineers and architects familiar with IPv6 and multicast technologies but may not have extensive knowledge of blockchain technology. The technical details provided aim to bridge the knowledge gap and foster understanding of the specific network demands and solutions in blockchain operations.

    Admin-reserved and Prohibited Key Derivation Protocols

    Ty Everett ([email protected])

    Abstract

    We define a set of reserved protocol namespaces that can be employed by clients utilizing the invoice numbering scheme to be set aside for administrative and internal use by the client software itself. This enables client software to manage its own internal state without the risk that application software will utilize the same internal protocols.

    sumInputAmounts > sumOutputAmounts

    Bitcoin transactions are the mechanism for transferring custody of bitcoin tokens from one party to another. It is crucial to have a clear and unambiguous specification for their format. The raw hex format is widely-used and understanding its structure is important for developers and other stakeholders in the Bitcoin ecosystem.

    Specification

    A Bitcoin transaction consists of a version number, a locktime value, a list of inputs, and a list of outputs. The format for a raw hex Bitcoin transaction is as follows:

    • Version: 4-byte integer (little-endian)

    • Input Count: variable-length integer

    • Inputs: a list of input objects, where each input object has the following fields:

      • Previous Transaction Hash: 32-byte hash (little-endian)

      • Previous Transaction Output Index: 4-byte integer (little-endian)

      • Script Length: variable-length integer

      • Unlocking Script: variable-length script

      • Sequence Number: 4-byte integer (little-endian)

    • Output Count: variable-length integer

    • Outputs: a list of output objects, where each output object has the following fields:

      • Value: 8-byte integer (little-endian)

      • Script Length: variable-length integer

      • Locking Script: variable-length script

    • Locktime: 4-byte integer (little-endian)

    Variable Integers

    The variable-length integer is a compact representation of an integer value. The first byte of the integer determines the format of the integer:

    • If the first byte is less than 0xfd, then the integer is that byte value.

    • If the first byte is 0xfd, then the integer is the next two bytes in little-endian format.

    • If the first byte is 0xfe, then the integer is the next four bytes in little-endian format.

    • If the first byte is 0xff, then the integer is the next eight bytes in little-endian format.

    The script fields in the input and output objects are interpreted as bytecode for a Bitcoin Script, which is a stack-based language used to define spending conditions for bitcoin.

    The transaction hash (referred to as the "TXID") is calculated by taking the double-SHA256 hash of the entire transaction. This hash is used as a unique identifier for the transaction on the Bitcoin network.

    Motivation

    Currently, there is no unified naming convention for topic managers and lookup services utilized in BRC-22 and BRC-24 standards. This absence can lead to confusion and errors in integration.

    Specification

    Naming Consistency Across Nodes

    Network services that deal with the same transactions and protocols should negotiate to agree upon a common name for their topic managers and lookup services. This ensures resiliency, in that network users are able to access the same services at known locations across nodes, even if one node in an overlay network goes down. It also aids node operators in synchronizing relevant transactions with one another.

    General Guidelines

    1. Consistency: Names should be consistent across different implementations to avoid ambiguity.

    2. Clarity: Names should be clear and descriptive enough for developers to understand their purpose.

    3. Length: While names should be descriptive, they should also be concise to ensure ease of use in configurations and codebases.

    Master Rules

    1. Only lower-case letters and underscores.

    2. Must not start or end with an underscore.

    3. No consecutive underscores.

    4. No longer than 50 characters.

    Naming Conventions for BRC-22 Topic Managers

    1. Prefix: Use the prefix tm_ to indicate a topic manager.

    2. Topic Identifier: Follow the prefix with a short descriptor of the topic.

    3. Example:

      • tm_uhrp_files

      • tm_tempo_songs

    Naming Conventions for BRC-24 Lookup Services

    1. Prefix: Use the prefix ls_ to denote a lookup service.

    2. Service Identifier: Follow the prefix with a brief descriptor of the lookup service functionality.

    3. Example:

      • ls_uhrp_files

      • ls_tempo_songs_search

    Implementation

    Each overlay network node and service provider must update their naming conventions to comply with the standardized guidelines described in this document. This update involves renaming existing topic managers and lookup services accordingly and ensuring that new implementations follow these standardized conventions.

    By standardizing naming conventions for topic managers and lookup services, we can significantly enhance the clarity, consistency, and interoperability of overlay networks on the BSV blockchain.

    Simplified Verification: The BRC-9 process for SPV enables easy verification of transfers without needing the full blockchain data. In UTXO-based transactions, the recipient can independently validate the transaction, making it efficient and user-friendly.

    BRC-9
    Motivation

    In the digital world, consumers often require access to specific content without regard for the hosting source. Content providers, on the other hand, have a vested interest in maintaining wide availability of their offerings, even during host outages. Existing systems, however, do not provide a standardized and robust means of connecting users to their required files.

    UHRP addresses this by enabling multiple content hosts to advertise the availability of content using UTXOs. Users can seek the content based on its hash, ensuring they connect to the files they need via an overlay network that is resilient to single points of failure. Content providers wishing to ensure consistent availability can pay multiple hosts, so that content remains available even if one host goes down.

    This new paradigm not only streamlines content availability but also enables new hosts to build reputation by demonstrating opportunity cost (for example, by paying higher than normal transaction fees to miners on hosting commitments). Over time, service providers and applications can build a trusted list of UHRP hosts, thereby improving the overall reliability and trustworthiness of the content hosting ecosystem.

    Specification

    A UHRP advertisement token comprises a Bitcoin UTXO with a locking script containing the following components:

    • <public key>: This is the public key associated with the host that is making the advertisement.

    • OP_CHECKSIG: Ensures that if the token becomes spent, a signature was made using the host's private key.

    • Protocol prefix: A protocol prefix pushed onto the stack, with a value of 1UHRPYnMHPuQ5Tgb3AF8JXqwKkmZVy5hG.

    • <address>: The base58 version of the address corresponding to the <public key>.

    • <hash>: The next 32 bytes are the SHA-256 hash of the content being advertised.

    • <url>: The HTTPS URL where the host is advertising that the content is available for download.

    • <expiryTime>: A UTF-8 encoded version of a decimal integer representing the Unix timestamp of the advertisement expiry.

    • <contentLength>: A UTF-8 encoded version of a decimal integer representing the byte length of the content.

    • <signature>: A digital signature over the concatenated fields fields from the host's <public key>.

    Upon creation and submission of an advertisement to a BRC-22 overlay network node for the UHRP topic, the node will track the UTXO and facilitate its lookup via a BRC-24 lookup service with the provider name UHRP. If the token ever becomes spent, the advertisement is canceled. The spending transaction may contain more information justifying the host's revocation (shch as a DMCA notice), but any such stipulation is beyond the scope of this initial document, and left for others to specify later.

    Implementation

    Tools such as NanoSeek (for downloading) and NanoStore-Publisher (for uploading to a NanoStore provider) have been created by the Babbage team. To implement the serialization format, the uhrp-url tool can be used.

    Questions about this initial draft specification should be directed to the author.

    BRC-22

    1. Introduction

    With the increasing volume of transactions in blockchain networks and the need for rapid propagation, traditional methods of transaction broadcast and update delivery are becoming inadequate. MLD, as noted in BRC-80, provides mechanisms for IPv6 hosts to report interest in multicast groups, but does not scale to the needs of global blockchain operations, which involve potentially trillions of multicast groups.

    2. Multicast Protocol Components

    2.1 MLDv2 at the Edges

    MLDv2 allows IPv6 nodes to report not only their interest in specific multicast groups but also to specify interest in blocks of addresses. This capability is crucial for managing the high volume of multicast groups involved in blockchain networks.

    • Local Router Management: Routers at the network edge use MLDv2 to manage local subscriptions efficiently, dynamically handling group memberships as user interests change.

    2.2 mBGP at the Core

    mBGP manages the exchange of multicast routing information between autonomous systems, crucial for the global delivery of multicast traffic.

    • Global Traffic Routing: mBGP ensures that multicast traffic is routed efficiently across different ISPs and backbone networks, based on aggregated routing information that represents the interests of multiple local networks.

    2.3 Aggregation/Summarization Layer

    An intermediate layer that aggregates multicast interests into larger, more manageable groups significantly reduces the complexity and volume of routing information needed at the global level.

    • Regional Aggregation: Dedicated multicast routers or servers summarize the multicast group information from multiple local networks, reducing the granularity of information propagated globally.

    3. Protocol Operation

    3.1 Subscription and Broadcasting

    Nodes subscribe to multicast groups relevant to their interests via MLDv2, which informs local routers of these interests. When transactions are broadcast or updates are sent, they are addressed to specific multicast groups based on transaction attributes such as version numbers and portions of transaction IDs.

    3.2 Routing and Delivery

    • Local Handling: Local routers manage multicast traffic within their networks based on MLDv2 reports.

    • Global Distribution: mBGP is used by ISPs to route traffic globally based on summarized interests from the aggregation layer.

    • Efficiency and Scalability: The aggregation/summarization layer updates mBGP information periodically, balancing the need for real-time accuracy with global routing efficiency.

    4. Economic Incentives and Security

    To ensure the economic sustainability of this multicast architecture, a mechanism for out-of-band payments must be implemented alongside these lower-level routing protocols, allowing nodes to compensate network providers for the data they consume. This payment mechanism should be designed to prevent DoS attacks by making it costly to spam the network with unnecessary subscriptions. MLDv2 subscriptions or mBGP advertisements made without respect to an associated payment must be ignored and dropped.

    • Payment Integration: Implement a secure, blockchain-based payment system for subscription services to ensure that providers of network resources are compensated for their services. This is an area of future work.

    5. Implementation Considerations

    • Security Measures: Implement robust security measures to authenticate and authorize multicast subscriptions to prevent unauthorized and costly subscriptions that have not been paid for.

    • Monitoring and Management: Deploy real-time monitoring tools to manage multicast traffic flows and performance across all layers of the network.

    6. Future Directions and Research

    Further research is needed to refine the aggregation algorithms and to enhance the scalability of the mBGP routing updates. Additionally, exploring the integration of an out-of-band payment mechanism for these multicast communications at scale will be crucial.

    7. Conclusion

    The proposed protocol provides a comprehensive solution for the scalable and efficient distribution of blockchain transaction data across global networks using IPv6 multicast. By leveraging MLDv2 at the edges for dynamic subscription management, mBGP at the core for robust global routing, and an aggregation/summarization layer in between, this protocol addresses the unique challenges posed by the high data volumes and rapid dynamics of modern blockchain networks.

    This document serves as a foundational step towards implementing a robust multicast protocol tailored for blockchain applications, ensuring efficient data dissemination and economic viability.

    BRC-80
    Motivation

    BRC-431 defines an open-ended way to create protocols and systems of interaction within a BRC-422 key derivation architecture. However, client software implementing the BRC-431 invoice numbering scheme needs a way to manage its own internal state, encrypt data and perform administrative tasks like permissions management without interference from applications.

    With this specification, we define a list of namespaces in which applications are never allowed to derive keys, and any client that follows this specification will refuse requests made by applications to perform these operations.

    Specification

    We reserve the following protocol IDs for the administrative and internal use of clients, no matter the security level:

    • Any protocol ID that starts with admin

    References

    • 1: BRC-43: Security Levels, Protocol IDs, Key IDs and Counterparties

    • 2: BRC-42: BSV Key Derivation Scheme (BKDS)

    BRC-43
    BRC-1
    BRC-1
    BRC-8
    BRC-14
    Babbage SDK

    label

    The label to filter the transactions by.

    skip

    The number of transactions to skip before returning results (optional).

    limit

    The maximum number of transactions to return (optional).

    RUN protocol
    Bitcoin OP_RETURN Bytecode (BOB)
    ) along with the name of the basket. Certificates can be deleted by specifying the certifier, serial number, and certificate type. The wallet will authenticate the request and remove the requested output from the basket or delete the specified certificate. If the request is denied or the output or certificate cannot be found, the wallet will respond with an error message.

    Motivation

    Applications need the ability to remove specific outputs from a basket when they are no longer needed, without having to spend them. Furthermore, certificates may need to be deleted when they expire or are no longer relevant. This functionality allows for tokens and certificates to be managed more efficiently within a wallet, improving user experience and reducing clutter.

    Specification

    This BRC introduces two new message types to the BRC-56 messaging layer:

    Output Basket Removal Request

    The Output Basket Removal Request message is sent by an application to request the removal of a specific output from a basket. It contains the following fields:

    Field
    Description

    txid

    The transaction ID of the output to be removed.

    vout

    The output index of the output to be removed.

    basket

    The name of the basket from which the output will be removed.

    The wallet will validate the request and remove the requested output from the specified basket if it exists. If the requested output does not exist or the user denies permission, the wallet will respond with an error.

    Output Basket Removal Response

    The Output Basket Removal Response message is sent by the wallet in response to an Output Basket Removal Request. If the removal was successful, the response will contain a success message. Otherwise, if the request was denied or the output could not be found, an error message will be included.

    Output Basket Removal Error

    If the wallet is unable to fulfill the Output Basket Removal Request for any reason, it will respond with a JSON-formatted Output Basket Removal Error. The fields for the error message are as follows:

    Field
    Description

    status

    This should always be the string "error".

    code

    A machine-readable error code.

    description

    A human-readable description of the error.

    One example of an Output Basket Removal Error is as follows:

    Certificate Deletion Request

    The Certificate Deletion Request message is sent by an application to request the deletion of a specific digital certificate. It contains the following fields:

    Field
    Description

    certifier

    The certifier responsible for the certificate.

    serialNumber

    The serial number of the certificate.

    certificateType

    The type of the certificate to be deleted.

    The wallet will validate the request and delete the specified certificate if it exists. If the certificate does not exist or the user denies permission, the wallet will respond with an error.

    Certificate Deletion Response

    The Certificate Deletion Response message is sent by the wallet in response to a Certificate Deletion Request. If the deletion was successful, the response will contain a success message. Otherwise, if the request was denied or the certificate could not be found, an error message will be included.

    Certificate Deletion Error

    If the wallet is unable to fulfill the Certificate Deletion Request for any reason, it will respond with a JSON-formatted Certificate Deletion Error. The fields for the error message are as follows:

    Field
    Description

    status

    This should always be the string "error".

    code

    A machine-readable error code.

    description

    A human-readable description of the error.

    One example of a Certificate Deletion Error is as follows:

    Implementations

    Implementations of this specification will need to extend the existing implementation of BRC-56 to include the functionality for output basket removal and certificate deletion. The wallet will need to handle incoming request messages, validate them, and perform the specified operations. The application will need to handle the response and error messages accordingly.

    BRC-56
    Motivation

    The use of scripts in Bitcoin SV transactions allows for greater flexibility and customization of transaction rules. To properly utilize these scripts, it is important to understand the different formats they can be written in. This standard aims to provide a clear and detailed description of the binary, hexadecimal, and ASM formats used in BSV scripts to facilitate their use in BSV transactions.

    Specification

    We specify three commonly-used Bitcoin script formats as follows:

    Binary Format

    The binary format is a series of bytes that represent the script. Each opcode in the script is represented by a single byte, with any arguments or data being represented by subsequent bytes. The script is executed sequentially, with each opcode performing a specific action on the stack. Bitcoin script uses reverse polish notation.

    Hexadecimal Format

    The hexadecimal format is a string of hexadecimal digits that represents the binary script. Each byte in the script is represented by two hexadecimal digits. The following is an example of a script in hexadecimal format:

    ASM Format

    Not to be confused with the full BRC-15 Assembly Language.

    The ASM format is a human-readable format that represents the script in a more intuitive way. Each opcode and its arguments are represented by a single string. For example, the following script in ASM format checks that a given public key has signed the transaction:

    SASM Format

    The SASM format is a shortening of the above ASM format which uses lowercase and removes the OP_ prefix from op codes to aid in quick typing and clearer readability. For example, the above ASM script is repeated now in SASM:

    Implementations

    BSV scripts can be written in any of the above formats and included in a transaction as a locking script or an unlocking script. To create a script in binary format, the opcodes can be written in hexadecimal and then converted to binary. To create a script in hexadecimal format, the binary script can be converted to hexadecimal. To create a script in the ASM format, the opcodes and arguments can be written as a string in the appropriate format.

    There are various libraries and tools available for creating and working with BSV scripts in these formats, such as the bitcoin-cli command-line tool for the node software. These tools allow for the creation and manipulation of BSV scripts in any of the supported formats.

    Motivation

    Bare multi-sig transactions offer a simple and straightforward method to enable multiple parties to authorize a transaction in a decentralized manner. This approach is particularly useful for securing funds, enhancing trust between parties, and enabling flexible access control. Although bare multi-sig transactions come with certain privacy trade-offs, their ease of implementation and direct use of low-level Bitcoin scripting constructs make them a valuable option in the Bitcoin SV ecosystem.

    Specification

    A bare multi-signature transaction output script adheres to the following structure:

    • minimum_signatures: The minimum number of signatures required to unlock the funds (also known as the "M" value).

    • pubkey1, pubkey2, ..., pubkeyn: The public keys involved in the multi-signature scheme.

    • maximum_signatures: The maximum number of public keys (also known as the "N" value).

    • OP_CHECKMULTISIG: The Bitcoin opcode that validates the provided signatures against the specified public keys.

    Example

    The following example demonstrates a 2-of-3 multi-signature locking script:

    Locking Script:

    To spend the funds locked by this script, an unlocking script containing the required signatures must be provided:

    In this example, the OP_0 opcode is required due to a known bug in the original implementation of the OP_CHECKMULTISIG opcode, which results in an extra item being consumed from the stack.

    How it Works

    Bare multi-sig transactions work by requiring a minimum number of signatures from a given set of public keys to unlock the funds. When the locking script is executed, the OP_CHECKMULTISIG opcode verifies if the provided signatures correspond to the specified public keys and meet the minimum signature requirement. If the validation succeeds, the funds are unlocked and can be spent in a new transaction.

    While bare multi-sig transactions offer simplicity in implementation, they also expose the public keys and the multi-signature scheme directly in the transaction output script, which may reveal information about the participants and their relationships. Despite these privacy concerns, bare multi-sig remains an important tool for creating secure and flexible transactions within the Bitcoin SV digital asset ecosystem.

    Motivation

    Bitcoin is a token system, and as such, every output should be spendable and have value in satoshis. This fundamental principle ensures that Bitcoin remains a secure and reliable system that can be trusted by users around the world. However, traditional BRC-18 scripts, employing the OP_FALSE OP_RETURN pattern, are not compatible with this view.

    OP_FALSE OP_RETURN outputs are non-spendable and carry no value, which means they cannot be considered tokens under this definition. This creates a problem for developers who want to store data on the blockchain using OP_RETURN, as it goes against the basic principles of the Bitcoin token system.

    To address this issue, we propose a new methodology for creating OP_RETURN scripts that are spendable and contain satoshis. This provides a way for software to automatically convert non-compliant OP_RETURNs into proper Bitcoin tokens while encouraging developers to consider the spendability constraints that govern their tokens.

    By adding the cost of one single satoshi and the fully-open spendability constraints to OP_RETURN outputs, developers will be encouraged to consider the actual constraints that govern their tokens. This will drive them towards script patterns that protect what their tokens represent and promote a more robust and secure token system for Bitcoin.

    This standard offers a solution that maintains the fundamental principles of the Bitcoin token system while providing a practical way for developers to store data on the blockchain using OP_RETURN. By adopting this methodology, we can ensure that Bitcoin remains a secure and reliable system that can be trusted by users worldwide.

    Specification

    We specify the same script template as BRC-18, except that instead of OP_FALSE being the first opcode, it is replaced with OP_TRUE. We also stipulate that at least one satoshi must be locked in the output.

    For example:

    Risks and Limitations

    Because BRC-18 implementers did not define the constraints under which their Bitcoin tokens would be unlocked, we have defined a fully-open system in which anyone can redeem these tokens. If implementers see this as a problem, they should consider being cognisant of the mechanisms that define the spendability constraints of their Bitcoin outputs.

    BRC-18
    {
        "inputs": {
          "900b7e9ced44f8a7605bd4c1b7054b8fb958385998954d772820a8b81eabb56f": {
            "rawTx": "010000000135620d3a8fb626b763cb7b9a3c3197eda9bd6709ef1e4ebc2b359607800eaa95020000006b483045022100c3ec1792f1780e453c6ea692271bcc5388fb179d6455897f4b4200706e8b9f150220352cc2ff81a5c698e4626aec8976643134efab91ca1c80729670c2d007c77cfd4121037798f038cb7fc18b9d67baa87ed33122eb7be65b95b0dd304dc476c60043773dffffffff03e803000000000000c4210399322f558d92ced9c45d3bfe7dc5c01b830a4b61d71695ab0a1fa2cd90aba8b9ac2131546f446f44744b7265457a6248594b466a6d6f42756475466d53585855475a473462812d4eeb030fa496c2965f7e0f0b0e825d0547aceb7a9d4c76fd17e795753d8e2e0e82274ab36744a7968a43dc45b1cbdfab6c473045022100a58914da5346960ecb4de964f0f1e1be43a7645a11449c3a209f3fd69b34209b02205d4d4294d04c5f87fb16c2cdc3d9b41f9866fb3d7a690da08089c972d1393d816d75c8000000000000001976a91473a95c0b12e33b3d79f80508200a075bbab0906588ac4ea80200000000001976a91478daf10df51b3ea4c9292a72bf2e1e1d48ebe11288ac00000000",
          "proof": {
              "index": 2,
            "txOrId": "900b7e9ced44f8a7605bd4c1b7054b8fb958385998954d772820a8b81eabb56f",
            "targetType": "header",
            "target": "00000020ed40984238c0d6ed157cfd4fda4b284b48bb5c3b00b3172a2b030000000000006dfcabcc55b822548d10198ad1ddc62700947c8053213bf254b5229c92b9f448c6d32f64f13d051aa8201615",
            "nodes": [
                "9c97050e4c5fcc7f3ae7f7de83668d1968a626d70690654dab0398b75ca447a1",
              "fde37bbbec5cb48c085749aea7059412cc59c339bbc3e98960c081632382d538"
            ]
          },
          "outputsToRedeem": [
              {
                "index": 0,
              "unlockingScript": "473044022040ac4ef063c5139ef940860ec993dea2b38f2226cb841c231d60833d185934d50220760c48202fc150e3090ffbda4ccfe4ebce36715b4396d3555fb2f3dc03346e5cc2",
              "spendingDescription": "Complete a ToDo list item"
            }
          ]
        }
      },
      "description": "Complete a TODO task: \\"test\\""
    }
    {
      "description": "Pay John Galt 3,301 satoshis",
      "labels": ["payment", "personal"],
      "outputs": [
        {
          "script": "76a914b10f7d6c7fda3285e9b98297428ed814374cbd4088ac",
          "satoshis": 3301
        }
      ]
    }
    {
      "label": "payment",
      "limit": 10
    }
    {
      "transactions": [
        {
          "rawTx": "...",
          "inputs": { ... },
          "mapiResponses": { ... },
          "txid": "..."
        },
        ...
      ],
      "totalActions": 42
    }
    .lock
      FALSE RETURN
      <data1>
      <data2>
      <data3>
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "The user has denied permission to remove this output from the basket."
    }
    {
      "status": "error",
      "code": "ERR_CERTIFICATE_NOT_FOUND",
      "description": "The specified certificate could not be found."
    }
    <Buffer 76 a9 14 57 f5 0e 13 db 98 a8 8e 9e 1b 8f 03 f6 5a 80 9d 6e 9c 9c ba 88 ac>
    76a91457f50e13db98a88e9e1b8f03f65a809d6e9c9cba88ac
    OP_DUP OP_HASH160 57f50e13db98a88e9e1b8f03f65a809d6e9c9cba OP_EQUALVERIFY OP_CHECKSIG
    dup hash160 57f50e13db98a88e9e1b8f03f65a809d6e9c9cba equalverify checksig
    <minimum_signatures> <pubkey1> <pubkey2> ... <pubkeyn> <maximum_signatures> OP_CHECKMULTISIG
    2 <pubkey1> <pubkey2> <pubkey3> 3 OP_CHECKMULTISIG
    OP_0 <signature1> <signature2>
    .lock
      TRUE RETURN
      <data1>
      <data2>
      <data3>

    An array serialized Bitcoin transactions

    In practical use, BEEFs are exchanged between parties to build and process new transactions as well as validate arbitrary data recorded on the blockchain.

    The extension proposed here is to allow for "agreed upon transactions" to be represented in the array of transactions as just their transaction hash (txid),

    This avoids the need to include potentially significant amounts of data already known to the parties exchanging BEEFs.

    In addition, this extension formally acknowledges that a BEEF may contain mulitple transaction "roots".

    Motivation

    Consider when two parties cooperate over a short amount of time to construct one or more transactions.

    Inputs may be added by either party. New inputs may come from unmined and mined transactions.

    At each exchange of information along this process, one party sends a BEEF to the other to validate the new inputs or transaction(s) they originate.

    The BEEF standard is well suited to this with two extensions:

    1. In the general case, a BEEF does not need to be a single transaction tree.

    2. A method of referencing what the process has previously validated.

    For example, when adding new inputs to an incomplete transaction, the set of source transactions for these inputs may need to be transmitted to a second party. A BEEF of this validation information might include multiple trees of unmined transactions.

    Furthermore, some of these inputs might be from transactions created earlier in the process for which complete validation data - back to mined transactions - has already been shared.

    Consider in particular if some of these transactions are truly large or if the rate of linked transaction generation is high.

    Specification

    The serialized format for the transaction array is updated and the BEEF version number is incremented to 0200BEEF.

    For each serialized transaction, the byte previously used to indicate BUMP (01) or no BUMP (00) is renamed the Tx Data Format, it is now the first thing written for each transaction, and the value of (02) is now used when only a 32 byte txid is serialized.

    Field
    Description
    Size

    Version no

    Version number starts at 4022206466, encoded Uint32LE => 0200BEEF

    4 bytes

    nBUMPs

    VarInt number of BSV Unified Merkle Paths which follow

    1-9 bytes

    BUMP data

    All of the BUMPs required to prove inclusion of inputs in longest chain of blocks

    many bytes x nBUMPs

    nTransactions

    VarInt number of transactions which follow

    1-9 bytes

    Validation Semantics

    A txid only transaction is treated as implicitly valid, no raw transaction or BUMP index is included and no BUMP data is required.

    Additional transactions that consume outputs from a txid only transaction treat those inputs as fully validated.

    The ordering of transactions obeys the V1 rules: Parents, including txid only, must occur before children.

    Discussion of Alternatives

    A1: Why not just send multiple beefs with one rooted transaction in each?

    The essential function of the BEEF format is to efficiently represent transaction validation data.

    When multiple beefs are merged, all common BUMPS, merkle paths, and parent transactions are collapsed to a single copy.

    BRC-62
    BRC-74
    Participants
    • Alice: Initiates the sync process.

    • Bob: Responds and participates in the sync process.

    Protocol Steps

    1. Initialization

      • Alice starts by sending a bloom filter containing all current spendable TXID+VOUTs as elements.

    2. Receiving and Building List

      • Bob receives the filter and builds a list of his items that are not members of the set.

    3. Transaction Verification

      • Bob sends an INV (Inventory) message to Alice for each item not in the set.

      • The INV includes:

    4. Alice's Response

      • For each INV, Alice responds with a list of input transactions she does not know about.

      • If Alice has the transaction but the metadata hash differs, she requests updated metadata.

      • If Alice lacks the transaction, she requests the entire transaction.

    5. Recursive Transaction Sync

      • Bob responds to Alice's requests with an INV containing the encompassing transaction, done recursively.

        • When including the full transaction, all metadata is provided.

    6. Error Handling and Recovery

      • In case of errors, affected transactions are ignored and not synced.

      • If errors prevent a party from fully anchoring transactions back to the blockchain, these transactions are ignored.

      • Failures experienced by one party are not communicated to the other due to the declaratory nature of the protocol.

    7. Finalization of Sync

      • The process continues until there are no more INVs for Bob to send.

      • Once complete, all of Bob's records are considered synced with Alice.

    8. Role Reversal

      • The roles reverse, with Bob sending Alice a bloom filter.

      • The parties then exchange data in the other direction, following the same steps.

    Security Measures

    • Verification of merkle proofs and the longest chain of block headers.

    • Recursively requesting information until all inputs are fully proven.

    • Invalidating transactions that cannot be linked back to a valid proof.

    Notes

    • The protocol is adaptable to various blockchain environments.

    • The recursive nature ensures thorough and complete data synchronization.

    • The protocol emphasizes security, efficiency, and data integrity.

    Conclusion

    GASP offers a robust and secure method for synchronizing transaction data between parties in a blockchain network, leveraging recursive data exchange and thorough verification mechanisms.

    [email protected]
    Motivation

    We propose that p2p destination and receive raw transaction functionality between hosts to include the data required for the counterparty to run SPV on the transaction.

    BRFCID

    A random ID was generated in order to avoid label collisions in the capability document of a paymail server.

    Specification

    We specify that an endpoint for delivery of transaction data ought to be added to the capabilities object in the .well-known response of a paymail service with the label: 5c55a7fdb7bb.

    Client Request

    The sender must replace the {alias} and {domain.tld} placeholders in the URI template provided by capabilities.5c55a7fdb7bb with a valid Paymail handle. The client must then perform a POST HTTP request with the following body:

    BEEF transaction hex is a string encoding of the binary format detailed in BRC-62.

    Server Response

    The server must validate the transaction and respond with the accepted transaction ID and an optional human-readable note.

    Swimlanes

    A swimlanes diagram is included here for further clarification: https://swimlanes.io/u/6J2q8QCEb

    BRC-12 RawTx
    BRC-62 BEEF

    The deployment-info.json Specification

    Ty Everett ([email protected])

    Abstract

    We define a comprehensive and authoritative specification of the deployment-info.json schema. It is intended to serve as a reference for developers building BSV blockchain applications that integrate with the LARS (Local Automated Runtime System) and CARS (Cloud Automated Runtime System) tooling and beyond. By following this specification, projects can ensure a standardized and interoperable structure that other tools and workflows can rely upon.

    Specification

    The deployment-info.json file defines the structure and metadata of a BSV-based application for both local development (via LARS) and cloud deployment (via CARS). It describes the app’s topic managers, lookup services, frontend build configuration, contract compilation requirements, and various deployment configurations.

    Top-Level Schema

    Example:

    Fields

    schema (string)

    • Required: Yes

    • Valid Values: "bsv-app"

    • A fixed string identifying the schema type for this file. Must be "bsv-app".

    schemaVersion (string)

    • Required: Yes

    • Indicates the version of this schema. Example: "1.0".

    • As the schema evolves, this can help tooling handle backward compatibility.

    topicManagers (object)

    • Required: No (You may have no Topic Managers if your app does not define an overlay.)

    • Maps topic manager names (strings) to paths of their implementing modules.

    • Key (Topic Manager Name): A unique name (string) identifying the Topic Manager within the app. For example, "tm_meter", as per BRC-87.

    lookupServices (object)

    • Required: No (Only if your app needs overlay retrieval/lookup functionalities.)

    • Maps lookup service names (strings) to configuration objects describing how to instantiate them.

    • Key (Lookup Service Name): A unique name (e.g., "ls_meter"), as per BRC-87.

    frontend (object)

    • Required: No (Only if your project has a frontend.)

    • Describes how the frontend portion of the app is set up.

    • Fields:

      • language (string): The frontend tech stack. Common values:

    Example:

    contracts (object)

    • Required: No (Only if your project uses on-chain contracts.)

    • Describes contract language and location for source and artifacts.

    • Fields:

      • language (string): The contract language. Common values:

    Example:

    If contracts is present and language is "sCrypt", LARS/CARS can trigger automatic contract compilation steps when contracts change.

    configs (array)

    • Required: Yes (although it can be empty initially)

    • An array of configuration objects defining different deployment targets or modes for the project.

    • Each config object corresponds to either:

      • LARS

    Common Fields in Each Config:

    • name (string, required): A human-readable name for the configuration. E.g., "Local LARS", "production", "staging".

    • provider (string, required): Indicates whether this config uses LARS or CARS. Common values:

    LARS-Specific Fields:

    • run (array of strings, optional): Which parts of the project to run locally. Usually ["backend"], may include "frontend" if supported, but often the frontend is served separately. Example:

    CARS-Specific Fields:

    • CARSCloudURL (string, required for CARS): URL of the CARS cloud service. E.g., "https://cars-cloud.example.com".

    • projectID (string, required for CARS): The Project ID on the CARS Cloud. Used for managing deployments, logs, admins, etc.

    • deploy (array of strings, required): Which parts of the application to deploy to the cloud. E.g., ["frontend", "backend"]

    Example CARS Config:

    Additional Notes on configs:

    • Multiple CARS configs can coexist (e.g., one for "staging", one for "production", different networks, resilient deployment across clouds).

    • Only one LARS config is typically present (local dev environment). Tools like LARS assume a single local configuration.

    • Tools like CARS will prompt or require the user to pick a configuration if multiple apply.


    Integration With LARS and CARS

    • LARS uses deployment-info.json to:

      • Determine which topic managers and lookup services to load locally.

      • Compile contracts if specified under contracts.

    By maintaining a consistent deployment-info.json schema, both local and cloud tools can parse and understand the application’s structure, enabling smooth transitions from local dev (LARS) to production deployments (CARS).


    Compatibility and Future-Proofing

    • schema and schemaVersion: Future updates to the schema may introduce new fields or optional properties. Always check if your tools (LARS, CARS, or others) support the version you’re using.

    • Optional Fields: Many fields are optional, allowing minimal setups. For example, you can omit frontend if you have no frontend. You can omit lookupServices if you have no shared state coordination needs.


    Example Minimal deployment-info.json

    No frontend, no contracts, no lookup services, and a single LARS config.


    Example More Complex deployment-info.json


    Conclusion

    This reference provides a complete specification of the deployment-info.json schema used by LARS, CARS, and related tooling. By adhering to this schema, developers create a consistent and predictable environment, enabling a smooth, automated workflow from local development to production deployment.

    TXO Transaction Object Format

    • Ty Everett ([email protected])

    • _unwriter

    Abstract

    This document presents the technical standard for the TXO (Transaction Object) format, a structured representation of Bitcoin transactions that enables powerful queries, processes, and filters. The TXO format captures transaction data in a hierarchical structure, facilitating its storage in document databases (e.g., MongoDB) and enabling real-time filtering with JSON filter libraries (e.g., JQ).

    Motivation

    Traditional raw one-dimensional Bitcoin transactions, as described in , are challenging to process and filter, which hinders the development of applications that rely on transaction data. The TXO format overcomes these limitations by transforming raw Bitcoin transactions into a structured, queryable, and hierarchical format, thereby enabling developers to build powerful applications and services using transaction data.

    Specification

    The TXO format represents a Bitcoin transaction as a JSON object with the following high-level structure:

    Level 1: Transaction

    At the top level, the TXO format includes two objects: tx and blk.

    • tx (transaction): contains:

      • h (transaction hash)

      • r (raw transaction)

    Level 2: Script

    The next level of the TXO format includes two arrays: in (input scripts) and out (output scripts).

    Each input and output is essentially a Bitcoin script. Attributes for each script include:

    • i: the index of the current script within the in (input) or out (output) array.

    • b0, b1, b2, ...: the script's push data.

    Level 3: Graphs

    The third level of a TXO interpreted transaction focuses on the graphs that represent the relationships between transactions. Graphs play a crucial role in understanding the flow of transactions in the Bitcoin network. Each item in the in and out arrays has an attribute called e (edge), which represents the graph structure of each transaction. The edge attribute helps in connecting the inputs and outputs of a transaction, as well as tracking the flow of satoshis between addresses.

    For inputs, the edge is an "incoming edge" that represents the outputs from the previous linked transaction. It contains the following fields:

    • h: The hash of the transaction that contains the previous output.

    • i: The index of the previous output within its transaction output set.

    • a: The sender address if it can be parsed into an address.

    For outputs, the edge is an "outgoing edge" that represents the outputs to the next linked transaction. It contains the following fields:

    • v: The amount of satoshis sent.

    • i: The output index within the transaction.

    • a: The receiver address if the output is linking to an address.

    Implementation

    To implement the TXO format, follow these steps:

    1. Deserialize the raw Bitcoin transaction into its input and output scripts.

    2. Parse the input and output scripts into a JSON object following the TXO schema described in the specification section. This includes constructing the transaction, script, and graph levels for each transaction.

    3. If applicable, store the TXO JSON object in a document database (such as MongoDB) to enable powerful queries, or filter the transactions in real-time using JSON filter libraries (such as JQ).

    The reference implementation was written by _unwriter of the 21st Century Motor Company and is available .

    Merkle Path Binary Format

    Deggen ([email protected])

    Abstract

    We propose a binary format for a Single Merkle Path optimized for storage in a key value database.

    Copyright

    This BRC is licensed under the Open BSV license.

    Motivation

    The includes oddities in it for future extensions which are no longer necessary since they are covered by the compound merkle path format defined in . So now we attempt to specify the smallest possible encoding of a simple merkle path.

    Specification

    We take the JSON version from eg.

    Encoding in bytes we start with a VarInt for index, followed by nPath being the number of leaves to follow, followed by 32 byte leaves.

    Data Types

    Field
    Description
    Size

    Example

    Hex

    Bytewise Breakdown

    Implementation

    Let's start by dumping this format as hex into a Buffer and parsing it into an object with a Buffer Reader. Then we construct an object

    Bitcoin Script Assembly Language

    Ty Everett ([email protected])

    Abstract

    Bitcoin script is a programming language used in Bitcoin transactions to control the spending of coins. While the Bitcoin script opcodes are machine-readable, they are not easily human-readable. We define an assembly language that provides a human-readable format for expressing Bitcoin script opcodes, making it easier for developers to understand and write Bitcoin scripts. This specification defines the rules for expressing Bitcoin script opcodes in assembly format, including indentation, comments, expressing text strings and numbers, templating and other guidelines.

    Motivation

    Bitcoin script is a powerful tool for controlling the spending of coins, but its opcodes can be difficult for developers to read and understand. By providing a human-readable assembly format for expressing Bitcoin script opcodes, developers can more easily write and debug Bitcoin scripts. This specification aims to standardize the assembly format for Bitcoin script opcodes, making it easier for developers to work with Bitcoin transactions.

    This specification is intended to start the discussion and propose an initial format for representing Bitcoin scripts in an assembly language. Iterative improvement through future BRCs will help improve this standard.

    Specification

    We specify an assembly language for Bitcoin script programs as follows:

    Syntax

    • Opcodes should be expressed in uppercase and without OP_ prefixing, e.g. CHECKSIG.

    • Data to push on the stack is represented by strings, hex values, or template variables.

    • Whitespace should be used for indentation and to separate tokens.

    For example:

    Data types

    • Numeric values should be expressed as their corresponding opcodes, or in hexadecimal format.

    • String values should be enclosed in single quotes.

    • Hex values should be expressed in lowercase, without 0x prefixing.

    For example:

    Flow control

    Conditional statements should use the IF opcode, followed by the conditional expression and the ELSE or ENDIF opcodes.

    For example:

    File Extension

    We specify that .basm files can be used to represent Bitcoin assembly language programs.

    Implementation

    The process of assembling programs written in this assembly language comprises:

    • Obtaining the values for template variables, either programmatically or by seeking user input

    • Substituting template variable placeholders for the actual values

    • Removing comments

    • Computing and adding the correct PUSHDATA opcodes for adding string and hexadecimal values to the stack

    Push TX

    Abstract

    Push TX is a technique that enables users to enforce and access transactional states and conditions within Bitcoin script using ECDSA signature messages. It allows for the enforcement of several transaction elements, such as the number of inputs, nSequence values, input and output values, and script conditions, as well as the ability to specify the script into which tokens will be spent. The Push TX algorithm works by pushing the transaction pre-image message that generates the signature onto the stack as part of the input's unlocking script. This message can be pushed as a single contiguous blob, multiple separate elements, or as a partial set, with the remaining elements of the message set via the output's locking script. The signature is then computed on-chain within the script and checked against the public key using OP_CHECKSIG to ensure the current transaction is valid. This standard outlines the motivation and specifications for implementing the Push TX technique within Bitcoin script.

    Motivation

    The Push TX technique offers several benefits to Bitcoin users and developers. Firstly, it allows for the enforcement of complex transactional states and conditions at the consensus layer, making it easier to create Turing complete machines within the Bitcoin ecosystem. This is achieved by enabling users to specify the script into which tokens will be spent, which can be used to enforce next state conditions. Additionally, it enables users to specify and enforce various transaction elements, such as input and output values, nSequence values, and the nLocktime condition. This improves the security and efficiency of Bitcoin transactions by ensuring that all transactional conditions are met and enforced at the consensus layer.

    Specification

    The Push TX algorithm works as follows:

    1. The user or process that is using the UTXO pushes the transaction pre-image message that generates the signature onto the stack as part of the unlocking script. This message can be pushed as a single contiguous blob, multiple separate elements, or as a partial set, with the remaining elements of the message set via the output's locking script.

    2. The algorithm pushes the current transaction onto the stack.

    3. The algorithm pushes a dummy private key onto the stack.

    The Push TX algorithm can be used to enforce several elements of the transaction, including but not limited to the number of inputs, nSequence values, input and output values, and script conditions, as well as the ability to specify the script into which tokens will be spent.

    Implementations

    This has been .

    Commentary

    Bitcoin script is often misunderstood as being limited to the data provided in the locking and unlocking scripts. However, the Push TX technique allows for the inspection of the entire transaction within a contract itself, including all inputs and outputs. This opens up boundless possibilities for smart contracts on Bitcoin.

    The ability to place arbitrary constraints on inputs and outputs within a contract means that a wide range of use cases can be implemented on Bitcoin. For example, contracts that enforce multi-signature transactions or time-based restrictions can be easily created using Push TX. Additionally, the technique enables the creation of more complex contracts that can enforce next state conditions, making it possible to create Turing complete machines within the Bitcoin ecosystem.

    The high-level functionality of Push TX is relatively simple: it allows for the inspection and enforcement of transactional states and conditions within Bitcoin script. However, the implications of this functionality are far-reaching, as it enables the creation of a wide range of smart contracts and decentralized applications on the Bitcoin blockchain. This is important for Bitcoin because it expands its use cases and makes it a more versatile platform for developers and businesses looking to leverage blockchain technology.

    References

    PacketPay HTTP Payment Mechanism

    Ty Everett ([email protected])

    Abstract

    This standard describes PacketPay, a mechanism for facilitating micropayments using Bitcoin SV within HTTP requests. It relies on the BRC-29 payment protocol for processing payments, and BRC-31 Authrite for authenticating communications between the API provider and consumer. PacketPay enables secure, per-request monetization of APIs, allowing API providers to charge consumers on a pay-per-use basis. This standard defines the required HTTP headers, the process of making and verifying payments, and the necessary steps to implement PacketPay in API interactions.

    Motivation

    The rapid growth of web services and APIs has created a need for efficient, secure, and scalable methods of monetizing these services. Traditional payment methods are often cumbersome and impose high fees, making them unsuitable for micropayments. PacketPay addresses this need by providing a secure, efficient, and low-cost solution for facilitating micropayments in HTTP requests. By leveraging Bitcoin SV's capabilities, PacketPay enables API providers to monetize their services on a per-request basis, and API consumers to pay only for the resources they use.

    Specification

    HTTP Headers

    PacketPay uses the following HTTP headers for facilitating payments between API consumers and providers:

    1. x-bsv-payment-satoshis-required: Sent by the API provider in a 402 response, it indicates the number of satoshis required for the requested resource.

    2. x-bsv-payment: Sent by the API consumer in a request to a payment-enabled API endpoint, it contains a JSON stringified object representing a payment.

    3. x-bsv-payment-satoshis-paid: Sent by the API provider in the response to a successfully paid API request, it indicates the number of satoshis paid for the requested resource.

    PacketPay Process

    The PacketPay process is divided into the following stages:

    1. Authentication: The API consumer and provider exchange Authrite requests and responses to authenticate their identities and share necessary identity information.

    2. Initial Request: The API consumer sends an HTTP request to the API provider without a payment. If the requested resource requires a payment, the API provider responds with a 402 status code and includes the x-bsv-payment-satoshis-required header, indicating the required payment amount.

    3. Payment Processing: The API consumer reads the x-bsv-payment-satoshis-required

    Implementation

    To implement PacketPay, API providers and consumers must follow these steps:

    1. Implement for processing payments and for authenticating communications between parties.

    2. For API providers, implement logic to determine the payment required for each request and include the x-bsv-payment-satoshis-required header in the 402 response.

    3. For API consumers, implement logic to read the x-bsv-payment-satoshis-required header, construct a payment, and include the x-bsv-payment

    By following the above implementation steps, API providers and consumers can ensure secure and efficient micropayments using the PacketPay system. This will enable a new revenue model for APIs, allowing for greater flexibility and scalability in the ever-growing world of web services.

    The PacketPay and have been implemented in JavaScript by the Babbage Team.

    Overlay Services Synchronization Architecture

    Ty Everett ([email protected])

    Abstract

    This document outlines the Overlay Services Synchronization Architecture, detailing the Services Host Interconnect Protocol (SHIP) and Services Lookup Availability Protocol (SLAP). These protocols enable efficient peer discovery and data synchronization across UTXO-based overlay networks. This BRC defines the components, interactions, and responsibilities of nodes running these protocols to maintain reliable and up-to-date overlay services.

    Motivation

    The proliferation of UTXO-based overlay networks necessitates robust mechanisms for peer discovery and data synchronization. While defines transaction submission and processing, SHIP and SLAP extend this by providing standardized methods for discovering the overlay hosts that run particular services. This architecture ensures seamless interaction between network participants, improving the efficiency and reliability of data propagation. It can also enable the users of services to find hosts that are interested in their transactions.

    Background

    Readers of this document should be familiar with BRCs 45, 59, 22, 24, 23, and 25.

    Specification

    Overview

    The Overlay Services Synchronization Architecture comprises two fundamental protocols:

    1. Services Host Interconnect Protocol (SHIP)

    2. Services Lookup Availability Protocol (SLAP)

    Each node running overlay services will implement topic managers and lookup services for both SHIP and SLAP, ensuring alignment between advertised services and their actual configuration.

    Components

    • SHIP/SLAP Topic Managers: Manage topic-specific transaction admittance.

    • SHIP/SLAP Lookup Services: Provide mechanisms for querying UTXO states within topics.

    • Advertiser: Handles the creation and revocation of SHIP and SLAP advertisements.

    • Overlay Services Engine: Coordinates the processing of transactions, alignment of advertisements, and synchronization of data across various services.

    Key Responsibilities

    1. Ensuring Alignment

    Each node must ensure alignment between the SHIP and SLAP advertisements it has sent out and the current set of topic managers and lookup services it is configured with.

    2. Hosting SHIP/SLAP Overlay Networks

    Nodes host copies of the SHIP and SLAP overlay networks, ensuring they are updated with new advertisements or revocations.

    • Submission: Any node can submit SHIP/SLAP advertisements to another node if it knows its domain name, updating the overlay network.

    • Internal Updates: Nodes submit their own advertisement transactions to themselves to update the overlay networks about new advertisements or revocations, thereby ensuring their hosted copies are always current and propagating them to other nodes.

    3. Transaction Propagation

    As part of the transaction submission process, nodes notify each other about transactions on topics they host and care about.

    When new transactions are submitted to a node, the Engine:

    • Ensures transactions are propagated to relevant nodes based on SHIP/SLAP advertisements made by them.

    • Updates lookup services with new or spent UTXOs.

    • Delegates transaction submission, verification, and output admittance to the SHIP/SLAP topic managers.

    SHIP and SLAP Token Formats

    SHIP Token Format

    Field
    Meaning

    SLAP Token Format

    Field
    Meaning

    Token Creation and Submission

    The advertiser creates a transaction output containing the token and submits it to known nodes, including their own. The process involves:

    1. Deriving the locking key using the advertiser's identity key.

    2. Computing the signature over the token fields.

    3. Creating and submitting the transaction output containing the token.

    Token Validation and Admission

    Nodes validate the identity key's link to the signature-producing key before admitting the output. The steps include:

    1. Extracting token fields.

    2. Verifying the SHIP/SLAP identifier.

    3. Verifying the locking key and signature.

    4. Admitting the token if valid.

    Implementation

    Developers should implement an HTTPS server that hosts the SHIP and SLAP topic managers and lookup services. The server should be responsible for notifying other nodes of relevant transactions and maintaining synchronization.

    BIP32 Key Derivation Scheme

    Abstract

    This technical standard describes a method for hierarchical key derivation called BIP32. Hierarchical key derivation enables the generation of a large number of public-private key pairs from a single master seed, and the ability to derive child keys from parent keys in a deterministic manner. BIP32 is a widely used standard in various fields such as wallets, but has various limitations and drawbacks that should be considered carefully before further adoption.

    Motivation

    In many applications, it is necessary to generate a large number of public-private key pairs. However, generating and securely storing many keys can be challenging. Hierarchical key derivation solves this problem by generating an unlimited number of keys from a single master seed. This reduces the complexity of managing multiple keys and enhances security. BIP32 provides a standard for implementing hierarchical key derivation, ensuring interoperability between different systems.

    Overview

    BIP32 is a method for hierarchical key derivation that enables the generation of a virtually unlimited number of public-private key pairs from a single master seed. The master seed is used to generate the master private key, which is used to derive child keys. Child keys can in turn be used to derive grandchildren keys, great-grandchildren keys, and so on, forming a hierarchical tree-like structure.

    Each key in the hierarchy is determined using a combination of its parent key and an index value. The index value determines the position of the key in the hierarchy, and the parent key serves as a starting point for deriving the child key. The combination of the parent key and the index value is used to generate a new private key, which can then be used to derive a new public key.

    BIP32 specifies the use of a deterministic algorithm for deriving keys. This means that given the same master seed and index value, the same key will be generated every time. This is important for ensuring that different systems can generate the same keys, and for enabling secure backup and recovery of keys.

    BIP32 also provides a standard for deriving hardened keys, which are child keys that cannot be derived from their parent public key alone. Hardened keys provide an additional layer of security, as they can only be derived using the parent private key.

    BIP32 is a widely used standard for implementing hierarchical key derivation. It enables the generation of a large number of public-private key pairs from a single master seed, and ensures interoperability between different systems.

    BIP32 Derivation Paths

    BIP32 defines a hierarchical tree-like structure for generating an unlimited number of public-private key pairs from a single master seed. This structure is organized using a derivation path, which is a sequence of index numbers and hardened/not-hardened markers that uniquely identify a particular key in the hierarchy.

    A derivation path always starts with the letter "m", which stands for "master", followed by a forward slash ("/") and then a series of numbers and markers that specify the child keys to be derived. For example, the path "m/0/1/2" indicates that the third child private key should be derived from the second child private key of the first child private key of the master key.

    In addition to simple index numbers, BIP32 allows for "hardened" derivation, which means that the derived key can only be generated using the parent's private key. Hardened keys are denoted with an apostrophe (') after the index number. For example, the path "m/44'/0'/0'/0/0" is commonly used for generating the first receiving address of a Bitcoin wallet using BIP44 standard (discussed below).

    BIP44 Wallet Addressing

    BIP44 is a widely used standard for generating hierarchical deterministic wallets with a specific structure for addressing different cryptocurrencies. This standard provides a consistent method for generating and organizing addresses across different wallets and platforms.

    The BIP44 structure uses a derivation path that starts with "m/44'/<coin_type>'/", where <coin_type> is a numeric identifier for the cryptocurrency being used. For example, "m/44'/0'/" is the path for generating Bitcoin keys, and "m/44'/60'/" is the path for generating Ethereum keys.

    Following the coin_type index, BIP44 specifies several other indices to organize keys, including account, change, and address indices. Account indices are used to manage multiple accounts within a single wallet, change indices are used to differentiate between incoming and outgoing transactions, and address indices are used to generate unique receiving addresses.

    For example, the path "m/44'/0'/0'/0/0" generates the first receiving address for the first account of a Bitcoin wallet. The "0'" after the coin_type index indicates a hardened key, ensuring that the derived key can only be generated using the parent's private key. The "0" after the hardened index specifies the first account, and the "0" after that specifies the first address in the account.

    Drawbacks and Alternatives

    While BIP32 is a widely used standard for hierarchical key derivation, there are several potential drawbacks that should be considered before further adoption.

    One major limitation is that BIP32 lacks privacy guarantees. Since it is common for all child keys in a wallet to be derived from a single node, any knowledge of the root public key could compromise the privacy of the entire key hierarchy for the wallet — since public keys can be derived from parent public keys, there is a risk of linkability between addresses that use the same parent key.

    Additionally, BIP32 is limited to a maximum of 2^31 possible child keys per parent, which may not be sufficient for applications that require a very large number of keys.

    To address these limitations, other key derivation schemes adopt various alternative approaches. By incorporating a shared secret between the sender and the recipient into the key derivation process, we can protect privacy even when the root public key becomes known. enables this functionality, and allows an unlimited number of child keys to be derived.

    References

    • 1:

    Serialization Format for Portable Encrypted Messages

    Ty Everett ([email protected])

    Abstract

    This document describes a protocol for a portable message encryption and description scheme. It follows the BRC-42 key derivation and BRC-43 invoice number standards to protect the confidentiality of message content, without requiring the added complexity of agreeing on a specific BRC-43 protocol for the parties to use.

    Motivation

    Message encryption is a fundamental requirement as it ensures the privacy and confidentiality of the content transmitted between parties. The current standards like Electrum ECIES don't provide a comprehensive solution for message encryption by integrating with BRC-42 and BRC-43. This document aims to enhance security by developing a protocol for message encryption and decryption, utilising the BRC-43 invoice numbers. The protocol facilitaes a way to exchange encrypted data in a general way.

    Specification

    The protocol employs the BRC-2 encryption process and makes use of the BRC-42 key derivation and BRC-43 invoice numbering scheme.

    The encryption procedure follows these steps:

    1. The sender employs BRC-43 with security level 2, protocol ID message encryption, and a randomly generated 256-bit key ID to compute the invoice number to facilitate BRC-42 key derivation. We specify the key ID is in base64 format when added to the invoice number.

    2. The sender derives their own child private key and the child public key of the recipient using BRC-42 key derivation.

    3. The sender then computes an ECDH shared secret between the two child keys which is used in symmetric encryption with AES-256-GCM.

    For decryption:

    1. The recipient computes their own private key and the public key of the sender using BRC-42 key derivation.

    2. The recipient computes the same Shared Secret and uses it along with the received initialization vector to decrypt the ciphertext.

    Serialization format

    The serialized data for transmission includes a version number, the identity key of the sender, the identity key of the recipient, and the AES-256-GCM ciphertext (with the initialization vector prepended). Note that anyone is not permitted for encrypted data:

    Field
    Field Length
    Description

    This standard serialization format contributes towards a standardized way of securely transmitting and decrypting encrypted messages.

    Hex Examples

    HTTPS Transport Mechanism for DPP

    Abstract

    BRC-27 defines an abstract messaging protocol that facilitates payments on the Bitcoin SV network. This specification extends the protocol with the specifics required for a concrete HTTPS implementation that includes message size limits and HTTPS-specific implementation details.

    Motivation

    HTTPS is one of the most widely used transport mechanisms for internet traffic. Enabling users of HTTPS to benefit from the use of the DPP will facilitate increased industry adoption and growth. Defining implementation-specific stipulations for HTTPS-based DPP will address problems and ambiguities specific to this communications substrate.

    Specification

    Below is the table with messages requested from client (wallet) to merchant (server).

    The paymentID parameter is assumed to be known as a result of request between client-server before DPP protocol operation.

    MESSAGE
    ENDPOINTS
    TYPE/SUBTYPE
    RESPONSE CODES

    PaymentTerms messages larger than 10 MB should be rejected by the wallet application, to mitigate denial-of-service attacks.

    Payment messages larger than 10 MB should be rejected by the payment host’s server, to mitigate denial-of-service attacks.

    PaymentACK messages larger than 11 MB bytes should be rejected by the wallet application, to mitigate denial-of-service attacks. This is larger than the limits on Payment and PaymentTerms messages as PaymentACK contains a full Payment message within it.

    Implementations

    The BRC-55 API is implemented .

    Merkle Path JSON format

    Deggen ([email protected])

    Abstract

    We present a data model and JSON format for a Merkle Path which will be passed from a Transaction Lookup service to a Lite Client via web API.

    TSC Proof Format with Heights

    Tone Engel ([email protected]), TonesNotes

    Abstract

    This is an argument for using block height as the standard for indexing block headers within merkle proofs.

    It argues for a backward compatible protocol extension in the short term and through deprecation, a long term reduction in the space cost of a usable local copy of block headers by a factor of two.

    The referenced specification, the "Spec":

    Everett-style Transaction Envelopes

    Ty Everett ([email protected])

    Abstract

    This document outlines the BRC-8 standard for Everett-style Transaction Envelopes. The standard defines the structure and format of the envelopes used to send Bitcoin transactions. The primary goal of this standard is to ensure interoperability between different Bitcoin wallet software and services, allowing them to exchange transaction data in a consistent manner. This standard also aims to facilitate the implementation of the Simplified Payment Verification (SPV) process, as defined in , by providing a standardized methodology for exchanging merkle proofs and input transactions.

    Pay to Public Key Hash

    Ty Everett ([email protected])

    Abstract

    The Pay-to-Public-Key-Hash (P2PKH) output script is a commonly used script in the Bitcoin network that allows users to send funds to a specific Bitcoin address. This standard provides a detailed specification of the P2PKH output script, providing detail on the operations performed, and giving examples for serialized Bitcoin addresses.

    Publishing Trust Anchor Details at an Internet Domain

    Ty Everett ([email protected])

    Abstract

    This document outlines a protocol that allows an entity to publish trust anchor details, including a public key, at a location on the internet. The information is stored in the /manifest.json file of the domain. This approach provides a user-friendly method for individuals to easily retrieve a trusted entity's public key by entering a known domain name.

    P Protocols: Allowing future wallet protocol permission schemes

    Ty Everett ([email protected])

    Abstract

    The architecture for wallet protocol permissions enables a wide range of use cases. By reserving protocol identifiers and preventing their use by applications, we ensure compatibility with future standards, supporting the future development of new protocol permission schemes.

    brfcid: 5c55a7fdb7bb
    title: Background Evaluation Extended Format Transaction
    author: Darren Kellenschwiler
    version: 1.0.0
    <!-- capabilities document of the host -->
    {
        "capabilities": {
            "5c55a7fdb7bb": "https://paymail.domain.tld/api/v1/beef/{alias}@{domain.tld}",
            <!-- ...others -->
        }
    }
    {
      "beef": "<beef_transaction_hex>", <!-- note the label is different >
      "metadata": {
        "sender": "<sender_paymail>",
        "pubkey": "<sender_public_key>",
        "signature": "<signature_of_txid>",
        "note": "<optional_human_readable_note>"
      },
      "reference": "<payment_reference>"
    }
    {
      "txid": "<accepted_txid>",
      "note": "<optional_human_readable_note>"
    }
    Output, transaction, and associated merkle proof.
  • Any metadata (such as labels, descriptions, or local timestamps) associated with transactions or outputs.

  • A list of VOUTs spent by its inputs and associated metadata hashes.

  • The preimage for each hash, including all metadata and the merkle proof or broadcast response.

  • When only metadata is included, it encompasses the list of spent VOUTs and associated metadata hashes.
    Using the transaction and private key pushed in steps 2 and 3, the algorithm generates an ECDSA signature on-chain within the script.
  • The algorithm pushes the public key derived from the private key onto the stack.

  • The algorithm uses OP_CHECKSIG to check the signature against the public key, ensuring that the current transaction is valid.

  • implemented in the sCrypt ecosystem
    nChain WP-1605
    Xiaohui Liu Article

    Field 1

    The string SHIP, denoting a SHIP advertisement.

    Field 2

    The BRC-31 identity key of the advertiser.

    Field 3

    The domain name of the HTTPS server hosting the network node.

    Field 4

    The topic name hosted by the advertiser.

    Field 1

    The string SLAP, denoting a SLAP advertisement.

    Field 2

    The BRC-31 identity key of the advertiser.

    Field 3

    The domain name of the HTTPS server hosting the network node.

    Field 4

    The service name, represented by a BRC-24 provider ID.

    BRC-22
    BRC-42
    1
    BRC-42: BSV Key Derivation Scheme (BKDS)

    PaymentTerms

    GET /api/v1/payment/{paymentID}

    application/json

    200 – contains PaymentTerms JSON object with all data used by the payee to construct a transaction 404 – returned if the paymentID has not been found 500 – returned if there is an unexpected internal error

    Payment

    POST /api/v1/payment/{paymentID}

    application/json

    201 – contains PaymentACK JSON object 400 – returned if the user input is invalid, usually an issue with the paymentID 404 – returned if the paymentID has not been found 500 – returned if there is an unexpected internal error

    BRC-27
    in this example from Jad Wahab

    Tx Data Format

    00 raw transaction without BUMP index; 01 raw transaction followed by BUMP index; 02 txid only

    1 byte

    BUMP index

    Format 01: VarInt index number indicating the BUMP to which Raw Transaction belongs.

    1-9 bytes

    Raw Transaction

    Format 00 or 01: RawTx bytes as in standard format BRC-12

    many bytes

    txid only

    Format 02: 32 byte transaction hash in reverse byte order

    32 bytes

    BRC-74
    Motivation

    The motivation for this proposal is to future-proof the BRC-43 architecture by enabling the seamless integration of new protocol permission schemes. By specifying reserved identifiers, we can ensure that new security and permission paradigms can be implemented without conflicts or unintended behavior.

    Specification

    To accommodate future protocol permission schemes, wallets must reject operation requests using protocol IDs beginning with p (a lowercase “p” followed by a space), regardless of security level.

    Future Scheme Identifiers

    Future permission schemes must define their ID formats as follows:

    • Scheme IDs cannot contain spaces.

    • Protocol IDs must start with p , followed by the scheme ID, a space, and the rest of the protocol identifier.

    Example Format

    A protocol ID like p 222 xxxxx could represent a specific invoice number (e.g., 2-p 222 xxxxx-kkkkk), where:

    • 2 indicates the BRC-43 security level.

    • p designates an alternative permission scheme.

    • 222 identifies the permission scheme.

    • xxxxx forms the remainder of the protocol ID under the alternative scheme.

    • kkkkk denotes the key ID.

    Protocol Parsing and Rules

    Wallets must differentiate between standard and alternative permission schemes by recognizing the p prefix followed by a distinct, space-free scheme ID. To ensure unambiguous parsing.

    Upon recognizing a protocol ID structured as p <scheme ID> <rest of the ID>, wallets may apply the specific rules defined by the scheme associated with the scheme ID. These rules could define:

    • Permitted protocols and key IDs.

    • Conditions for operation execution.

    • Counterparty requirements and customizable permission attributes.

    Reserved Structure

    To maintain clarity and prevent conflicts:

    • Protocol IDs beginning with p must be reserved for future use.

    • Wallets must reject operations involving such IDs unless they explicitly support the scheme ID.

    • A space must immediately follow the scheme ID to separate it from other elements.

    Extensibility Beyond Current Paradigms

    This specification allows future permission schemes to extend beyond current BRC-43 models (e.g., security levels or BRC-73 paradigms), enabling flexible and innovative wallet permissions that evolve with user and application needs.

    Conclusion

    By reserving protocol IDs starting with p and specifying rules for future permission schemes, this specification ensures forward compatibility and robust wallet permission functionalities. It enables seamless integration of new schemes without disrupting existing applications or introducing parsing ambiguities.

    BRC-43
    header, constructs a
    payment message for the required amount, and includes it in the x-bsv-payment header of the subsequent API request.
  • Payment Verification: The API provider reads the x-bsv-payment header, verifies the payment using BRC-29, and processes the request if the payment is valid.

  • Payment Acknowledgment: The API provider sends a response containing the x-bsv-payment-satoshis-paid header, indicating the number of satoshis paid for the requested resource. The API consumer reads this header to confirm successful payment.

  • header in the subsequent request.
  • For API providers, implement logic to read and verify the x-bsv-payment header using BRC-29, process the request if the payment is valid, and include the x-bsv-payment-satoshis-paid header in the response.

  • For API consumers, implement logic to read the x-bsv-payment-satoshis-paid header and confirm successful payment.

  • BRC-29
    BRC-31
    BRC-29
    BRC-31
    BRC-29
    client
    express middleware
    BRC-29

    blk (block): contains:

    • i (block index)

    • h (block hash)

    • t (block time)

    Opcodes: stored as a JSON object with a single key op and the Bitcoin opcode value (e.g., {"op": 106} for the 'return' opcode).

  • Non-Opcodes: stored as a base64 encoded string.

  • lb0, lb1, lb2, ...: base64 encoded string, used when the push data size is larger than 512 bytes.

  • s0, s1, s2, ...: UTF8 encoded representation of the push data, used for full-text search and simple string matching.

  • ls0, ls1, ls2, ...: UTF8 encoded representation, used when the push data size is larger than 512 bytes.

  • str: full string representation of the script.

  • e: contains the graph structure of each transaction.

  • Ensure compatibility with the TXO format by including all specified fields and adhering to the defined structure.
    BRC-12
    on NPM

    index

    VarInt tx index number from within a block

    1-9 bytes

    nLeaves

    VarInt number of leaves which follow

    1-9 bytes

    leaf

    Each leaf of the path is a 32 byte hash

    32 bytes x nLeaves

    TSC format
    BRC-61
    BRC-58

    Comments should start with the # character and extend to the end of the line.

  • .unlock and .lock can be used to denote the boundary between an unlocking script and its corresponding lock.

  • Template variables are placed in angle brackets like <hash>

    Converting all string values to hexadecimal

  • Substituting all opcode names for their hexadecimal coded values

  • Removing .unlock and .lock annotations if present

  • Removing all whitespace to arrive at the fully-assembled program

  • With a random initialization vector, the message is encrypted and the vector is prepended to the ciphertext.

    Ciphertext

    Variable

    The encrypted message data (AES-256-GCM with IV prepended)

    Version

    4 bytes

    Defines the version of the standard used. Currently 0x42421033.

    Sender ID

    33 bytes

    Identity key of the sender (encryptor)

    Recipient ID

    33 bytes

    Identity key of the recipient (decryptor)

    Key ID

    32 bytes

    The specific key ID used for the signature

    Value (Path): A relative file path (string) to a .ts module with a default export for a class that implements the TopicManager interface from @bsv/overlay.
  • Example:

  • Value (Service Config Object):
  • Fields in the Service Config Object:

    • serviceFactory (string, required): A path to a .ts module containing a default export of a factory function that creates a LookupService instance. The factory function may accept database connections (e.g., a MongoDB Db object) and return a class that implements the LookupService interface from @bsv/overlay.

    • hydrateWith (string, required): Defines how the service should be backed by persistent storage. Accepted values:

      • "mongo": Indicates that the lookup service’s storage uses a MongoDB database. LARS/CARS will provide a mongoDb instance.

      • "knex": Indicates that the service uses a SQL-based storage via Knex. LARS/CARS will provide a knex instance.

  • "react"
    ,
    "html"
    , etc. Tools can use this to know how to build or deploy the frontend.
  • sourceDirectory (string): Path to the frontend source files relative to the project root.

  • "sCrypt"
    .
  • baseDirectory (string): Path to the directory containing contract source code and related build outputs, depending on the language.

  • : A local development environment configuration.
  • CARS: A cloud deployment configuration.

  • You can have multiple CARS configs (e.g., "staging", "production") and at most one LARS config (by convention, though not strictly enforced).

  • "LARS": Local environment config
  • "CARS": Cloud environment config

  • network (string, optional): "mainnet" or "testnet". Specifies which BSV network this config targets.

    • For LARS: Required to know if the local environment simulates mainnet or testnet conditions.

    • For CARS: Determines which network the release should be associated with.

  • .
  • frontendHostingMethod (string, optional): How the frontend is hosted in the cloud. Common values:

    • "HTTPS": Host frontend over HTTPS (CDN or static hosting, default)

    • "UHRP": Host via the UHRP protocol (if integrated and supported by the specific CARS Cloud)

  • Identify a LARS config in configs to know what network to run, what keys to use, and what parts of the app to start.
  • CARS uses deployment-info.json to:

    • Identify CARS configs and connect to the specified CARS Cloud environment.

    • Build and upload artifacts, define which components to deploy.

    • Manage projects, logs, admins, and releases in a cloud environment based on project ID.

  • Custom Fields: It’s possible tools or future expansions add custom fields. Such fields should not conflict with the specified ones and should be namespaced or documented externally. Primary LARS/CARS tooling will typically ignore unknown fields.
    Motivation

    BRC-10 otherwise known as the TSC Merkle Proof Standardized Format has a few competing ideas baked into it rather than it being a clear standard to be used in one way only. This has lead to an ugly solution which can be ambiguous. This JSON format is a simple recommendation for how we might use a prettier structure in future to clarify the intended use.

    The name Merkle Proof suggests that it can on its own prove something. I don't think this is the case as a blockheader is required to validate. Therefore the suggested name is a "Merkle Path".

    Specification

    A Merkle Path needs to indicate the txid of the transaction in question, but this is assumed to be the key of the object rather than contained within the object itself. Also needed is an index number which indicates position with a block.

    The proposed JSON is:

    Use

    The idea is to use the Merkle Path like so:

    1. Convert all hex string into reverse bytes, txid and all leaves.

    2. Calculate the Merkle root by hashing the txid with each element in the path.

      1. Checking the last bit of the index number, if it's 1 then the txid should be on the right workingHash = sha256d([...leaf, ...txid]) else other way around workingHash = sha256d([...txid, ...leaf])

      2. Right shift the index number

      3. Check the new last bit, if it's 1 then the workingHash should be on the right workingHash = sha256d([...leaf, ...workingHash]) else other way round workingHash = sha256d([...workingHash, ...leaf])

    3. Once all leaves are accumulated into a single hash with the above method - we have the Merkle root which we reverse and convert back into a hex string.

    4. This root can be used to look up a block header.

    5. If the blockheader is part of the longest chain of work then we have a "Merkle Proof" that the tx is included in that block.

    Merkle Proof JSON

    You would only likely see a Merkle Proof when you are in a position where you have to present evidence to a court for dispute resolution or something to that effect. In day to day use the Merkle Path format detailed above is all that need be kept within the transaction store, the block header information can be kept separately.

    Discussion

    The main difference between this and the TSC Merkle Proof Standard Format is renaming a few labels:

    Labels

    • txOrId is dropped in favor of txid because the ambiguity is unnecessary, and full transactions have their own format considerations to focus on, hence separation of concerns.

    • nodes are renamed to path because this more accurately describes the specific hashes we are referring to as those without children in a Merkle tree, and also disambiguates between these and bitcoin nodes or network nodes in general. Citing the original Merkle Tree patent we see this referred to as "path", with no mention of nodes anywhere.

    Order

    The order of items in the JSON is not strict but does imply a better general understanding. As a sentence: This transaction in this block is at index 12 with path... etc.

    Motivation

    The P2PKH output script is used to ensure that only the owner of a specific Bitcoin address can spend the funds sent to that address. This is achieved by requiring the spender to provide a valid signature that corresponds to the public key associated with the address. The P2PKH output script is widely used in the Bitcoin network and is the most common output script used in transactions.

    Specification

    The P2PKH output script is defined as follows:

    Where:

    • OP_DUP duplicates the top stack item.

    • OP_HASH160 computes the RIPEMD160 hash of the SHA256 hash of the top stack item.

    • <PubKeyHash> is the RIPEMD160 hash of the SHA256 hash of the public key associated with the Bitcoin address.

    • OP_EQUALVERIFY checks if the top two stack items are equal and removes them if they are.

    • OP_CHECKSIG verifies that the signature provided by the spender is valid for the public key associated with the address.

    Serialization Format (Base58)

    The P2PKH output script is serialized using Base58 encoding. The serialized format is as follows:

    Where:

    • [Version Byte] is a single byte that identifies the network and the script type. The value of the version byte is 0x00 for the mainnet and 0x6F for the testnet.

    • [PubKeyHash] is a 20-byte RIPEMD160 hash of the SHA256 hash of the public key associated with the Bitcoin address.

    • [Checksum] is a 4-byte checksum computed using the first four bytes of the double-SHA256 hash of the serialized script.

    Examples

    P2PKH Bitcoin addresses for mainnet always start with a 1 because the [Version Byte] is 0x00. On testnet, they will always start with either m or, less often, n, because the [Version Byte] is 0x6F.

    Mainnet example P2PKH address: 1PyWzkfKrq1kakvLTeaCdAL8y8UJAcZAqU

    Testnet example P2PKH address: mineSVDRCrSg2gzBRsY4Swb5QHFgdnGkis

    How it Works

    When a user creates a new Bitcoin address, a public key and a corresponding private key are generated. The public key is then hashed, first with SHA256 and then the result is hashed again using the RIPEMD160 algorithm to obtain a 20-byte hash value, which is the PubKeyHash used in the P2PKH output script.

    To send funds to a P2PKH address, the sender creates a transaction that includes an output with the P2PKH output script and the address's PubKeyHash. To spend the funds, the recipient must provide a valid signature that corresponds to the public key associated with the address. The signature is verified using the OP_CHECKSIG opcode in the output script.

    Implementations

    The P2PKH output script is implemented in most Bitcoin wallets and is widely used in the Bitcoin network. There are also many libraries available that provide functions for creating and validating P2PKH transactions.

    {
      "tx": {
        "h": [TRANSACTION HASH],
        "r": [RAW TRANSACTION]
      },
      "blk": {
        "i": [BLOCK INDEX],
        "h": [BLOCK HASH],
        "t": [BLOCK TIME]
      },
      "in": [
        INPUT1,
        INPUT2,
        ...
      ],
      "out": [
        OUTPUT1,
        OUTPUT2,
        ...
      ],
      "coinbase": [COINBASE]
    }
    
    { 
       "index": 136,
       "path": [
    	"6cf512411d03ab9b61643515e7aa9afd005bf29e1052ade95410b3475f02820c",
    	"cd73c0c6bb645581816fa960fd2f1636062fcbf23cb57981074ab8d708a76e3b",
    	"b4c8d919190a090e77b73ffcd52b85babaaeeb62da000473102aca7f070facef",
    	"3470d882cf556a4b943639eba15dc795dffdbebdc98b9a98e3637fda96e3811e"
        ]
    }
    88040c82025f47b31054e9ad52109ef25b00fd9aaae7153564619bab031d4112f56c3b6ea708d7b84a078179b53cf2cb2f0636162ffd60a96f81815564bbc6c073cdefac0f077fca2a10730400da62ebaebaba852bd5fc3fb7770e090a1919d9c8b41e81e396da7f63e3989a8bc9bdbefddf95c75da1eb3936944b6a55cf82d87034
    88 // index VarInt
    04 // nLeaves
    0c82025f47b31054e9ad52109ef25b00fd9aaae7153564619bab031d4112f56c // leaf
    3b6ea708d7b84a078179b53cf2cb2f0636162ffd60a96f81815564bbc6c073cd // etc.
    efac0f077fca2a10730400da62ebaebaba852bd5fc3fb7770e090a1919d9c8b4
    1e81e396da7f63e3989a8bc9bdbefddf95c75da1eb3936944b6a55cf82d87034
    const { Br } = require('bsv')
    const reader = new Br()
    reader.buf = Buffer.from('88040c82025f47b31054e9ad52109ef25b00fd9aaae7153564619bab031d4112f56c3b6ea708d7b84a078179b53cf2cb2f0636162ffd60a96f81815564bbc6c073cdefac0f077fca2a10730400da62ebaebaba852bd5fc3fb7770e090a1919d9c8b41e81e396da7f63e3989a8bc9bdbefddf95c75da1eb3936944b6a55cf82d87034', 'hex')
    
    let merklePath = { path: [] }
    merklePath.index = reader.readVarIntNum()
    let nLeaves = reader.readVarIntNum()
    for (x = 0;x < nLeaves; x++) {
      const leaf = reader.read(32).reverse().toString('hex')
      merklePath.path.push(leaf)
    }
    
    	
    console.log({ merklePath })
    .unlock
      <sig> # The signature used to unlock the script
      <key> # The public key that unlocks the script
    
    .lock
      DUP HASH160 # Duplicate the key and take its hash
      1a98d1ea5702a518b8c4ad9bb736bf34fa9e7291 EQUALVERIFY # Check the hashes are equal
      CHECKSIG # Check that the signature from this key is valid
    OVER 3 SPLIT NIP TRUE SPLIT SWAP SPLIT DROP HASH160 <hash> EQUALVERIFY CHECKSIG
    2 3 ADD 5 EQUAL IF # if 2 + 3 = 5
      'yes' RETURN     # Return 'yes'
    ELSE               # Otherwise
      'no' RETURN      # Return 'no'
    ENDIF              # End
    10334242 # version
    032e5bd6b837cfb30208bbb1d571db9ddf2fb1a7b59fb4ed2a31af632699f770a1 # Sender
    02e5e1a150745253aff65cdbcef722873110d89c396223e3d8715f018e72f7d4f8 # Recipient
    46a897fa6c3b4e1269284f28fb46827dc3a6a88d424f7570aca296e587612c52 # key ID
    7511245c12f83e8e5ad5bd2e536ce33e06cdb76bfb80022830e0976db7866a6607cede3f9b5c95011a0cb04b0816c9c3586f106be31effc73dd8e24d1eca818bc3cdf0f9d330e2696786d375ea8c8bc38ac7f67eb2436eb4daf5c7739047d9d341cdd8eaa10d7f577122726b2ab08ffa8ca88fb2ad2c69f04edcf877a1712c2999f8a85cf94e5ae94a13862d00ec4ffd71782b7ab8b98f8844d0e011cf3843dbb3f763087e3d94693d24d57a9d389aa466bd3779adbe862ba146bbec8ac59991d56a5f2fe282720b42ce058838f0fd577d39a2e2309b4ac765f3cd64b38ed8296bd044641b814000a840fa8c0577d89ff74578c75b4b7883180bf3f994fba623 # ciphertext
    {
      "tm_meter": "./backend/src/topic-managers/MeterTopicManager.ts"
    }
    {
      "schema": "bsv-app",
      "schemaVersion": "1.0",
      "topicManagers": {
        "tm_meter": "./backend/src/topic-managers/MeterTopicManager.ts"
      },
      "lookupServices": {
        "ls_meter": {
          "serviceFactory": "./backend/src/lookup-services/MeterLookupServiceFactory.ts",
          "hydrateWith": "mongo"
        }
      },
      "frontend": {
        "language": "react",
        "sourceDirectory": "./frontend"
      },
      "contracts": {
        "language": "sCrypt",
        "baseDirectory": "./backend"
      },
      "configs": [
        {
          "name": "Local LARS",
          "network": "testnet",
          "provider": "LARS",
          "run": [
            "backend"
          ]
        },
        {
          "name": "production",
          "provider": "CARS",
          "CARSCloudURL": "http://some-cloud.example.com",
          "projectID": "your-project-id",
          "network": "mainnet",
          "deploy": [
            "frontend",
            "backend"
          ],
          "frontendHostingMethod": "HTTPS"
        }
      ]
    }
    "frontend": {
      "language": "react",
      "sourceDirectory": "./frontend"
    }
    "contracts": {
      "language": "sCrypt",
      "baseDirectory": "./backend"
    }
    {
      "name": "Local LARS",
      "network": "testnet",
      "provider": "LARS",
      "run": ["backend"]
    }
    {
      "name": "production",
      "provider": "CARS",
      "CARSCloudURL": "http://cloud.example.com",
      "projectID": "abc123",
      "network": "mainnet",
      "deploy": ["frontend", "backend"],
      "frontendHostingMethod": "HTTPS"
    }
    {
      "schema": "bsv-app",
      "schemaVersion": "1.0",
      "topicManagers": {},
      "lookupServices": {},
      "configs": [
        {
          "name": "Local LARS",
          "provider": "LARS",
          "network": "testnet",
          "run": ["backend"]
        }
      ]
    }
    {
      "schema": "bsv-app",
      "schemaVersion": "1.0",
      "topicManagers": {
        "tm_meter": "./backend/src/topic-managers/MeterTopicManager.ts"
      },
      "lookupServices": {
        "ls_meter": {
          "serviceFactory": "./backend/src/lookup-services/MeterLookupServiceFactory.ts",
          "hydrateWith": "mongo"
        }
      },
      "frontend": {
        "language": "react",
        "sourceDirectory": "./frontend"
      },
      "contracts": {
        "language": "sCrypt",
        "baseDirectory": "./backend"
      },
      "configs": [
        {
          "name": "Local LARS",
          "network": "testnet",
          "provider": "LARS",
          "run": ["backend"]
        },
        {
          "name": "staging",
          "provider": "CARS",
          "CARSCloudURL": "http://staging-cloud.example.com",
          "projectID": "staging-project-id",
          "network": "testnet",
          "deploy": ["frontend", "backend"],
          "frontendHostingMethod": "HTTPS"
        },
        {
          "name": "production",
          "provider": "CARS",
          "CARSCloudURL": "https://cars-cloud.example.com",
          "projectID": "your-production-project-id",
          "network": "mainnet",
          "deploy": ["frontend", "backend"],
          "frontendHostingMethod": "HTTPS"
        }
      ]
    }
    {
      "serviceFactory": "./backend/src/lookup-services/MeterLookupServiceFactory.ts",
      "hydrateWith": "mongo"
    }
    // filename or key is a 32 byte txid in hex
    
    { 
       "index": 12, // JSON Number - technically has no MAX size
       "path": [
          "...leaf of the merkle path", // hex string 32 bytes
          "...leaf of the merkle path",
          "...leaf of the merkle path",
          "...leaf of the merkle path"
       ]
    }
    // fake data example merkle proof
    {
       "txid": "cefffc5415620292081f7e941bb74d11a3188144312c4d7550c462b2a151c64d", 
       "index": 657813,
       "path": [
    	"6cf512411d03ab9b61643515e7aa9afd005bf29e1052ade95410b3475f02820c",
    	"cd73c0c6bb645581816fa960fd2f1636062fcbf23cb57981074ab8d708a76e3b",
    	"b4c8d919190a090e77b73ffcd52b85babaaeeb62da000473102aca7f070facef",
    	"3470d882cf556a4b943639eba15dc795dffdbebdc98b9a98e3637fda96e3811e"
       ]
       "block": {
          "header": {
             "version": 536870912,
             "prevBlockHash": "0000000000000000005d2328b618e043d80d0e5cd33f79b8351965305482cb6b",
             "merkleRoot": "d66e56fb408763e36e8622eb56a8a1072ccc606476fe9e0765cca0dff95949b1",
             "creationTimestamp": 1534851560,
             "difficultyTarget": 402787433,
             "nonce": 3785175761,
          },
          "hash": "000000000000000001fc2f61db1087c820da44599a82bda8ede1f3c82f67098c",
          "work": 2305305885491475308752,
          "height": 544379
       }
    OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
    [Version Byte][PubKeyHash][Checksum]
    Motivation

    The Spec implies that a compatible implementation support the capability to lookup block hash and merkle root values, to confirm that they correspond to actual mined blocks.

    The Project Babbage team has implemented a block header management system called Chaintracks primarily to support validating merkle proofs as defined in the Spec.

    We have a focus on space efficiency as we target the full range of client application deployment scenarios, including mobile and IoT.

    You hear that a full set of block headers is only 50MB and only grows at 4MB per year - and this is true - but it refers to the serialized binary space required for just the headers, without the indices required to implement the Spec.

    Because the required indices are hash values (merkle root and block header hash), which together make up 64 of the 80 block header bytes, it is likely unavoidable that any implementation will be approximately the size of the headers themselves: To turn a hash into a height, the indices must list all the hash values paired with their height values.

    While it is possible to use partial indices and trade index size for IO operations, the indices are not actually needed at all. As Elon says, "the best part is no part."

    Stepping Back: What's the Point of Merkle Proofs?

    The purpose of a merkle proof is to prove that a particular bit of data, a bitcoin transaction, was recorded at a particular location in the block chain.

    The nodes in the proof enable the computation of what the merkle root should be for a block containing the transaction at a particular index position.

    To complete the proof, it must be verified that the computed merkle root matches the actual merkle root of the target block.

    Being given a merkle root value as part of the proof does NOT complete the proof.

    The only thing that completes the proof is to confirm from a trusted copy of block headers that one exists with the computed merkle root value.

    Being given a merkle root, block hash, or block header as part of the proof is only useful as an identifier for which block header to check in the trusted copy. If a matching block header isn't found, the proof is invalid, no matter what additional target values are provided.

    Furthermore, if the trusted copy includes a merkle root index, then proof can be completed directly from the computed merkle root value: Look it up in your own index, if it is found, the proof is valid and the block is identified.

    It is therefore the case, that the existing target and targetType values in a proof per the Spec are unnecessary.

    It may actually be the case, that the only useful targetType would be height. With a height value, no indices are needed at all, the target block header can be found directly since all headers are exactly 80 bytes long. The trusted copy does not require any indices.

    Specification

    1. Add height as a supported targetType

    In "Binary form", proofs reserve two bits of "flags" bytes (bits 1 and 2) to identify what the "JSON form" calls the targetType of the proof.

    Here are the current and proposed values for targetType:

    Name
    Binary Flags Value
    JSON targetType Value
    Binary target format
    JSON target format

    Block Hash

    existing

    0

    'hash' (default)

    32 bytes

    64 hex chars

    Block Header

    2. Deprecate targetType Other Than height

    As discussed in Motivation above, the existing target types and target values are irrelevant to being able to complete a merkle proof given the remaining values.

    Implementations

    The Project Babbage Chaintracks package currently implements the Spec with this extension.

    A comparison of Chaintracks and the Pulse block header packages is listed under References.

    References

    • The "Spec": TSC Merkle proof standardised format

    • Bitcoin VarInt

    • Review of Pulse and Comparison With Chaintracks

    TSC Merkle proof standardised format
    Motivation

    The use of Bitcoin as a means of payment and store of value has gained significant traction in recent years. As the adoption of Bitcoin continues to increase, there is a need for a standard format for the envelopes that contain Bitcoin transactions. The lack of a standardized format for envelopes can lead to interoperability issues and hinder the development of new Bitcoin-native applications.

    The SPV process, outlined in BRC-9, allows payment recipients to verify the validity of a transaction without downloading and verifying the entire blockchain. However, without a standard methodology for exchanging the required merkle proofs and input transactions, applications and businesses are unable to fully benefit from adopting SPV. BRC-8 addresses this issue by providing a consistent format for transaction envelopes that can be used for SPV.

    Specification:

    We specify that the Everett-style Transaction Envelope is a JSON object that consists of the following fields:

    • rawTx (required): The BRC-12 hex transaction contained in the envelope in serialized hex string format.

    • inputs (required unless proof is provided): An object whose keys are TXIDs of each of the outpoints spent by the transaction. The values are objects containing:

      • rawTx (required): The transaction that was spent in serialized hex string format.

      • proof (required unless inputs is provided): If the transaction is confirmed in a block, the SPV proof of the transaction's inclusion is given in format as a JSON object.

      • mapiResponses (optional): An array of signed mAPI response objects, each of which is an object conforming to the mAPI specifications (either a successful broadcast acknowledgment or an affirmative status response).

      • inputs (optional): If the transaction is not yet confirmed in a block, this field is the same as the field from the root object, except referring to the previous transaction instead of the root transaction. The field nests recursively back in the tree of the previous unconfirmed transactions until each of the branches can ultimately be traced back to the chain of blocks with a proof at the end.

    • proof (optional): If the root transaction in the envelope is already confirmed in a block, the SPV proof of the transaction’s inclusion is given in format as a JSON object.

    • mapiResponses (optional): An array of signed mAPI response objects, each of which is an object conforming to the mAPI specifications (either a successful broadcast acknowledgment or an affirmative status response).

    • headers (optional): An array of 80-byte block header strings in hex format, starting with the block after the recipient's latest known block (indicated and communicated out-of-band) and ending with the latest header known to the sender.

    • pruned: true (optional): Indicates references to the same TXID are omitted in the inputs object, known as deduplication.

    The inputs object is required unless the proof field is provided for the transaction. The inputs object can be used to create a tree data structure that nests recursively back in the tree of the previous unconfirmed transactions until each of the branches can ultimately be traced back to the chain of blocks with a proof at the end. The inputs object is optional when the transaction is already confirmed in a block and proof field is provided. The proof field serves as the proof of the transaction's inclusion in a block and is given in BRC-10 format as a JSON object.

    The mapiResponses field is an array of signed mAPI response objects that are optional as per this specification, but may be required by higher-layer payment protocols such as BRC-29. If included, it should be omitted if proof is given. mAPI responses provide assurance that the transaction has been accepted and broadcast to multiple miners, making double-spend attacks harder to achieve.

    The headers field is an optional array of 80-byte block header strings in hex format. This field can be omitted if no new headers are necessary for verification. The mechanism by which the parties negotiate about which headers are to be provided is beyond the scope of this specification.

    Tree Structure

    The Everett-style Transaction Envelope uses a tree structure instead of a flat list structure to avoid providing information for the same transaction more than once. The tree structure has advantages as it can easily be validated with a simple recursive function, allowing parallelized processing of nodes further back in the tree at the same time as parents without needing to keep and reference a copy of the entire envelope while validating each node. This approach also allows for a degree of modularity because each node in the tree is itself a fully-valid envelope, and there is no need to re-scan and re-calculate which other transactions would be required to get a valid sub-envelope (very efficient for adding/removing/working with chains of dependent transactions).

    A special case can be added when nodes at different depths in the tree depend on a common transaction, to remove tree-level duplications. The first time a transaction appears, it can be included as normal. Subsequent references to the same TXID can be omitted where they appear in the inputs object. To indicate that an envelope has been deduplicated in this way, the root object MUST contain pruned: true. With the issue of duplication solved, we believe a tree structure is the most intuitive and efficient approach.

    The use of mAPI is optional and can be disabled by those who do not wish to use it in their implementations. Disabling mAPI allows “receiver-only broadcast” implementations to work. By not allowing mAPI as part of the data structure, the control is taken away from application developers and stakeholders who have widely varying requirements.

    Extensions and Added Fields

    There are a wide array of potential applications, higher-layer payment protocols and use-cases for these envelopes. We stipulate that many systems will append (or even remove) certain fields from various nodes in these structures. This specification defines a baseline, and deviations from this baseline need only be documented by other standards which inherit from this one, such as BRC-29.

    Implementations

    A web tool has been implemented which, given any TXID, will produce a valid Everett-style Transaction Envelope.

    Developers are encouraged to create their own implementations and contribute to the ecosystem by sharing their work with the community. By doing so, they can help improve the interoperability between different Bitcoin wallet software and services, and further promote the adoption of the BRC-8 standard.

    In addition to the web tool, developers should consult the BRC-9 and BRC-10 specifications for more information on implementing the Simplified Payment Verification (SPV) process and the format for SPV proofs, respectively. By adhering to these specifications, developers can ensure their implementations are compatible with existing and future Bitcoin wallet software and services that also follow the BRC standards.

    Future Work

    While this standard provides a solid foundation for Everett-style Transaction Envelopes, there is always room for improvement and expansion. Future work could include:

    • Developing more efficient algorithms for constructing and validating the tree structure of transaction envelopes.

    • Expanding on the negotiation process for providing block headers, making it more seamless and efficient.

    • Creating additional tools and libraries to simplify the implementation of the BRC-8 standard in various programming languages and platforms.

    • Defining higher-layer protocols for live-updating non-final transactions, peer-to-peer data exchange, and efficient tree state reconciliation.

    BRC-9
    Motivation

    The internet today has an increasingly complex landscape of entities that users may or may not trust. As systems decentralize, the need to independently verify the identity of a digital entity becomes vital. By allowing entities to publish trust details at known locations (their domains), users are provided with a recognizable and straightforward method to retrieve and validate their public keys, hence building a more trustable web.

    Specification

    Location & Protocol

    1. The trust anchor details MUST be published in a file named manifest.json.

    2. The manifest.json file MUST be hosted using the HTTPS protocol. Plain HTTP is not supported.

    3. Only Fully Qualified Domain Names (FQDNs) are supported for hosting the manifest.json file.

    Data Structure

    The trust details should be stored under the key babbage in the manifest.json file. Under the babbage key, the trust object should be defined with the following properties:

    • name: The human-readable name of the entity.

    • note: A brief note describing the role or function of the entity.

    • icon: A URL pointing to an icon image representing the entity.

    • publicKey: The public key of the entity in hexadecimal format.

    Validation Rules

    1. name

      • MUST be a string.

      • MUST contain between 5 to 30 characters, inclusive.

    2. note

      • MUST be a string.

      • MUST contain between 5 to 50 characters, inclusive.

    3. icon

      • MUST be a valid image URL.

      • Should be accessed over HTTPS.

    4. publicKey

      • MUST be a string in DER format.

      • MUST be compressed.

      • MUST use the secp256k1 elliptic curve.

    Examples

    Here is a valid example of a manifest.json containing the trust anchor details:

    For this example:

    • name is "SigniCert", which has a length between 5 and 30 characters.

    • note has a length between 5 and 50 characters.

    • icon points to an image hosted over HTTPS.

    • publicKey is a compressed DER-encoded key using the secp256k1 curve, starting with "02" and is 66 characters long.

    Conclusion

    This technical specification provides a comprehensive framework for entities to publish trust anchor details at a known internet domain. By adhering to the defined structure and validation rules, we ensure a standardized method for users to access and trust these details. This is a step towards creating a more transparent and trustable digital landscape.

    Pay to R Puzzle Hash

    Ty Everett ([email protected])

    Abstract

    The R-puzzle technique is a powerful cryptographic tool that can be used to create Bitcoin output scripts that can be unlocked by anyone who is able to solve for a value k, without revealing k to the world. The technique relies on the fact that in an ECDSA digital signature, the R component is computed by multiplying a generator point on the elliptic curve with this k-value. By constructing a Bitcoin output script that requires knowledge of this value, it is possible to create puzzles that can be solved by anyone who is able to compute the correct value for k. The R-puzzle technique is flexible and can be used for a variety of applications, including those that benefit when the solver does not reveal their solution to the world, only proving knowledge of it. R-puzzles also provide a way to create Bitcoin output scripts that can be unlocked without requiring knowledge of a specific private key, while still maintaining a high level of security and cryptographic strength. By serializing short-hand script templates in a standard way, implementers can maintain ecosystem-wide compatibility.

    Motivation

    The creation of puzzles that can be unlocked by anyone who is able to solve a complex problem has become increasingly popular in recent years, particularly in the field of distributed computing. However, it is important to ensure that these puzzles are designed in such a way that they maintain a high level of security and cryptographic strength, while still allowing anyone to solve them without revealing any sensitive information.

    To achieve this, it is valuable to create a script template that enables the solver to prove knowledge over a value, k, without revealing the k-value to the world. This provides a way to create puzzles that are secure and difficult to solve, while still allowing anyone to claim the solution and the associated rewards. In addition, it is desirable to employ a script template that does not require the creator of the puzzle to know which key will be used by the solver in claiming the solution, at the time the puzzle was created. Finally, there is also a need to standardize the way these scripts are expressed and exchanged between users of the Bitcoin network, to enable greater cross-compatibility and wider adoption.

    Specification

    We specify the following Bitcoin script template for R-puzzles:

    We specify that the same private key and k-value must NEVER EVER be used, and that steps MUST be taken to prevent the same private key and k-value from ever being used to sign different messages in ECDSA. Failure to follow this provision will result in leakage of private keys and k-values.

    Serialization Format (Base58)

    We specify that the P2RPH output script is serialized using Base58 encoding. The serialized format is as follows:

    Where:

    • [Version Bytes] is a prefix that identifies the network and the script type. The value of the version byte is 0x0e00 for the mainnet and 0x1c00 for the testnet.

    • [PubKeyHash] is a 20-byte RIPEMD160 hash of the SHA256 hash of the R-value.

    Examples

    P2RPH Bitcoin addresses for mainnet always start with an R because the [Version Bytes] we selected are 0x0e00. On testnet, they will always start with lowercase r because the [Version Bytes] are 0x1c00.

    Mainnet example P2RPH address: RsQphNVccTzET8zwMNESLmTeJ4cJYxyc9cx

    Testnet example P2RPH address: rjQPANNiecDK1a6jedyCsQ6UND4SnK6rJNe

    How it Works

    The locking script is the script that is attached to the Bitcoin output that is being locked with the R-puzzle. When a Bitcoin transaction is created that spends this output, the unlocking script must provide the correct input to satisfy this locking script.

    The locking script essentially creates a puzzle that can only be unlocked by providing an ECDSA digital signature that satisfies certain conditions. Specifically, the signature must have an R component that, when hashed with SHA256 and then RIPEMD160, produces the same value as the <hash> specified in the script. The S component of the signature can be computed using any key of the solver's choosing.

    The unlocking script essentially satisfies the conditions set out by the locking script by providing a valid ECDSA digital signature with an R component that matches the hash specified in the locking script, and an S component that is computed using the solver's chosen private key.

    The locking and unlocking scripts for the R-puzzle comprise a powerful and flexible tool for creating puzzles that can be solved by anyone who is able to compute the correct value for the k parameter used in the ECDSA digital signature. By using this technique, it is possible to create Bitcoin outputs that can be unlocked by anyone who is able to solve the puzzle, without requiring knowledge of a specific private key.

    Security Considerations

    It is crucial to emphasize the importance of never using the same private key and k-value for different messages in ECDSA. Doing so can compromise the security of the digital signatures and result in the leakage of private keys and k-values, which can lead to the loss of funds or assets associated with those signatures.

    Therefore, it is essential to take steps to ensure that private keys and k-values are never reused. One way to achieve this is by using a secure random number generator to generate new values for each signature. It is also important to store private keys securely and to use secure communication channels when transmitting them.

    To further emphasize the importance of this provision, it is advisable to include clear warnings and instructions in any documentation or educational material related to the R-puzzle technique. This will help ensure that users understand the potential risks of reusing private keys and k-values and take the necessary precautions to prevent such incidents from occurring.

    Implementations

    The first-known implementation for R-puzzles was created by .

    Message Signature Creation and Verification

    Ty Everett ([email protected])

    Abstract

    This document defines a protocol for creating and verifying digital message signatures in the Bitcoin ecosystem. It leverages the BRC-42 key derivation and BRC-43 invoice numbers to facilitate privately-verifiable signatures, increasing security and privacy in Bitcoin message interactions.

    Motivation

    While Bitcoin Signed Messages (BSM) offer a simplistic solution for digitally signing Bitcoin messages, they lack capabilities for privately-verifiable signatures and they re-use keys, potentially compromising security and privacy. By incorporating BRC-42 key derivation, this standard enhances the security and private signing capabilities, providing a robust and unified standard for the Bitcoin ecosystem. Private signing enables a specific verifier to check the signature, without revealing its validity to the rest of the world.

    Scope

    The scope of this specification is to convey a message signature. The message data (the thing being signed) is not serialized as part of this signature structure.

    One notable aspect of BSM is the need to prefix all messages with "Bitcoin signed message" to avoid inadvertently signing a Bitcoin transaction. However, since the new approach utilizes a new signing key for each message, there is no danger of signing Bitcoin transactions with a key capable of spending locked coins.

    Specification

    The protocol employs the BRC-3 digital signature process and makes use of the BRC-42 key derivation and BRC-43 invoice numbering scheme.

    We specify message signing as the BRC-43 protocol ID, with security level 2. We specify that the signer generates a random 256-bit value to be used as the key ID when the signature is computed for a given counterparty.

    The system operates in the following way:

    1. Message sender computes the BRC-43 invoice number based on the security level (2), protocol ID (message signing), and their 256-bit key ID. We specify the key ID is in base64 format when added to the invoice number.

    2. Message sender derives a child private key for the counterparty (or anyone) with the computed invoice number using the BRC-42 key derivation process.

    3. Message sender then computes the digital signature using the ECDSA with the derived private key.

    Serialization format

    The standard serialization format encapsulates all the necessary information required for message verification into a binary representation. The format starts with a version number, followed by the identity key of the signer, the identity key of the recipient (or 0x00 to represent anyone if it's publicly verifiable), the 256-bit key ID used for the signature, and the ECDSA signature over the message. This structure ensures a standardized way for efficiently and securely transmitting and verifying signatures:

    Field
    Field Length
    Description

    Hex Examples

    Scalable Transaction Processing in the BSV Network

    Ty Everett ([email protected])

    Abstract

    The BSV network is designed to process transactions at scale, leveraging a robust, distributed system of miners, validators, and aggregators. This system balances parallel processing with sequential validation, ensuring transactions are both processed rapidly and recorded in the correct order. Below, we document the detailed processes by which BSV miners will come to handle transactions at scale.

    1. Transaction Submission

    Users and services across the globe create and sign Bitcoin transactions, broadcasting them to the network. The network's miners collect these transactions at numerous Points of Presence (PoPs), which act as edge nodes in the BSV ecosystem. The following steps outline the process:

    • Preliminary Checks: Upon receiving a transaction, miners at PoPs verify its scripts, ensuring they comply with network standards and contain valid signatures. If valid, the transaction proceeds to the next stage.

    • Batching: After initial verification, the miners batch transactions, preparing them for forwarding to regional aggregators. This batching process occurs periodically, facilitating efficient transfer and further processing.

    2. Transaction Stripping

    After initial verification, transactions undergo a stripping process, which reduces each transaction to its essential elements:

    • Stripped Data: The remaining data includes:

      • The TXID and output indices of the consumed outputs.

      • The TXID of the transaction itself.

      • The number of new outputs it creates.

    3. Edge-Level Stripped Transaction Graph Summarization

    Where possible, edge validators summarize stripped transaction graphs before sending them to regional aggregators. This process is crucial in reducing the workload of higher-level aggregators:

    • Internal Transactions: The summarized graph only needs to include:

      • The TXIDs and output indices of previously consumed outputs.

      • The newly created outputs.

      • A merkle root for the transactions it includes.

    4. Regional Aggregation

    After receiving stripped transactions and summarized graphs, regional aggregators build subtrees of transactions:

    • Subtree Formation: Subtrees are groups of transactions or graphs, each forming a summarized graph with a merkle root and lists of outputs consumed and created.

    • Multi-Level Aggregation: Multiple levels of regional aggregation may occur in parallel, gradually integrating more of the completed transaction graph into larger structures.

    • Fee Tracking: Fees from child graphs are aggregated to track the total fees collected by the parent graph.

    5. Global Aggregation and Block Assembly

    Regional aggregators send subtree summaries to global aggregation systems, which then prepare the final block:

    • Graph Consistency: The system checks graph edges for consistency, ensuring no edge is consumed by one graph before being created by another.

    • Block Template: The block assembler combines these subtrees, including the coinbase transaction with the correct amount of fees, forming a finalized block template ready for hashing.

    • Proof of Work: Upon finding a valid proof-of-work header, the new block header is immediately propagated throughout the network for parallel validation by all systems.

    6. Proof Completion

    Once a valid header is found, it triggers a cascading parallel proof completion process:

    • Downstream Propagation: The header propagates down to all regional aggregators, who append the upper layers of the merkle tree to their subgraph roots.

    • Notifier Chain: Each regional aggregator notifies its child aggregators or edge validators, which in turn notify their children. This chain of notifications continues until all edge validators have completed proofs for all transactions they submitted.

    • End-User Notification: Finally, edge validators notify network end-users of the completed proofs available for their transactions.

    7. Summary

    The BSV network effectively balances parallel processing and sequential validation to achieve scalable transaction processing. By employing edge-level validation, regional aggregation, and global assembly, the system reduces the workload at higher levels, ensuring rapid, consistent processing. This layered, hierarchical approach to aggregation, alongside the use of transaction stripping and summarization, makes the BSV network a robust solution for scalable blockchain processing.

    8. Future Work: Modeling the BSV Network

    To model and describe the BSV network quantitatively, it is essential to focus on the parameters and metrics that influence the performance and scalability of the system. Here are some key components and steps to construct a quantitative model of the BSV transaction processing system:

    8.1. Parameters and Metrics

    Key Parameters

    • Transaction Arrival Rate: The rate at which transactions are received at edge nodes, typically expressed in transactions per second (tps).

    • Batch Size: The number of transactions processed together in batches at edge nodes before being sent to regional aggregators.

    • Transaction Processing Time: Time taken to verify and strip a single transaction.

    • Propagation Delay

    Performance Metrics

    • Throughput: The total number of transactions processed per unit time across the network.

    • Latency: The total time taken from when a transaction is submitted until it is included in a validated block.

    • Resource Utilization: Measures how efficiently resources (computational, bandwidth) are used.

    • Scalability: The ability of the network to handle increasing transaction loads without a proportional increase in latency or resource costs.

    8.2. Modeling Steps

    Step 1: Transaction Input Modeling

    • Model the transaction inputs as a Poisson process or another suitable stochastic process that reflects real-world arrival patterns.

    Step 2: Process Modeling at Edge Nodes

    • Model the batch processing as a queue where transactions are collected, verified, and stripped. Queuing theory, specifically a batch service queue model, can be applied here.

    • Calculate the processing rate of batches based on the transaction processing time and batch size.

    Step 3: Summarization and Aggregation Modeling

    • Use a hierarchical tree model to represent the multi-level aggregation process. Each node in the tree represents an aggregation point (edge, regional, global).

    • Model the propagation of transaction summaries through this tree, accounting for delays and processing times at each node.

    Step 4: Block Assembly and Propagation

    • Model the final block assembly as a sequential process that only begins once all necessary summaries and proofs are available.

    • Consider the proof-of-work process and its impact on block propagation and finality.

    Step 5: Analytical Model Construction

    • Construct a series of equations or a simulation model that integrates these components. For example, use differential equations to represent the rate of change in the queue sizes, or develop a discrete-event simulation to model the dynamic interactions and delays.

    Step 6: Validation and Simulation

    • Validate the model against real data or simulated data to ensure it accurately represents the BSV network's behavior.

    • Use the model to simulate different scenarios, such as increased transaction loads, changes in batch sizes, or different network delays, to study their impacts on throughput, latency, and scalability.

    8.3. Utilizing the Model

    • Optimization: Use the model to find optimal parameters (e.g., batch size, number of edge nodes) that maximize throughput or minimize latency.

    • Capacity Planning: Estimate the resources needed to achieve certain performance metrics under expected future loads.

    • Scenario Analysis: Assess the impact of network changes or growth on performance and resource needs.

    By quantitatively modeling these processes, the BSV network's design and operation can be better understood, optimized, and scaled to meet the demands of a high-volume, real-time transaction processing environment.

    Atomic BEEF Transactions

    Ty Everett ([email protected])

    Abstract

    This BRC defines Atomic Background Evaluation Extended Format (Atomic BEEF) Transactions, a variant of the BEEF transaction format (as defined in BRC-62) that focuses on atomicity—specifically, ensuring that all the data within a BEEF structure relates to a single "subject transaction." This format disallows unrelated transactions within the BEEF structure, reinforcing a clear, minimalistic data set for transaction validation while maintaining efficiency in bandwidth usage.

    Atomic BEEF is designed to solve problems arising from multiple graphs of unrelated transactions being aggregated into a single BEEF, which can complicate validation and increase data complexity. Atomic BEEF introduces a strict structure optimized for single-transaction use cases, ensuring that every transaction in the BEEF relates to a defined subject transaction. This format is particularly suited for applications where the verification of a singular transaction and its direct ancestry is critical.

    Motivation

    The introduction of the BEEF format (BRC-62) provided a solution for transmitting transaction data in a binary format to allow (SPV) with minimal bandwidth. However, BEEF allows the inclusion of multiple, potentially unrelated transactions aggregated within the same structure, making it flexible but not ideal for cases where strict atomicity is needed.

    Atomic BEEF is motivated by the following challenges:

    1. Transaction Ambiguity: In BEEF, there is no explicit constraint to keep transactions related to a single subject transaction. This can lead to ambiguity when unrelated transaction graphs are included in the same BEEF structure, making validation and verification more complex.

    2. Simplified Use Cases: Many use cases of SPV revolve around validating a single payment or transaction, not multiple. Atomic BEEF optimizes for this by focusing entirely on the recursive transaction graph relevant to a specific transaction.

    3. Data Minimalism: For micropayments or systems requiring highly efficient data transfer, limiting the number of transactions included in the BEEF to only the required set for validation of a single subject transaction reduces unnecessary overhead.

    In response to these motivations, Atomic BEEF introduces a new mechanism for enforcing the atomicity of BEEF transactions.

    Specification

    Atomic BEEF is an extension of BEEF (BRC-62) with specific structural and validation rules that ensure atomicity. It adheres to the same encoding and transaction structure principles, with the following additional constraints:

    Header Structure

    Atomic BEEF introduces a unique header prefix that ensures the atomicity of the BEEF structure. The Atomic BEEF format starts with a constant prefix followed by the TXID of the "subject transaction." This TXID serves as the reference transaction that the entire BEEF structure must relate to.

    • Prefix: The first 4 bytes of the Atomic BEEF structure must be 0x01010101, a fixed constant to indicate Atomic BEEF.

    • Subject TXID: The next 32 bytes are the TXID of the "subject transaction"—the primary transaction that the rest of the structure must validate and verify.

    Field
    Description
    Size

    Transaction Inclusion Rules

    Atomic BEEF strictly enforces that all transactions included in the structure must be part of the subject transaction's dependency graph. This means that every transaction in the BEEF structure must either be:

    1. The subject transaction itself, or

    2. An ancestor transaction required to validate the inputs of the subject transaction.

    Transactions that fall outside of this graph, or are unrelated, are not allowed in Atomic BEEF. This ensures that the BEEF is entirely focused on a single, verifiable transaction and its direct dependencies.

    Validation Process

    The validation of an Atomic BEEF structure follows these steps:

    1. Subject Transaction Identification:

      • The first step in validation is to extract the subject TXID from the header. If the BEEF structure does not include the subject transaction or if any unrelated transactions are present, the validation fails.

    2. Transaction Graph Validation:

    Error Conditions

    Atomic BEEF introduces two specific error conditions that must cause validation to fail:

    1. Missing Subject Transaction: If the BEEF structure does not include the subject transaction identified by the subject TXID in the header, validation fails.

    2. Unrelated Transactions: If any transactions within the BEEF structure fall outside the dependency graph of the subject transaction, validation fails.

    These error conditions ensure that Atomic BEEF maintains strict atomicity and avoids the ambiguity and complexity of unrelated transactions within the same structure.

    Bytewise Breakdown:

    Digital Signature Creation and Verification

    Ty Everett ([email protected])

    Abstract

    We define a mechanism for requesting and receiving digital signatures over the abstract communications channel first described by . We rely on the invoice numbering and permission scheme on top of for key derivation, enabling the creation of private digital signatures that can only be verified by the counterparty. A signer derives their own child private key and uses it to compute an ECDSA signature, which is then communicated to the verified, together with the signer's identity key, the message, and the protocol ID and key ID used. The verifier uses this information to derive the corresponding child public key for the signer, which is then checked against the signature and message with ECDSA. Without the shared secret, no third parties can discover the correct child public key, making then unable to validate the signature.

    Window Wallet Communication Substrate

    Brayden Langley ([email protected])

    Abstract

    The Window Wallet Communication Substrate is a standardized interface that enables seamless integration between web applications and browser embedded Bitcoin wallets. It serves as a unified gateway for applications to access various wallet functionalities, including the creation of Bitcoin transactions, encryption, digital signature creation, and more. By establishing this standardized interface, applications gain the ability to support multiple wallet providers, enhancing flexibility and choice for users in managing their Bitcoin-related tasks. This interface empowers users with greater control and accessibility while maintaining compatibility across different applications and wallets.

    Simple Authenticated BSV P2PKH Payment Protocol

    Ty Everett ([email protected])

    Abstract

    This BRC specifies a protocol for exchanging simple P2PKH payments between a sender and a recipient in a way that is SPV-compliant and cross-compatible. The protocol makes use of key derivation to derive public and private keys between users, transaction envelopes to relay SPV-related information between the sender and the recipient, and a SPV implementation to enable the recipient to obtain confidence that the transactions are valid and legitimate. This BRC specifies the JSON version of the payment message format used by the sender when exchanging the payment with the recipient, and the steps and processes involved in constructing and validating a payment message.

    Proven Identity Key Exchange (PIKE)

    Darren Kellenschwiler ([email protected]) Damian Orzepowski ([email protected])

    Abstract

    Allowing humans to securely exchange public keys using web apis and an off channel sharing of TOTPs.

    Submitting Received Payments to a Wallet

    Brayden Langley ([email protected])

    Abstract

    To ensure a seamless process for submitting payments to a wallet, there must be a standardized method by which this process takes place. Wallets that implement this standard will be able to support the direct submission of transactions from applications to a user's wallet along with the associated SPV information as defined by . The required message structure and fields are defined below in the section, and the expected response to provide is defined in the section. Wallets that choose to implement this specification will allow applications that facilitate the exchange of payments to be built in a way that is interoperable, extensible, and SPV compliant.

    {
      "name": "SigniCert",
      "babbage": {
        "trust": {
          "name": "SigniCert",
          "note": "Certifies legal first and last name, and photos",
          "icon": "https://signia.babbage.systems/images/signiaIcon.png",
          "publicKey": "0295bf1c7842d14babf60daf2c733956c331f9dcb2c79e41f85fd1dda6a3fa4549"
        }
      }
    }

    The string should start with either "02" or "03".

  • MUST be in hexadecimal format, and 66 characters in length (including the starting "02" or "03").

  • Graph Representation: The stripped transaction thus forms a node in the transaction graph, containing only the necessary information to link it to other transactions.

    The total amount of fees left for the miners.

  • Merkle Paths: The summarized graph also contains partial merkle paths, linking all transactions or child graphs to the merkle root of the summarized graph. However, this information only needs to be retained locally and never shared upwards.

  • : The time it takes for information to travel from the edge nodes to the regional and global aggregators.
  • Aggregation Time: Time required to aggregate transactions into subtrees and summarize them into merkle roots at various levels (edge, regional, global).

  • existing

    1

    'header'

    80 bytes

    160 hex chars

    Merkle Root

    existing

    2

    'merkleRoot'

    32 bytes

    64 hex chars

    Height

    new

    3

    'height'

    Bitcoin VarInt

    integer

    BRC-10
    BRC-10
    [Checksum]
    is a 4-byte checksum computed using the first four bytes of the double-SHA256 hash of the serialized script.
    Dean Little
  • Message sender serializes their own public key, the recipient public key, the selected key ID, and the ECDSA signature according to the serialization format below.

  • A message recipient can then deserialize the structure to learn the sender's public key and the correct key ID for verification.

  • The recipient can then use their own private key, the public key of the sender, and the computed invoice number to verify the signature over the message.

  • 32 bytes

    The specific key ID used for the signature

    Signature

    Variable

    The ECDSA signature of the message, in DER format

    Version

    4 bytes

    Defines the version of the standard used. Currently 0x42423301

    Signer ID

    33 bytes

    Identity key of the signer (DER, compressed)

    Verifier ID

    1 or 33 bytes

    Identity key of the recipient (DER, compressed), or 0x00 if anyone

    Key ID

    Streamlined Validation: By restricting the BEEF to a single subject transaction and its dependencies, Atomic BEEF reduces the complexity of the validation process, as there is a clear expectation of the data's scope.

    The BEEF structure must contain all transactions necessary to validate the subject transaction, recursively including all ancestor transactions up to the point where each input can be confirmed with a Merkle proof.
  • The structure must not contain any transactions that are not part of the subject transaction's dependency graph.

  • Merkle Proof Validation:

    • As with the original BEEF format, any included transactions that have been mined must be accompanied by BSV Universal Merkle Path (BUMP) data to prove their inclusion in the longest chain of blocks.

    • The Merkle roots derived from the BUMP data are verified against the local header service.

  • Final Transaction Validation:

    • The final validation is complete when all necessary transactions (including script evaluations) and proofs have been processed, and the subject transaction is confirmed to be valid based on its dependencies.

  • Atomic Prefix

    Fixed constant 0x01010101, indicates the start of an Atomic BEEF structure

    4 bytes

    Subject TXID

    The TXID of the subject transaction that this BEEF structure will validate

    32 bytes

    Simplified Payment Verification
    Motivation

    When you use hosted servers for payment output generation there's no way to detect if the host has been compromised and is sharing keys not associated with the intended recipient.

    BRFCID

    A random ID was generated in order to avoid label collisions in the capability document of a paymail server.

    Specification

    Roughly speaking you create a shared secret between you and the counterparty using their public key and your private key. If you each do this you can arrive at a shared secret. You then derive a time hashed one time pass code to prove you both have the same value - each sharing the TOTP and validating the counterparty's. Thereafter you can use that public key knowing that it really is that counterparty without fear of MITM attacks.

    Implementations

    SPV Wallet

    Flow

    1. Sender wallet: generate random hash

    2. Sender wallet generate public key from private key and random hash

    3. Sender wallet is sending "add contact request" to Sender BUX containing: a. contact paymail address b. random hash c. generated public key

    4. Sender BUX is performing Paymail host discovery (which is described on this page: https://tsc.bsvblockchain.org/standards/paymail/#ServiceDiscovery)

    5. Sender BUX is performing Paymail capability discovery on Receiver BUX by requesting /.well-known/bsvalias

    6. If Receiver BUX doesn't contain Proven Identity Key Exchange (PIKE) capability, Sender BUX should return an error to Sender Wallet

    7. else the Sender BUX is sending a "Add a contact" request to Receiver BUX on the endpoint provided in PIKE capability. This request contains: a. sender paymail address b. random hash c. generated public key

    8. Receiver BUX stores that "contact" as "waiting" in database

    9. Receiver BUX is answering to Sender BUX with success

    10. Sender BUX is storing the "contact" as "waiting"

    11. Receiver Wallet asks Receiver BUX for "waiting" "contact" to confirm or reject

    12. Receiver BUX is responding with the list of contacts

    13. If Receiver Wallet reject the contact, then: a. it is sending rejection request to Receiver BUX b. Receiver BUX is removing the contact from database c. In that case the flow ends

    14. else: Receiver Wallet generate public key from private key and random hash from the contact

    15. Receiver Wallet is sending the request for Receiver BUX for accepting the contact with informations: a. paymail address for contact to accept b. generated public key

    16. Receiver BUX is marking a "contact" as "accepted"

    17. Receiver BUX is sending the "contact accepted" request to Sender BUX with: a. paymail address of Receiver b. generated public key c. random hash

    18. Sender BUX is validating random hash, and stores received public key in "contact" and marks it as accepted

    19. Sender Wallet is asking Sender to confirm contact

    20. Sender asks Receiver for TOTP

    21. Receiver checks TOTP for Senders paymail in Receiver Wallet

    22. Receiver Wallet calculates shared secret based on private key and Senders public key

    23. Receiver Wallet generates TOTP based on shared secret

    24. Receiver Wallet sends back TOTP to Receiver

    25. Receiver is responding with TOTP to Sender

    26. Sender is providing TOTP to Sender Wallet

    27. Sender Wallet calculates shared secret based on private key and Receiver public key

    28. Sender Wallet generates TOTP based on shared secret

    29. Sender Wallet is comparing received TOTP with generated TOTP. If their match then it marks contact as confirmed.

    30. Sender Wallet is now generating another TOTP and provides to Sender

    31. Sender is providing TOTP to Receiver

    32. Receiver is providing TOTP to Receiver Wallet

    33. Receiver Wallet is generating TOTP and comparing it with received TOTP If their match then it marks contact as confirmed.

    .unlock
      <ECDSA sig>              # This is the first stack element and represents the ECDSA digital signature provided by the 
                               # solver. It must have an R component that, when hashed with SHA256 and then RIPEMD160, 
                               # produces the same value as the <hash> specified in the locking script. The S component can 
                               # be computed using any key of the solver's choosing.
      <key>                    # This is the second stack element and represents the private key that was used to compute the S component of the 
                               # signature. It can be any key of the solver's choosing, as long as it produces a valid S component for the signature that 
                               # was provided as the first stack element.
    
    .lock
      OVER                     # Duplicates the second stack element (the signature) so that it can be used later in the script. Now the stack has 
                               # three elements, <signature> <key> <signature> and we can work with the top <signature> without bothering the bottom one.
      3 SPLIT                  #
      NIP                      #
      TRUE SPLIT               # This section of the script picks out the R-value from the signature.
      SWAP                     #
      SPLIT                    #
      DROP                     # 
      HASH160                  # Here, we hash the R-value with SHA256 and then again with RIPEMD160 (the combined operation is HASH160).
      <hash> EQUALVERIFY       # The hash we calculated in the previous step is compared with <hash> and if they are not equal then the script fails.
      CHECKSIG                 # Finally, the ECDSA signature is checked.
    [Version Bytes][RPuzzleHash][Checksum]
    42423301 # version
    032e5bd6b837cfb30208bbb1d571db9ddf2fb1a7b59fb4ed2a31af632699f770a1 # signer
    02e5e1a150745253aff65cdbcef722873110d89c396223e3d8715f018e72f7d4f8 # verifier
    8166f775e9128dfea9ddb8fc92c655cfaae6795e18911d7d1b6d981ac8664e36 # key ID
    30450221009fd5c15bb289bd3a26454131b269b4f550f32dca4c21fde29cef3ebaa913363c022052d421eae633c363b1dad674a1da4821c885425cc636147388b8b08b439721be # signature
    42423301 # version
    032e5bd6b837cfb30208bbb1d571db9ddf2fb1a7b59fb4ed2a31af632699f770a1 # signer
    00 # verifier (anyone)
    e8ff1624ede8d6ca5303badb68dec8f226284385bed3bc7c19b578a905866587 # key ID
    3045022100b304d38e25106c732f0247fab70b9cf47d5434c08d7a94ef4ad7069bae9a9a0e02202f4e3b4e5d7d698cfebe64f643dbcddc1631e6f09aece0850613f602ec4d50e6 # signature
    01010101 // Atomic BEEF Prefix
    2222222222222222222222222222222222222222222222222222222222222222 // Subject TXID
    0100beef // Start of standard BEEF structure...
    ...
    brfcid: 8c4ed5ef8ace
    title: Proven Identity Key Exchange (PIKE)
    author: Darren Kellenschwiler, Damian Orzepowski
    version: 1.0.0
    sequenceDiagram
    actor Sender
    participant Sender Wallet
    participant Sender BUX
    participant Receiver BUX
    participant Receiver Wallet
    actor Receiver
    
        Sender->>Sender Wallet: Add receiver as contact
        activate Sender Wallet
        Sender Wallet->>Sender Wallet: Generate random hash
        Sender Wallet->>Sender Wallet: Generate public key from private key and random hash
        deactivate Sender Wallet
        activate Sender Wallet
        Sender Wallet->>Sender BUX: Add contact request
        activate Sender BUX
        Sender BUX->>Sender BUX: Paymail host discovery
        Sender BUX->>Receiver BUX: Paymail capability discovery
        activate Receiver BUX
        Sender BUX->>Receiver BUX: Add a contact request
        Receiver BUX->>Receiver BUX: Store contact as "waiting" in database
        Receiver BUX->>Sender BUX: Success
        deactivate Receiver BUX
        Sender BUX->>Sender BUX: Store contact as "waiting"
        Sender BUX->>Sender Wallet: success
        deactivate Sender BUX
        Sender Wallet->>Sender: Display success
        deactivate Sender Wallet
        
        Receiver Wallet->>Receiver BUX: Get "waiting" "contact" to confirm or reject
        activate Receiver Wallet
        activate Receiver BUX
        Receiver BUX->>Receiver Wallet: List of contacts
        deactivate Receiver BUX
        alt reject contatct
            Receiver Wallet->>Receiver BUX: Rejection request
            activate Receiver BUX
            Receiver BUX->>Receiver BUX: Remove contact from database
            deactivate Receiver BUX
        else accept contact
            Receiver Wallet->>Receiver Wallet: Generate public key from private key and random hash
            Receiver Wallet->>Receiver BUX: Accept contact request
            activate Receiver BUX
            Receiver BUX->>Receiver BUX: Mark contact as "accepted"
            Receiver BUX->>Sender BUX: Contact accepted request
            Sender BUX->>Sender BUX: Validate random hash and store received public key
            Sender BUX->>Receiver BUX: success
            Receiver BUX->>Receiver Wallet: success
            deactivate Receiver BUX
            deactivate Receiver Wallet
        end
        Sender Wallet->>Sender: Confirm contact?
        activate Sender
        Sender->>Receiver: TOTP request
        activate Receiver
        activate Receiver
        Receiver->>Receiver Wallet: Check TOTP for Senders paymail
        activate Receiver Wallet
        Receiver Wallet->>Receiver Wallet: Calculate shared secret based on private key and Senders public key
        Receiver Wallet->>Receiver Wallet: Generate TOTP based on shared secret
        Receiver Wallet->>Receiver: TOTP
        deactivate Receiver Wallet
        Receiver->>Sender: TOTP
        deactivate Receiver
        Sender->>Sender Wallet: TOTP
        activate Sender
        activate Sender Wallet
        Sender Wallet->>Sender Wallet: Calculate shared secret based on private key and Receiver public key
        Sender Wallet->>Sender Wallet: Generate TOTP based on shared secret
        Sender Wallet->>Sender Wallet: Compare received TOTP with generated TOTP
        Sender Wallet->>Sender Wallet: Mark contact as confirmed
        Sender Wallet->>Sender Wallet: Generate another TOTP
        Sender Wallet->>Sender: TOTP
        deactivate Sender Wallet
        deactivate Sender
        Sender->>Receiver: TOTP
        deactivate Sender
        activate Receiver
        Receiver->>Receiver Wallet: TOTP
        activate Receiver Wallet
        Receiver Wallet->>Receiver Wallet: Generate TOTP and compare it with received TOTP
        Receiver Wallet->>Receiver Wallet: Mark contact as confirmed
        deactivate Receiver Wallet
        deactivate Receiver
        deactivate Receiver
    Motivation

    The increasing use of Bitcoin wallets has highlighted the need for a secure and interoperable digital signature standard that can be used across different applications. Digital signatures provide a vital aspect of data authentication, allowing for the verification of information and secure transactions, and are critical to ensuring the integrity of the Bitcoin network.

    While other solutions have proposed digital signatures within a wallet, none of them have provided a unified and open standard that supports both privately and publicly verifiable signatures, while also incorporating proper BRC-42 key derivation. The lack of such a standard has created a fragmentation within the ecosystem, with each application requiring its own solution, thus hindering interoperability and leading to duplicated effort.

    To address this issue, the BRC-3 standard has been created to enable the creation and verification of digital signatures using BRC-43 invoice numbering and permission scheme on top of BRC-42 for key derivation. This allows for the creation of private digital signatures that can only be verified by the intended counterparty, while maintaining security against third-party tampering.

    The BRC-3 standard not only provides a secure and interoperable solution for wallet implementations, but it also enables new use cases and experiences that were previously not possible. With a unified standard, different wallets can create and verify each other's digital signatures seamlessly, reducing friction and enabling greater innovation.

    Specification

    We start with the same constructs defined in BRC-43: users with clients, protocols and applications. We stipulate the use of BRC-43 invoice numbers in the context of BRC-42 key derivation, and we build on top of the permissions architecture defined by BRC-43.

    When an application sends a message to a client requesting that data be signed, the message comprises:

    • The BRC-43 security level, protocol ID, key ID and counterparty to facilitate BRC-42 key derivation and permissioning

    • The data to sign

    We stipulate the following process for digital signature creation:

    • The message signer begins by computing the BRC-43 invoice number based on the security level, protocol ID, and key ID

    • The message signer uses BRC-42 key derivation with the computed invoice number to derive their own child private key

    • The message signer computes the digital signature using ECDSA with their derived child private key (this specification is silent about ECDSA k-value utilization)

    We stipulate the following process for message verification:

    • The verifier somehow comes to know the signature, the counterparty (signer), the security level, protocol ID, and key ID. The mechanism for conveying this information to the verifier is beyond the scope of this specification.

    • The verifier begins by computing the BRC-43 invoice number based on the security level, protocol ID, and key ID

    • The verifier uses BRC-42 key derivation with the computed invoice number, their own private key and the public key of the sender, to compute the signer's child public key

    • The verifier uses ECDSA to verify the signature against the message using the signer's child public key

    We build upon the abstract messaging layer first described in BRC-1. Specifically, we define five new BRC-1 messages to facilitate requests and responses for signatures and verification operations, and error handling. For each of the messages, we stipulate that there exists some out-of-band mechanism for the parties to communicate which of the messages are being exchanged, removing the need for a message type field. Finally, specifically for the request messages, we stipulate that the message comprises a header and a payload, with the payload containing the data (ciphertext or plaintext), and the header containing the other information. For the response messages, no message header is defined and the payload simply contains the specified data.

    Signature Creation Request

    The signature creation request is a message sent by the BRC-43 application to the client. It contains a header with the following information:

    Field
    Description

    protocolID

    The security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The key ID

    counterparty

    The counterparty, anyone or self

    The message payload comprises the data to sign.

    Signature Creation Response

    The response message comprises the ECDSA digital signature in DER format.

    Signature Verification Request

    The signature verification request is a message sent by the application to the client. It contains a header with the following information:

    Field
    Description

    protocolID

    The security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The key ID

    counterparty

    The counterparty, self or anyone

    signature

    The DER-formatted signature for verification

    The message payload comprises the data to verify.

    Signature Verification Response

    The response message comprises a JSON payload containing the following fields:

    Field
    Description

    result

    The value is true if the signature is valid, otherwise it is false.

    Signature Error

    If the client is unable to fulfill the signature creation or verification requests for any reason, we specify that it should respond with a JSON-formatted Signature Error. The fields for the object are specified as follows:

    Field
    Description

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_VERIFICATION_FAILED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    One example of a Signature Error is given below:

    Test Vectors

    For compatibility with this signature scheme, we stipulate the following:

    Any user who knows the following identity private key (counterparty=anyone)...

    ...should be able to use security level 2, the BRC3 Test protocolID with keyID 42 and the following counterparty (signer)...

    ...to verify the message with the following digital signature (DER format)...

    The message that was signed is:

    Implementations

    • This digital signature capability is incorporated into the Babbage SDK

    BRC-1
    BRC-43
    BRC-42
    BRC-42
    Motivation

    The motivation behind this standard is to enable web browsers to directly integrate Bitcoin wallet functionality without relying on an additional application running on the client's device.

    Although BRC-5 defines a standard for local communication over HTTP, integrating wallet functionality in the browser eliminates the need for external wallet applications, reducing the overhead of inter-process communication and network requests.

    This also eliminates the need for users to switch between multiple applications when approving permissions, creating transactions, etc. They can perform all wallet-related tasks within the web application they are already using, resulting in a more cohesive and convenient user experience.

    Specification

    We define a specification for providing access to Bitcoin wallet functionality via the global window object that is directly available in all standard browser implementations.

    Once the browser has verified that the user is authenticated, an object labeled CWI should be added to the window object to provide access to the standard wallet functionality as defined by BRC-56.

    Standard CWI Functions Associated with Various Message Types

    For each of the message pairs (request and response) incorporated into BRC-56, we specify the existence of a corresponding message type with a specific function name:

    Message Type
    Window Function Name Value

    window.CWI.createAction()

    window.CWI.encrypt()

    window.CWI.decrypt()

    window.CWI.createSignature()

    window.CWI.verifySignature()

    This will allow applications to call functions with the following syntax:

    Parameter Format Specification

    We specify that all required parameters are provided in an object to the CWI functions.

    Example Identity Key Request

    Example Encrypt Function

    Implementation

    Implementors of this BRC should follow the abstract messaging layer as defined by BRC-56 to provide support for standard messaging types, and then modify the window object created to include this functionality in a CWI object.

    Motivation

    The motivation for this BRC is to establish a simple, secure, and cross-compatible payment protocol that facilitates P2PKH payments across the BSV ecosystem. The protocol utilizes BRC-42 key derivation to provide a privacy-enhanced approach to P2PKH transactions. The incorporation of BRC-9 SPV checking ensures secure validation of transactions while maintaining efficient processing times. This standard aims to simplify the process of P2PKH payments for wallets and applications, providing a straightforward implementation path for developers.

    Specification

    We specify a protocol for exchanging simple P2PKH payments between a sender and a recipient. The protocol employs BRC-42 key derivation to derive related public and private keys with invoice numbers, BRC-8 transaction envelopes to relay SPV-related information, and BRC-9 SPV checks to enable the recipient to validate the transactions.

    Key Derivation Scheme

    As defined by BRC-42, the sender and the recipient each have a master private key and a master public key. The invoice number is used to derive related keys, which can be used to facilitate payments. A payment sender can derive a public key for the recipient, and with the same invoice number, the recipient can derive the corresponding private key.

    We start with the need for a unique identifier for the payment, used for key derivation. To provide for the possibility that multiple outputs can be exchanged as part of the same payment, we also need a UTXO-specific number. We specify these two values as follows:

    • Derivation Prefix: A unique value generated by the sender of a payment to distinguish keys used within this payment from keys used in other payments.

    • Derivation Suffix: Each suffix is a unique value generated by the sender, so that each UTXO in the same payment has a different key, and so that the keys are not linkable by third parties.

    The keys that protect the funds exchanged under this protocol are derived with BRC-42 key derivation by the sender from the identity key of the recipient. The invoice number is specified as follows:

    Where:

    • 2 is a protocol security level denoting the access restrictions applied under this protocol (see BRC-43 Security Levels)

    • 3241645161d8 is a magic number that denotes compliance with this BRC

    • <derivationPrefix> is the payment-specific prefix used to arrive at a common key universe for all outputs in this payment

    • <derivationSuffix> is the UTXO-specific suffix used to arrive at a unique key for a specific P2PKH UTXO

    Payment Message Construction (JSON)

    The payment message format used by the sender when exchanging the payment with the recipient is a JSON object comprising:

    • "protocol": This field denotes that the JSON object comprises a payment message according to this protocol. Its value should be set to 3241645161d8.

    • "senderIdentityKey": The recipient will need to know the public identity key of the sender in order to validate the incoming payment. This field's value should be the 33-byte, compressed, hex-encoded secp256k1 public key of the sender

    • "derivationPrefix": This field denotes the payment-wide derivation prefix used by the sender when the keys for the payment UTXOs were derived

    • "transactions": This field comprises an array of one or more extended transaction envelopes. Each of the envelopes is extended with an additional "outputs" field, which is specified below

    The Outputs Extension

    Within each of the BRC-8 transaction envelopes, there is an additional field called outputs. This field is an object whose keys are integers that correspond to the output numbers in the specific transaction, all of which are intended by the sender to be redeemable by the recipient as part of this payment. The object values are objects that contain the suffix property, which is the derivation suffix for the specific UTXO being referenced. Here is an example of the outputs field:

    This example would be affixed onto an envelope that contained a transaction where the fourth, fifth, and eighth outputs (zero-indexing) are intended by the sender to be redeemable by the recipient as part of a payment.

    Sending Payments

    The steps for a sender to send a payment under this protocol are as follows:

    1. Learn the identity key of the recipient, determine the total amount of the payment and generate a derivation prefix.

    2. Decide on the number of outputs (across one or multiple transactions) that will comprise the payment.

    3. For each output, generate a derivation suffix for the output and decide on the number of satoshis in the output.

    4. For each output, use key derivation to derive a public key for the recipient for the output, and use the public key to construct a P2PKH Bitcoin output script as per .

    5. Use any wallet capable of creating Transaction Envelopes to construct and sign transactions that contain the output scripts derived for the recipient from the previous step.

    6. With all of the transactions, the derivation prefix, the derivation suffixes, and your sender identity key in hand, construct a payment message for the recipient that contains this information.

    Recipient Validation:

    When the recipient processes their incoming transactions, they check that the public key hashes in the output scripts are properly derived. The recipient should also perform the standard BRC-9 SPV checks. If these checks pass, the payment is marked as accepted and acknowledged, and goods or services can be rendered to the payee.

    Implementations

    Implementations of this protocol should adhere to the key derivation scheme and the payment message format specified in this BRC. The transaction submission system within any wallet can implement this protocol and validate that incoming transactions submitted under this protocol contain UTXOs that are properly derivable by the recipient. The protocol is intended to be cross-compatible and SPV-compliant.

    BRC-42
    BRC-8
    BRC-9
    Motivation

    BRC-50 standardizes payment submission to a wallet, improving the user experience for incoming Bitcoin payments. This enables higher-layer applications to add funds to a user's wallet without needing to maintain their own external balance. By standardizing payment submission, developers can create interoperable, extensible, and SPV compliant applications. This ensures a seamless and secure payment process, benefiting both wallet providers and end-users.

    Specification

    For this specification, we assume that there exists a wallet that facilitates a channel by which communication can occur with an application, such as over HTTP as defined in BRC-5. Based on this premise, we specify a standard by which payments can be submitted from an application to a wallet which then receives and processes the payment.

    Payment Submission Message

    We define an extension to the abstract BRC-1 messaging layer as the Payment Submission Message which comprises a JSON object with the following fields:

    Several of the same fields as defined in BRC-29 are present in this message. This standard essentially facilitates an implementation of BRC-29 over an abstract, wallet-to-application interface.

    Field
    Type / Required
    Description

    protocol

    (string, required)

    This field denotes that the JSON object comprises a payment message according to the given protocol (such as 3241645161d8 for ).

    transaction

    (object, required)

    The transaction envelope to submit, including key derivation information (the "Outputs Extension" as defined in )

    senderIdentityKey

    (string, required)

    The recipient will need to know the public identity key of the sender in order to validate the incoming payment. This field's value should be the 33-byte, compressed, hex-encoded secp256k1 public key of the sender

    The transaction field is a JSON object that conforms to the BRC-8, with the BRC-29 Outputs Extension. Only one transaction can be submitted per request.

    This provides the wallet with enough information to verify and receive payments from an application.

    Here is an example of a simple Payment Submission Message:

    Payment Acknowledgment Message

    The Payment Acknowledgment Message is the response that should be returned from the wallet to the calling application with the status of the request, and a reference number for the transaction submitted.

    Here is an example response from a successful payment submission:

    Payment Error Message

    If an error occurs during submission, an internal error should be thrown which can be caught and handled by the application code.

    Implementation

    Wallets can implement this specification by providing access to a submitDirectTransaction route over a given BRC-1 communications substrate, such as BRC-5, BRC-6 or BRC-7.

    A specific implementation of this BRC can be seen in the Babbage Dojo/Ninja architecture.

    BRC-9
    Payment Submission Message
    Payment Acknowledgment Message

    Overlay Network Data Synchronization

    Ty Everett ([email protected])

    Abstract

    This document proposes a solution for synchronizing data across UTXO-based overlay networks by specifying a secure and efficient mechanism for submitting and processing transactions. By utilizing a BRC-31 protected server hosting an API endpoint, overlay network nodes can process and admit transactions based on their relevance to the hosted topics. This standard defines the parameters and processing steps needed to track topical UTXOs.

    Motivation

    As discussed in , UTXO-based overlay networks provide a secure and scalable solution to managing states derived from the Bitcoin network. In order to maintain a consistent and up-to-date state across nodes, a method of data synchronization is required. Additionally, it is essential to provide a standard way for network participants to submit new transactions and notify network operators of their relevance to hosted topics. This document aims to address these needs by outlining a clear and well-defined process for submitting transactions and processing them based on topic-specific rules.

    Specification

    We start with a server that is set up to track the state of one or more topics. Every individual server implementing this specification decides what specific topic labels mean, and which rules they want to apply when admitting new UTXOs.

    API Endpoint and JSON Parameters

    The protected server will host a POST /submit API endpoint, which accepts JSON request payloads. The JSON request body will include a transaction envelope (rawTx, inputs, mapiResponses, proof) and an additional field called topics. The transaction envelope facilitates SPV checking, while the topics field denotes which overlay network topics should be notified about the transaction.

    Overlay Network Node Processing Steps

    Upon receiving a transaction, the overlay network node will perform the following steps:

    1. Verify the identity of the sender and establish the required level of identity for submitting transactions, negotiating under the protocol to the satisfaction of the network operator and the transaction sender.

    2. Check whether the node hosts at least one of the tagged topics from the payload. If none are hosted, the node returns an early response indicating no outputs were admitted. Otherwise, it can drop any unhosted topics from the list before proceeding.

    3. Use the process to verify the submitted envelope and confirm the transaction's legitimacy.

    Example

    We provide an example of an HTTP request and response.

    Request

    Response

    In this example, a client submits a transaction to the /submit API endpoint. The JSON payload contains the transaction envelope (rawTx, inputs, mapiResponses, proof) and an additional field called topics, which includes two example topics: "example_topic_1" and "example_topic_2".

    The overlay network node processes the transaction and determines that outputs 0 and 2 are admissible for "example_topic_1" and outputs 1 and 2 are admissible for "example_topic_2". The node then returns an HTTP response with a status of "success" and a topics object containing the admitted outputs for each topic.

    Implementation

    To implement this data synchronization solution, developers should first set up a protected server to host the POST /submit API endpoint. The server should be capable of processing JSON request payloads and performing the necessary transaction validation using .

    Overlay network nodes must be programmed to process incoming transaction submissions following the steps outlined in the specification. This includes verifying the sender's identity, checking for hosted topics, validating the transaction using , and applying topic-specific logic to determine output admittance.

    Developers should ensure that their implementation adheres to the JSON request and response structures specified in this document, enabling seamless interaction between overlay network participants.

    Hybrid Payment Mode for DPP

    Abstract

    The core DPP (Direct Payment Protocol) has been defined by BRC-27, but it is non-functional without at least one mode to facilitate payments. We extend the core DPP by introducing the Hybrid Payment Mode. This flexible and open-ended payment mode facilitates payments with BSV as well as various token types, such as loyalty points and stable coins. The Hybrid Payment Mode allows a payment host to stipulate payment from a set of funding types created with AND and OR connections, enabling a wallet to choose the most suitable option based on user resources.

    Motivation

    The motivation behind the Hybrid Payment Mode is to provide a flexible and versatile payment mode within the Direct Payment Protocol. This mode aims to accommodate various payment scenarios and combinations by enabling payment hosts to define multiple payment options with different funding types. The Hybrid Payment Mode can address the growing demand for handling diverse payment scenarios in the evolving digital currency landscape.

    Specification

    HybridPaymentMode (BRFCID: ef63d9775da5) will be described together with related Payment and PaymentACK objects. It is the first defined payment mode capable of fulfilling numerous requirements due to its flexible nature.

    HybridPaymentMode Structure

    The Hybrid Payment Mode contains a dictionary of various options (options are OR relation, so they are alternative sets of outputs, and the customer or their wallet will pick one).

    Options (In PaymentTerms)

    Every option contains a set of transactions (AND relation, if the customer chooses the option, they must provide all the required funds to satisfy the transaction). The interface for transaction object and transaction’s internal objects are described below.

    Transaction

    A transaction object is a set that contains 3 parts:

    • Outputs: A way of specifying a Bitcoin transaction output, including the value and script for various token standards.

    • Inputs: A way of declaring which specific inputs should be used (useful for multisig, payment_channels, etc).

    • Policies: A way of requesting specific TX policies like fees, SPV, nLockTime, etc.

    Outputs

    List of outputs – payment destinations.

    Native output

    This is a regular native BSV output which specifies the amount and recipient in bitcoin script form (usually p2pkh).

    STAS output

    This output is used for getting tokens using the STAS protocol. It is required to define tokenId (with symbol), amount, and recipient.

    TokenXYZ

    The structure for this object is specific to each particular token standard. It may be based on the BRFC reference if the token standard hasn't published a name yet, or otherwise based upon a particular token's name.

    Inputs

    A list of input objects contains data needed to specify the required inputs which should be used.

    Policies

    An object containing some policy information like fees or SPV envelope.

    Mode (In Payment)

    This object defines fields required by HybridPaymentMode. In this mode, important data are the chosen payment option (paymentId) and a list of transactions which fulfill this option:

    Mode (In PaymentACK)

    This object defines fields required by HybridPaymentMode:

    Example

    An example of a Hybrid Payment Mode implementation is provided below:

    Payment

    PaymentACK

    The BRC-54 Hybrid Payment Mode specification provides a comprehensive structure for enabling diverse payment scenarios within the Direct Payment Protocol. By carefully following the structures, processes, and context described in this document, a developer can create a compatible implementation within the BRC-54 specification.

    Extensible Proof-Type Format for Specific Key Linkage Claims

    Ty Everett ([email protected])

    Abstract

    This BRC proposes an extensible format for including zero-knowledge proofs (ZKPs) in specific key linkage revelations as per BRC-69 Method 2. While BRC-94 addresses limitations of BRC-69 Method 1 through a Schnorr-based ZKP, there is currently no standardized method for provable specific key linkage claims in Method 2. Given the rapid evolution of ZKP technologies, this specification introduces a proof-type enumeration scheme to accommodate future proof mechanisms. By defining a flexible proof-type field, we allow for the inclusion of various ZKP schemes as they become available, ensuring that wallets and applications can adopt and support them over time, eventually converging on standardized formats.

    Motivation

    We aim to provide a method for proving specific key linkage revelations under Method 2. However, current ZKP techniques may not fully support this requirement, as these technologies are still maturing. This proposal allows us to proceed with standardizing wallet interactions and linkage proofs while accommodating future advancements in ZKP capabilities. By introducing an extensible proof-type field, we create a flexible mechanism for integrating new proof schemes as they emerge, fostering innovation and facilitating eventual convergence on standard proofs.

    Scope and Assumptions

    This specification focuses on proofs of a specific computation: that a prover (Alice) has computed a shared secret between herself and a counterparty (Bob), and used it as a SHA-256-HMAC key over a defined invoice number to derive a specific linkage offset value. The approach is constrained to non-interactive proof schemes, as interactive proofs are impractical for our use case.

    We make the following assumptions:

    1. Non-Interactive Proofs: Only non-interactive proof schemes are considered, as per existing standards like .

    2. External Verification: Proof verification is expected to be performed by external systems or verifiers, not within the wallet itself.

    3. Encrypted Proof Payloads: Proof payloads are encrypted according to to ensure confidentiality during transmission.

    Specification

    Integration with Existing Standards

    We build on the existing standards:

    • : Defines methods for revealing key linkages.

    • : Specifies encryption of linkage information in transit using .

    • : Provides a Schnorr-based ZKP for counterparty-level linkage revelation (Method 1).

    This proposal extends these standards by defining an extensible proof-type format for specific key linkage claims (Method 2).

    Proof Encryption with BRC-72

    All proofs are encrypted using the mechanism defined in .

    • Counterparty-Level Revelations: Encrypted according to BRC-72, including both the shared secret and the Schnorr proof as per .

    • Specific Key Revelations: Encrypted according to BRC-72, including the linkage offset and the proof payload defined herein.

    Proof Formats

    Counterparty-Level Proof Format (BRC-94)

    We define a binary format for the encrypted Schnorr proof payload for counterparty-level revelations:

    This binary data is concatenated in the above order, then encrypted as per alongside the shared secret, and returned by the wallet to the verifier.

    Specific Key Proof Format (BRC-97)

    We define a binary format for the encrypted payload for specific key linkage proofs:

    This binary data is assembled by first specifying the Proof-Type, followed by the Proof payload (if applicable), then encrypted as per alongside the specific linkage offset, and returned by the wallet to the verifier.

    Proof-Type Enumeration

    We introduce a proof-type numbering scheme:

    • Proof-Type 0: Indicates no proof is provided. Verifiers must trust the prover when the proof-type is zero. The Proof payload is empty.

    • Proof-Types 1-255: Reserved for future proof schemes. As new ZKP methods become available, they can be assigned unique proof-type identifiers within this range, along with their specific proof formats.

    Example: Proof-Type Zero

    When Proof-Type is zero:

    • The Proof payload is empty.

    • The verifier receives the encrypted linkage offset but must trust the prover's claim, as there's no way to independently verify the correctness without a proof.

    Implementation Guidelines

    Wallet and Application Behavior

    • Wallets: Should implement the ability to generate and include the Proof-Type and Proof payload in the encrypted data when performing specific key linkage revelations.

    • Verifiers: Should be able to parse the Proof-Type field and handle the Proof payload accordingly, based on supported proof schemes.

    Future-Proofing

    • As new ZKP methods are developed and standardized, new BRCs can define additional proof-types (1-255) and their corresponding proof formats.

    • Wallets and verifiers should be designed to be extensible, allowing for the addition of new proof-types without significant changes to underlying architectures.

    Security Considerations

    • Confidentiality: All proof payloads must be encrypted as per to ensure that sensitive linkage information is protected during transit.

    • Trust: When using Proof-Type 0 (no proof), verifiers must be aware that they are relying on the prover's honesty, as no independent verification is possible.

    Future Work

    Future specifications may define new proof-types (1-255) along with their proof formats and verification methods. Potential avenues include:

    • Proof-Type 1: Could be assigned to a specific ZKP scheme (e.g., Bulletproofs, STARKs, SNARKs) that is suitable for proving specific key linkage claims.

    • Standardization: As the ecosystem converges on preferred proof schemes, updates to this BRC can formalize these proofs, promoting interoperability.

    References

    Conclusion

    This BRC provides a flexible and extensible framework for including proof schemes in specific key linkage revelations, accommodating future advancements in ZKP technology. By standardizing the proof-type field, we enable wallets and applications to adopt new proof mechanisms as they emerge, facilitating independent verification of specific key linkage claims while maintaining backward compatibility and fostering innovation in the BSV blockchain ecosystem.

    Wallet Transaction Output Tracking (Output Baskets)

    Ty Everett ([email protected])

    Abstract

    We define an extension to that enables a wallet to facilitate the tracking of specific application-defined transaction outputs within baskets. A new set of messages across the abstract messaging interface facilitates applications' access to unspent outputs stored in these baskets, with a permission system similar to that described in employed to regulate access by applications. Spending an output stored in a basket removes it, while new outputs can be added by specifying their basket as part of transaction creation requests.

    Certificate Creation and Revelation

    Ty Everett ([email protected])

    Abstract

    We define methods for an application to request that a wallet create and prove identity certificates. We define a set of additional messages that extend the application-to-wallet messaging layer with this functionality. We specify the functionality to be performed by the wallet as part of these processes, including a standard methodology for wallets to contact identity certificate certifiers over HTTP and carry out the signing of these documents. To keep users in control over how their data is processed and used, we allow for the wallet to obtain user consent prior to carrying out these operations.

    README

    A repository for submitting, discussing, sharing, and indexing technical proposals for use across the Bitcoin ecosystem. Data models, user interfaces, script templates, encoding formats, communication protocols, and constructive critique of existing industry practice are all welcome. The goal is to provide a platform for sharing ideas without any bureaucratic overhead.

    Contributing

    Contributions from all builders are welcome and encouraged. To propose a new BRC, fork the repo and create a new markdown file using the as the template. The common structure is outlined below, which is a guideline to aid you rather than a strict requirement. Once your proposal is ready to share, submit a pull request so that others can review and discuss it.

    To participate in discussions about existing proposals, simply open an issue and link back to the BRC file in question.

    Data Encryption and Decryption

    Ty Everett ([email protected])

    Abstract

    We devise a method for applications to request the encryption and decryption of data. Specifically, we define a mechanism for data encryption within the key derivation system, utilizing the protocol and key ID scheme. During encryption, the sender derives their own child private key and the child public key of the recipient using the process, then computes an ECDH shared secret between the child keys which is used in symmetric encryption with AES-256-GCM. The initialization vector, together with the ciphertext, are sent to the recipient. During decryption, the recipient computes their own private key and the public key of the sender, and uses ECDH to compute the same shared secret. The key is then used together with the provided initialization vector to decrypt the ciphertext. When no counterparty exists, we stipulate substitution for the sender's own public key in the child key derivation process.

    Mandala Token Protocol

    BRC-92: Mandala Token Protocol

    Deggen ([email protected])

    Abstract

    Minimalist protocol for tokenization, issuance, transfer, recovery, and redemption.

    Security Levels, Protocol IDs, Key IDs and Counterparties

    Ty Everett ([email protected])

    Abstract

    We propose a standard format for invoice numbers that enables secure and permissioned access to a set of restricted key derivation universes within the context of derivation. The format defines a string that includes the security level, protocol ID, and key ID separated by hyphens. Security level 0 implies no permissions, level 1 grants permissions to all key IDs and all counterparties for the given protocol ID, and level 2 grants permissions only to a particular counterparty. The standard aims to enable the creation of protocols that can request permission to access data controlled by a user in a secure and standardized way.

    Overlay Network Lookup Services

    Ty Everett ([email protected])

    Abstract

    This document proposes a solution for querying the state of UTXO-based overlay networks by specifying a mechanism for accessing data using lookup services. By utilizing a protected server hosting an API endpoint, overlay network nodes can return relevant UTXOs based on the topics they host and the user's query. This standard defines the parameters and processing steps needed to query for and access topical UTXOs.

    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "You have denied permission for signing this data."
    }
    0000000000000000000000000000000000000000000000000000000000000001
    0294c479f762f6baa97fbcd4393564c1d7bd8336ebd15928135bbcf575cd1a71a1
    [48, 68, 2, 32, 43, 34, 58, 156, 219, 32, 50, 70, 29, 240, 155, 137, 88, 60, 200, 95, 243, 198, 201, 21, 56, 82, 141, 112, 69, 196, 170, 73, 156, 6, 44, 48, 2, 32, 118, 125, 254, 201, 44, 87, 177, 170, 93, 11, 193, 134, 18, 70, 9, 31, 234, 27, 170, 177, 54, 96, 181, 140, 166, 196, 144, 14, 230, 118, 106, 105]
    BRC-3 Compliance Validated!
    window.CWI.<functionName>
    const identityKey = await window.CWI.getPublicKey({ 
        identityKey: true 
    })
    const ciphertext = await window.CWI.encrypt({
      plaintext: Buffer.from('Hello BRCs!'),
      protocolID: [0, 'Hello World'],
      keyID: '1'
    })
    “2-3241645161d8-<derivationPrefix> <derivationSuffix>”
    outputs: {
      3: { suffix: 'abcdefg' },
      4: { suffix: 'hijklmnop' },
      7: { suffix: 'qrstuvwxyz' }
    }
    {
      "protocol": "3241645161d8", // Simple Authenticated BSV P2PKH Payment Protocol
      "transaction": {
        "rawTx": "01000000017...",
        "inputs": {
            "b7d1297158f01bfc3fdace31f62a0d4634e9471d11b2a99f0784621cedb9367c": {
            "proof": {...},
            "rawTx": "01000000011..."
            }
        },
        "mapiResponses": [...],
        "txid": "737a1e90af9745da3f22ef74bc71a089c5e2a76e9662a0c9fa5b7cf94fe32e75"
      },
      "senderIdentityKey": "031d903f5b32a6121f29c59c547d2ea41ee8157ab0f0c2b5190be24a032816f827",
      "note": "Payment for spelling fix pull request.",
      "amount": 1033,
      "derivationPrefix:": "8217bb4e7fa0541e0f5e04fea764ab91"
    }
    {
      "reference": "cd5b1e4947e304476c788cd474fb579a"
    }
    BRC-8
    BRC-42
    BRC-16
    BRC-8
    BRC-94: Verifiable Revelation of Shared Secrets Using Schnorr Protocol
  • STARKs: Scalable, Transparent, and Post-Quantum Secure Computational Integrity

  • Field

    Bytes

    Description

    R

    33

    Nonce public key point R in compressed 33-byte DER format.

    S'

    33

    Nonce shared secret point S' in compressed 33-byte DER format.

    z

    Variable

    Response scalar z as a big-endian integer.

    Field

    Bytes

    Description

    Proof-Type

    1

    One-byte unsigned integer (0-255), indicating the proof scheme used.

    Proof

    Variable

    Proof payload, format depends on Proof-Type.

    BRC-69
    STARKs
    BRC-72
    BRC-69
    BRC-72
    BRC-2
    BRC-94
    BRC-72
    BRC-94
    BRC-72
    BRC-72
    BRC-72
    BRC-2: BRC Encryption Standard
    BRC-69: Revealing Key Linkages
    BRC-72: Protecting BRC-69 Key Linkage Information in Transit
    BRC-93: Limitations of BRC-69 Key Linkage Revelation
    BRC-43
    BRC-43
    BRC-43
    BRC-43
    BRC-43
    BRC-43

    derivationPrefix

    (string, required)

    This field denotes the payment-wide derivation prefix used by the sender when the keys for the payment UTXOs were derived

    note

    (string, required)

    Human-readable description for the transaction.

    amount

    (number, optional)

    Amount of satoshis associated with the transaction. If provided, it is used to verify that the amount returned from processing the transaction matches the payment amount.

    BRC-29
    BRC-8
    BRC-29

    BRC-53 Certificate Creation

    window.CWI.createCertificate()

    BRC-53 Certificate Verification

    window.CWI.proveCertificate()

    BRC-56 HMAC Creation

    window.CWI.createHmac()

    BRC-56 HMAC Verification

    window.CWI.verifyHmac()

    BRC-56 Public Key Derivation

    window.CWI.getPublicKey()

    BRC-56 Certificate List

    window.CWI.findCertificates

    BRC-56 Version Request

    window.CWI.getVersion()

    BRC-56 Network Request

    window.CWI.getNetwork()

    BRC-56 Authentication Request

    window.CWI.isAuthenticated()

    BRC-56 Async Auth Request

    window.CWI.waitForAuthentication()

    BRC-1 Transaction Creation
    BRC-2 Encryption
    BRC-2 Decryption
    BRC-3 Signature Creation
    BRC-3 Signature Verification
    swimlanes
    Options {
      "ID": Transactions // required, min one key-value pair.                   
    }
    Transaction {
      outputs // list of output objects. required
      inputs // list of input objects. optional
      policies // additional properties and requirements for transaction. optional
    }
    Outputs {
      native // list of native output objects. optional.
      brfcXYZ // list of brfc objects of XYZ token. optional.
      tokenABC // list of ABC token objects. optional.
      ...
    }
    Native output {
      amount // number. required.
      script // string. required. hexadecimal script.
      description // string. optional. must not have JSON string length of greater than 100.
    }
    STAS output {
      tokenId // string. required.
      amount // number. required.
      recipient // string. bitcoin address or paymail.
    }
    brfc1234 {
      properties_1
      properties_2
      ...
    }
    unicornToken {
      tokenId // string. required
      script // string. required. hexadecimal script.
      ...
    }
    Input {
    scriptSig // string. required.
    txid // string. required.
    vout // integer. required.
    value // integer. required.
    nSequence// number. optional.
    }
    Policies {
    fees // dictionary. optional. Nested dictionary which include on Fee objects on 3rd level.
    SPVRequired // boolean. optional. default is false.
    lockTime // number. optional.
    }
    "ef63d9775da5" {
    optionId // string. ID of chosen payment options
    transactions // a list of raw transactions. required
    ancestors // object. optional.
    }
    {
    transactionIds // a list of transaction ids. required
    peerChannel // object. optional
    }
    {
      optionId: "choiceID1",
      transactions: [
        " RAW_TRANSACTION for 'choiceID1.transactions[0]' ",
        " RAW_TRANSACTION for 'choiceID1.transactions[1]' ",
      ],
      ancestors: {
        " TXID of RAW_TRANSACTION for 'choiceID1.transactions[1]' ": {
          /* This object has the ancestors of 'choiceID1.transactions[1]' */
        }
      }
    }
    {
      transactions: [
        " TXID of transaction for 'choiceID1.transactions[0]' ",
        " TXID of transaction for 'choiceID1.transactions[1]' ",
      ],
      // Things like peer_channel should probably still be defined at the paymentAck root level. Different transactions should probably not have different peer_channel-s.
      peerChannel: {
        host: "peerchannels:25009",
        token: "token",
        channel_id: "channelid",
      }
    }

    Apply topic-specific logic to the transaction by iterating through all specified topics and performing the following for each topic:

    • Check the transaction's list of inputs for UTXOs that are part of the current topical overlay. Flag these inputs and communicate the information to the topic's management logic.

    • Apply the topic-specific management logic and protocol rules to determine output admittance for each transaction output.

    • Update the node's tracking system, associating each relevant output with the topic labels of topics that have admitted those outpoints. If implementing BRC-24, notify lookup services about the new incoming entries.

    • Remove any now-spent inputs that were previously associated with a topic from the tracking system, as they have now become spent by this transaction. If implementing , notify lookup services about the old outgoing entries.

  • Generate and return a JSON response object containing the transaction processing results, including a status key with a value of success, and a topics key with an object containing topic labels and arrays of output numbers denoting which outputs were admitted into the specific topics.

  • Pursuant to any peering or data synchronization arrangements or contracts that the node operator may have negotiated with other node operators with whom they would like to remain in sync, use the agreed-upon exchange mechanisms to notify the other node operators about the received transaction, potentially in conjunction with an incoming or outgoing BRC-41 payment.

  • BRC-59
    BRC-31
    BRC-8
    BRC-31
    BRC-31
    BRC-9
    BRC-8
    BRC-8
    BRC-31
    BRC-9
    BRC-31
    BRC-9
    Motivation

    Transaction outputs in Bitcoin take many forms, and serve many purposes. While BRC-1 defines a way for applications to request the creation of transaction outputs by wallets, there is no way for applications to request that a wallet tracks these outputs. Enabling applications to request that wallets track outputs provides a number of advantages: First, applications may no longer need to rely on external data storage and retrieval systems, simplifying their architecture. Second, there is the potential to represent different types of Bitcoin-native tokens within specific baskets, and define protocols for manipulating specific types of tokens based on which baskets they are stored in. Finally, when permission to access a basket is decided by the user on a per-application basis, it facilitates a greater degree of control for users over their tokens, enabling multiple applications to access and use the same tokens.

    Specification

    We extend the BRC-1 Transaction Creation Request message so that, in addition to the normal script and satoshis fields defined in each element of the outputs array, there is another basket field. The new basket field is a string comprising the name of the basket into which this output is to be inserted and tracked by the wallet. We specify that, when a wallet creates a transaction responsive to the Transaction Creation Request, it utilizes some internal storage and retrieval system (beyond the scope of this specification) to associate the specified output with the specified basket.

    To allow applications to specify information that would later be needed to unlock and use outputs that are stored in baskets, an optional customInstructions field can also be added when basket is given. This field is retained by the wallet and included as part of the Transaction Outputs Response (defined below).

    To facilitate permissioned access to baskets by applications, we stipulate that the wallet, upon receiving a transaction creation request, may prompt the user to grant permission for the application to use the basket. The method by which the wallet seeks the consent of the user is out-of-scope for this standard, but the process, if it occurs, must be facilitated by the wallet asynchronously between the receipt of the Transaction Creation Request and the furnishment of any Transaction Creation Response or Transaction Creation Error messages.

    To facilitate access to the tokens stored within baskets by applications, we define a new set of messages across the abstract communications channel between the wallet and the application, as follows:

    Transaction Outputs Request

    This message constitutes a request by the application for a list of Bitcoin UTXOs that are responsive to the request. The message contains the following information:

    Field
    Required
    Description

    basket

    yes

    The basket from which outputs should be returned

    includeEnvelope

    no

    Whether transaction envelopes are requested for the outputs

    limit

    no

    The maximum number of outputs to return

    This provides the wallet with enough information to furnish the outputs requested by the application. Here is an example of a simple Transaction Outputs Request in JSON:

    In this example, the application is stipulating that a maximum of 25 outputs from the todo tokens basket are to be returned, including their BRC-8 transaction envelopes.

    Transaction Outputs Response

    The response comprises a list of transaction outputs currently in the specified basket. This is an array of objects where each object has the following fields:

    Field
    Description

    amount

    The number of satoshis in the transaction output

    txid

    The TXID of the transaction that created the output, given as a hex string

    vout

    The output index number of this output within the transaction that created it

    outputScript

    The hex-encoded Bitcoin script program that locks the output

    customInstructions

    The spending instructions that were stored when the output was created

    Here is an example of a simple Transaction Outputs Response:

    Transaction Outputs Error

    If the Bitcoin wallet is unable to fulfill the Transaction Outputs Request for any reason, we specify that it should respond with a JSON-formatted Transaction Outputs Error. The fields for the object are specified as follows:

    Field
    Description

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_PERMISSION_DENIED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    One example of a Transaction Outputs Error is given below:

    Implementations

    This functionality is implemented as part of the Babbage SDK, via the getTransactionOutputs function.

    BRC-1
    BRC-43
    BRC-1
    Motivation

    The BRC-52 identity certificate standard provides a decentralized, privacy-centric solution to digital identity, allowing users to selectively reveal their identity data. However, without a standard method for applications to create and prove these certificates, wallet support will be limited. BRC-53 provides a set of standardized methods for applications to request and interact with BRC-52 certificates, enabling wider adoption and integration of BRC-52 certificates within the ecosystem.

    Specification

    We define two new sets of messages to be sent over the abstract BRC-1 messaging layer:

    Certificate Creation Request

    An application may request a wallet to create a BRC-52 certificate by providing the following parameters:

    Field
    Description

    certificateType

    The type of certificate to create.

    fieldObject

    An object containing the fields to be added to the certificate.

    certifierUrl

    The URL of the certifier responsible for signing the certificate.

    certifierPublicKey

    The public identity key of the certifier responsible for signing the certificate.

    The wallet will then carry out the following steps:

    1. Initialize a BRC-53 client with the primary identity key of the wallet.

    2. Generate a client nonce.

    3. Request the validationKey and serialNumber from the certifier by making a BRC-53-enabled HTTPS POST request to the certifierUrl's /initialRequest endpoint with the client nonce.

    4. Validate the received serialNumber and validationKey using the client and server nonces.

    5. Encrypt the fields of the fieldObject using encryption and store the concealed fields and encrypted field revelation keys in the fields and keyring objects, respectively.

    6. Create a Certificate Signing Request (CSR) containing the certificate type, nonces, validation key, serial number, fields, and keyring.

    7. Send the CSR to the certifier's /signCertificate endpoint via an HTTP POST request.

    8. Receive and verify the signed certificate's authenticity.

    9. Store the signed certificate in the wallet's data store (how the wallet stores its data is beyond the scope of this specification).

    Certificate Creation Response

    The response sent back over the abstract messaging layer from the wallet to the application will constitute a valid, fully-signed BRC-52 identity certificate with no keyring.

    Certificate Creation Error

    If the Bitcoin wallet is unable to fulfill the Certificate Creation Request for any reason, we specify that it should respond with a JSON-formatted Certificate Creation Error. The fields for the object are specified as follows:

    Field
    Description

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_CERTIFIER_REJECTED_CSR".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    One example of a Certificate Creation Error is given below:

    Certificate Proof Request

    An application may request a wallet to prove a BRC-52 certificate by providing the following parameters:

    Field
    Description

    certificate

    The certificate to be proven.

    fieldsToReveal

    An array containing the names of the fields to be revealed to the verifier.

    verifierPublicIdentityKey

    The public identity key of the verifier.

    The wallet will then carry out the following steps:

    1. Verify the authenticity of the provided certificate.

    2. Ensure that the application and the verifier have been granted access to the requested certificate fields (optional permissions checks).

    3. Decrypt the encrypted field revelation keys using the wallet's primary identity key.

    4. Encrypt the decrypted field revelation keys for the verifier using the verifierPublicIdentityKey.

    5. Add the encrypted field revelation keys to the certificate field revelation keyring (as defined in ) object.

    6. Attach the field revelation keyring to the certificate.

    7. Return the certificate with the attached field revelation keyring for presentation to the verifier for field examination.

    Certificate Proof Response

    The response sent back over the abstract messaging layer from the wallet to the application will constitute a valid, fully-signed BRC-52 identity certificate with the attached field revelation keyring for the verifier.

    Certificate Proof Error

    If the Bitcoin wallet is unable to fulfill the Certificate Proof Request for any reason, we specify that it should respond with a JSON-formatted Certificate Proof Error. The fields for the object are specified as follows:

    Field
    Description

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_PERMISSION_DENIED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    One example of a Certificate Proof Error is given below:

    Wallet-to-Certifier Interface

    The wallet and certifier communicate in a standard way over a BRC-31 protected HTTPS interface to facilitate the requesting and signing of a certificate. Here, we specify the requirements and fields for these communications.

    We require that the wallet engages in the BRC-31 authentication process with the certifier, and we further require that the wallet authenticate using the same key which is the subject of the certificate issuance process. This provides a way for the certifier to know that the person making the request is the person who will be receiving the identity certificate.

    Initial Request

    The wallet initiates the communication with the certifier by sending an initial request. The initial request includes a client nonce, generated randomly by the wallet. The request is sent to the /initialRequest endpoint using the HTTP POST method.

    Request fields

    • clientNonce: A randomly generated 32-byte string in base64 format.

    The certifier processes the initial request and generates two nonces: serialNonce and validationNonce. The certifier calculates the serialNumber and validationKey by hashing the concatenation of clientNonce with the respective nonces. The certifier then returns these values in the response.

    Response fields

    • validationKey: A base64 encoded string calculated by hashing the concatenation of clientNonce and validationNonce using SHA256.

    • serialNumber: A base64 encoded string calculated by hashing the concatenation of clientNonce and serialNonce using SHA256.

    • validationNonce: A base64 encoded nonce generated by the certifier.

    • serialNonce: A base64 encoded nonce generated by the certifier.

    Certificate Signing Request

    After receiving and validating the values from the initial request, the wallet creates a Certificate Signing Request (CSR) and sends it to the /signCertificate endpoint using the HTTP POST method.

    Request fields

    • messageType: The string "certificateSigningRequest".

    • type: The type of certificate to create.

    • clientNonce: The client nonce generated by the wallet during the initial request.

    • serverSerialNonce: The serial nonce received from the certifier in the initial request.

    • serverValidationNonce: The validation nonce received from the certifier in the initial request.

    • validationKey: The validation key received from the certifier in the initial request.

    • serialNumber: The serial number received from the certifier in the initial request.

    • fields: An object containing encrypted fields of the certificate.

    • keyring: An object containing encrypted field revelation keys, revealed from the subject to the certifier.

    The certifier processes the CSR and signs the certificate using its private signing key. The signed certificate is then returned to the wallet in the response.

    Response fields

    • status: The status of the signing process, either "success" or "error".

    • description: A description of the error, if applicable.

    • code: An error code, if applicable.

    • certificate: The signed certificate, if the signing process is successful.

    Implementations

    These processes have been implemented into the createCertificate and proveCertificate functions of the Babbage SDK. The Computing with Integrity kernel (currently proprietary) implements the wallet-to-certifier communications protocol, and CoolCert implements the certifier side of the protocol.

    BRC-52
    BRC-1
    Iterative improvement

    We believe in encouraging discussion and iterative improvement of proposals, resulting in incremental improvement within the bounds of the Bitcoin protocol. We welcome suggestions for improvement and are committed to working with contributors to improve proposals and ensure that they align with our guidelines.

    Note that substantial revisions to standards (beyond fixing typos, adding context or wording) should go into a new standard that extends or revises the old one, so as not to disrupt existing implementations.

    We look forward to your contributions and helping to create a world where transactions are seamlessly formed, and applications interact with each other with ease.

    Read more about areas of interest on OpenStandards.cash

    Structure

    The BRCs repository is organized into directories, each representing a different category of proposal. Categories may include, but are not limited to:

    • Transaction Templates

    • Bitcoin Script Templates

    • Communication Protocols

    Each proposal should be written as a markdown file and should loosely adhere to the following:

    • Title: A descriptive title for the standard being defined.

    • Author(s): Who wrote the standard and where did it come from? How can they be reached?

    • Abstract: A brief description of the proposed standard or template.

    • Motivation: The reasoning behind the proposal and why it is needed.

    • Specification: A detailed technical specification of the proposal.

    • Implementations: Information on how the proposal has been or can be implemented.

    • References: Any relevant literature or external resources related to the proposal.

    Note that additional relevant content, identifiers or other information may be added to the document. Documents that already existed before the repository may not follow these requirements.

    Things that help depict and understand the document, such as media, may also be added in a media subdirectory where appropriate.

    Refer to the Banana-Powered Bitcoin Wallet Control Protocol for a fun example template you can copy when proposing your own standards.

    Standards

    BRC
    Standard

    0

    1

    2

    3

    4

    5

    License

    Everything in this repository is subject to the Open BSV License.

    Terms and Conditions

    Terms and Conditions

    ~EXAMPLE.md
    Motivation

    The Bitcoin ecosystem has demonstrated a clear desire for wallets to support data encryption between parties1. This capability facilitates secure exchange of information, improves user privacy, and enables novel applications that require direct and secure communication between users. The unique economic incentives of micropayment-based applications, particularly those facilitated by Bitcoin wallets, make user privacy paramount, and have led to the adoption of end-to-end encryption by many applications2. While several encryption systems have been developed and integrated into various platforms, there is currently no standard methodology that supports both single-party and multi-party encryption, protocol-level permissions management, and leverages BRC-42 key derivation. The BRC-2 standard aims to fill this gap and provide a secure and standardized framework for encryption and decryption within the Bitcoin ecosystem.

    Specification

    We start with the same constructs defined in BRC-43: users with clients, protocols and applications. We stipulate the use of BRC-43 invoice numbers in the context of BRC-42 key derivation, and we build on top of the permissions architecture defined by BRC-43.

    When an application sends a message to a client requesting that data be encrypted, the message comprises:

    • The BRC-43 security level, protocol ID, key ID and counterparty to facilitate BRC-42 key derivation and permissioning

    • The data to encrypt

    We stipulate the following process for encryption:

    • The message sender begins by computing the BRC-43 invoice number based on the security level, protocol ID, and key ID

    • The message sender uses BRC-42 key derivation with the computed invoice number to derive a child public key for the recipient

    • The message sender uses BRC-42 key derivation with the computed invoice number to derive their own child private key

    • The message sender computes the ECDH shared secret between the two derived child keys

    • The resulting elliptic curve point's X and Y values are hashed with SHA256 to create an AES-256-GCM symmetric encryption key

    • The resulting 256-bit value is used in conjunction with a randomly-generated 256-bit initialization vector to encrypt the message with AES-256-GCM

    • The initialization vector is prepended to the ciphertext, and the combined value is returned by the client to the application over the abstract communications substrate.

    We stipulate the following process for message decryption:

    • The recipient somehow comes to know the ciphertext (prepended with the initialization vector), the counterparty, the security level, protocol ID, and key ID. The mechanism for conveying this information to the recipient is beyond the scope of this specification.

    • The recipient begins by computing the BRC-43 invoice number based on the security level, protocol ID, and key ID

    • The recipient uses BRC-42 key derivation with the computed invoice number, their own private key and the public key of the sender, to compute the sender's child public key

    • The recipient uses the same process to compute his own child private key

    • The recipient computes a shared secret between the two child keys, using the hash of the X and Y values as an AES-256-GCM symmetric key

    • The recipient then uses the symmetric key to decrypt the ciphertext with the provided initialization vector

    We build upon the abstract messaging layer first described in BRC-1. Specifically, we define five new BRC-1 messages to facilitate requests and responses for encryption and decryption, and error handling. For each of the messages, we stipulate that there exists some out-of-band mechanism for the parties to communicate which of the messages are being exchanged, removing the need for a message type field. Finally, specifically for the request messages, we stipulate that the message comprises a header and a payload, with the payload containing the data (ciphertext or plaintext), and the header containing the other information. For the response messages, no message header is defined and the payload simply contains the specified data.

    Encryption Request

    The encryption request is a message sent by the BRC-43 application to the client. It contains a header with the following information:

    Field
    Description

    protocolID

    The security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The key ID

    counterparty

    The counterparty, or self

    The message payload comprises the data to encrypt.

    Encryption Response

    The response message comprises a payload containing the encrypted ciphertext, prepended with the 32-byte initialization vector.

    Decryption Request

    The decryption request is a message sent by the application to the client. It contains a header with the following information:

    Field
    Description

    protocolID

    The security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The key ID

    counterparty

    The counterparty, or self

    The message payload comprises the data to decrypt, prepended with the 32-byte initialization vector.

    Decryption Response

    The response message comprises a payload containing the decrypted plaintext.

    Cryptography Error

    If the client is unable to fulfill the encryption or decryption requests for any reason, we specify that it should respond with a JSON-formatted Cryptography Error. The fields for the object are specified as follows:

    Field
    Description

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_DECRYPTION_FAILED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    One example of a Cryptography Error is given below:

    Test Vectors

    For compatibility with this encryption scheme, we stipulate the following:

    A user who has the following identity private key...

    ...which implies the followign identity public key for that user...

    ...should be able to use security level 2, the BRC2 Test protocolID with keyID 42 and the following counterparty...

    ...to decrypt the message with the following ciphertext (with prepended initialization vector)...

    ... and receive the following plaintext:

    ...and to validate the message with the following HMAC...

    ... the message whose HMAC is above as being:

    Implementations

    • This encryption capability is incorporated into the Babbage SDK

    References

    • 1: MoneyButton Encryption

    • 2: BaeMail

    BRC-42
    BRC-43
    BRC-42
    Motivation

    There is a lack of clarity with respect to how tokens can be defined and managed within the context of Overlays. This proposal aims to demonstrate the minimim viable solution for tokens, having considered all available options, picked the most viable, and made small improvements to allow for simple extension of functionality.

    Specification

    1. Use a genesis transaction output as an assetId concatenating the txid and vout.

    2. Push that assetId to the stack in any output script you want to send that token to so that overlays, wallets, and smart contracts can evaluate it.

    3. Push the amount of tokens the output represents if it's a fungible token.

    4. Drop the data so that you can use whatever functional logic you like thereafter ...

    5. 1 satoshi assigned to each output.

    6. Prefix everything with a UTF8 exclamation point ! (0x21 in hex) for sake of measuring adoption.

    Fungible Token

    NFT Script

    Transfers

    The sum of input token amounts must equal the sum of output token amounts of the same assetId.

    MFT
    inputs
    outputs

    output holding 9 tokens

    21 assetId 04 OP_DROP OP_2DROP ...

    21 assetId 05 OP_DROP OP_2DROP ...

    The order of inputs and outputs is disregarded.

    Design Justification

    Include Genesis Output and Protocol Identifier In Every Output

    Token outputs each refer to the genesis output as a way to avoid collisions when identifying the asset they represent. This acts as a universal asset identifier for enabling swap contracts and token based payment protocols. The randomness helps us avoid things like people competeing to claim the "USD" assetId or other potentially popular labels.

    They also include a prefix of ! in utf8 as a way to tag outputs for tracking global adoption of the protocol; to reduce the cost of recovery from archival services; and for use within the context of IPv6 multicast group address routing.

    Why Push Data Formatting?

    The only reason to include the data in the outputs at all is for access to the data in smart contracts, any metadata ought to be kept in the application layer if needed.

    Bitcoin Number format is used for the token amount.

    Transaction outpoint format is used for the genesis outpoint information.

    This is to ensure smart contracts can more easily parse the data within a transaction to enforce conditional logic based on token values, and enforce token type in a format which is already incorporated into the transaction format itself.

    Single Satoshi Outputs

    All outputs have 1 satoshi assigned to avoid AML problems like sending “a worthless bean token” to someone which actually has 100 BSV under it.

    Tokenization: Deep Dive

    NFTs

    Non-Fungible tokenization is the process of associating something with a particular transaction output which will thereafter represent a claim to that something. We assume that the issuer has already registered a public key as associated with them: identityPublicKey.

    We propose this key be referred to as a BoundKey.

    The output looks like a regular P2PK but if you know the owner’s identity public key and the token details you are able to verify the association. The txid and vout of this transaction form the assetId for this NFT.

    boundKeyNFT

    Fungible Tokens

    Fungible tokens sometimes require administrative management: multiple issuances to increase available supply, redemptions to reduce supply, recovery from loss in case of errors or theft. These things require an known issuer to steward the token system as a whole while keeping individual transactions private.

    boundKeyFT

    Registration

    There is an issuer who is responsible for maintaining the relationship between tokens and the real world assets they represent. Before we issue any tokens, we register a public key by creating an authorized outpoint with a key derived from the issuer’s identity key. This transaction is used as the basis for a particular fungible token.

    inputs
    outputs

    any

    21 OP_DROP boundKey OP_CHECKSIG (the genesis outpoint, assetId, and authorized outpoint 0)

    Issue

    Once registered, tokens can be issued by creating a single transaction which:

    • spends the genesis outpoint

    • creates token outputs

    • creates the next authorized outpoint

    inputs
    outputs

    authorized outpoint n

    21 OP_DROP boundKey OP_CHECKSIG (authorized outpoint n+1)

    21 assetId 09 OP_2DROP P2PKH (creates 9 tokens)


    Redeem

    Redemption transactions spend token outputs without creating new ones, taking them out of circulation. The boundKey in this case could incorporate data associated with a withdrawal of funds from an associated bank account for example.

    inputs
    outputs

    authorized outpoint n

    21 OP_DROP boundKey OP_CHECKSIG (authorized outpoint n+1)

    Any token outpoint with our genesis_outpoint

    no token outputs

    A chain of authorization outpoints is created such that the transaction DAG works as an immutable linked hash chain of all administrative actions taken since genesis. Public audit-ability. No hidden issuances or redemptions. The token supply is known and provable.


    Burning ⇒ Loss

    When a token owner creates a valid BSV transaction which does not conform to the token transfer rules, the tokens are burned, and the transaction will not be accepted by the token overlay, despite perhaps being broadcast on the blockchain itself.

    inputs
    outputs

    Valid tokens

    no token outputs, or too few

    In this case, tokens in does not equal tokens out.


    Recovery

    Post burning, tokens which were lost can be recovered by the issuer by spending and creating an authorized output while including metadata into the derivation of a pubkey to indicate which txids are to be processed as having been spent invalidly.

    recovery
    inputs
    outputs

    authorized outpoint n

    21 OP_DROP boundKey OP_CHECKSIG (authorized outpoint n+1)

    21 assetId 05 OP_2DROP P2PKH


    Example Transactions

    1. Register

    2. Issue

    3. Transfer

    4. Redeem

    Implementations

    Not yet available. Proposal stage.

    Motivation

    The BRC-42 key derivation architecture allows parties to derive child keys for each other based on flexible invoice numbering schemes. However, the lack of a standard format for invoice numbers creates challenges for using different sets of keys for different purposes. This standard proposes a solution to address these challenges by defining a common standard for formatting invoice numbers.

    By enabling the development of various classes of protocols, each with different security models, this standard allows for the sharing of a common set of root keys while keeping key universes separate. This approach provides an easy-to-use solution for various applications, including Bitcoin and MetaNet client software, where different applications require access to various classes of a user's data.

    The proposed scheme for key IDs is open-ended and can be defined by the rules for each protocol, making it easy to implement and apply to a wide range of use cases. This standard makes it easier for software using BRC-42 key derivation for cryptographic operations to protect user data by granting permission for particular parties to access and use keys based on the security level for the protocol. Overall, the adoption of this standard will simplify and enhance the use of BRC-42 key derivation in a variety of contexts, improving security and facilitating innovation.

    Specification

    We specify that an invoice number has the following three components:

    Component
    Description

    Security Level

    Denotes the level of permissioning security applied to protocols using the scheme.

    Protocol ID

    The identifier for the protocol that is using the scheme.

    Key ID

    Protocol-specific information used to arrive at a particular key under a particular protocol.

    We specify the following format for invoice numbers:

    We specify that there are users who have clients, there are applications and there are protocols. Protocols define a key derivation scheme that facilitates access by applications to user-held keys via their client. For example, an application could use a particular protocol to encrypt some data with the user's client. The keys used for encryption under one protocol are different than the keys used for other protocols, because the invoice number used for key derivation contains the specific protocol ID being used.

    We specify the counterparty as the other party whose key is being used for derivation. When there is only one party, we specify that their single key be used both as the sender and the recipient. This is known as self-derivation. When the sender wishes to create a scheme where anyone can derive the corresponding key, we specify the use of the number 1 as the private key. This is known as anyone-derivation.

    We specify a permission system in which the security level defined as part of the protocol is employed to determine whether the user is prompted to allow a key derivation operation to succeed. We specify that there exists some mechanism for the client to prompt the user, transparently to the application, about these permission requests. We specify that all permission requests are granted by the client on a per-application basis, and that the client has some reliable manner of identifying applications.

    When the protocol specifies a security level of 0, no permissions are required and the key derivation operation is always allowed to succeed without user input. When the security level is 1, the user must grant the application permission to use the protocol, and the application can use the protocol for any counterparty without additional grants of permission. When the security level is 2, the client will require a new permission grant for every new counterparty, and the grants of permission made under level-2 protocols are counterparty-specific.

    We specify that the client may provide a mechanism for the expiration of permission grants by the user, at which time the user would need to re-authorize an application's continued use of their keys. Since the permissions process is handled transparently by the client, it is beyond the scope of this standard.

    Rules

    Protocol IDs are normalized by the following rules:

    • only letters, numbers and spaces

    • no multiple space " "

    • all lower case when used

    • maximum 280 characters

    • must be at least 5 characters

    • must not end with " protocol"

    • leading and trailing spaces are removed

    All strings that normalize to the same value identify the same protocol.

    Key IDs must be a string of at least one byte and no more than 1033 bytes.

    Some protocol IDs are used internally by various clients, and thus are never allowed within applications. These are specified by other standards, such as BRC-44.

    Examples

    To illustrate how the system is intended to function, we provide several examples.

    1. An application, example.com, sends a request to the user's client for encrypting some data (as per BRC-2). The application is requesting to use security level 0, a protocol ID of Hello World, a key ID of 1, and counterparty of self.

      • The client makes no permission requests because the security level is 0.

      • The client computes 0-hello world-1 as the invoice number.

      • The client uses its own private key and the corresponding public key for derivation, because counterparty is self.

      • The client derives a child public key as the sender and a child private key as the recipient, using the same invoice number for both operations.

      • The client computes a shared secret between the two child keys.

      • The client uses the shared secret key as a symmetric key for the encryption process.

    2. An application, example.com, sends a request to the user's client for creating a digital signature over some data (as per ). The application is requesting to use security level 1, a protocol ID of Document Signing, a key ID of 1, and counterparty of anyone.

      • The client checks if example.com has already been granted permission to use this protocol. Because the security level is

    3. An application, example.com, sends a request to Alice's client for creating a digital signature over some data (as per ). The application is requesting to use security level 2, a protocol ID of Private Document Signing, a key ID of 1337, and counterparty of Bob's public key.

      • Alice's client checks if example.com has already been granted permission to use this protocol specifically for interacting with Bob. Because the security level is 2

    Implementation

    The system is implemented into the Babbage SDK, which employs protocol IDs, key IDs and security levels when facilitating the functionality of the encryption and digital signature creation components.

    BRC-42
    Motivation

    As introduced in BRC-22, UTXO-based overlay networks provide a secure and scalable solution to managing states derived from the Bitcoin network. In order to enable users to query the state of these overlay networks and retrieve relevant UTXOs, a standardized method for lookup services is required. This document aims to address this need by outlining a clear and well-defined process for submitting queries to overlay network nodes and retrieving the resultant UTXOs.

    Specification

    We build on the node first described in BRC-22 and hook into the output admittance and spend events that naturally occur as transactions are submitted. When transactions are received, topical logic determines which outputs will be part of which overlay networks, and we specify that the lookup services respond to these events.

    API Endpoint and JSON Parameters

    The BRC-31 protected server will host a POST /lookup API endpoint, which accepts JSON request payloads. The JSON request body will include a provider, which is a string denoting the chosen provider, and a query field, whose meaning is determined by the specific provider being chosen.

    Overlay Network Node Processing Steps

    Upon receiving a query, the overlay network node will perform the following steps:

    1. Engage in BRC-31 authentication and learn the identity of the person making the request, to the extent required in order to fulfill the request.

    2. If consistent with the policy set by the node operator, charge a BRC-41 payment based on the query being performed, providing a mechanism by which the node can monetize its operations.

    3. Check that the provider stipulated by the request is supported on this node. If not, return a JSON error response with a status key of error, a code of ERR_LOOKUP_SERVICE_NOT_SUPPORTED, and a description comprising a human-readable error message.

    4. Send the query to the provider for processing. The provider will use the current known state of the overlay in conjunction with its data storage and retrieval system to fulfill the query.

    5. The provider returns a responsive list of current topical UTXO identifiers (topic labels + TXIDs + output numbers) to the overlay network node, where each identifier is for a UTXO that is currently admitted into a topical overlay.

    6. After retrieving the list of UTXOs responsive to the query from the lookup service provider, the overlay network node will hydrate each UTXO with its output script, amount, encompassing transaction, and other information. The format for the UTXOs constructed by this process is defined by .

    7. The node will then return a JSON response to the consumer, comprising an array of -style UTXOs.

    Lookup Service Providers

    Each lookup service is assigned a provider identifier by the overlay network node so that multiple can be installed simultaneously. For each provider, the overlay network node will send events when new UTXOs are added and when they later become spent. The events will contain the output script, the number of satoshis, the TXID, the output number from the transaction, and the topic identifier for the topic where the output was added or removed.

    Each lookup service maintains its own data storage and retrieval mechanism independently. This allows each service to use the most appropriate solution for the specific data being managed. Each service chooses how it will respond to these events, which could involve adding, removing, incrementing, decrementing, replacing, updating, or otherwise mutating data storage and retrieval systems applicable to its specific use-case or indexing methodology. Providers are under no obligation to process events for all topics and can freely drop events they deem irrelevant to their operations. Each service will do this in a way so that it can later provide effective responses to queries.

    Payments for Queries

    The /lookup route may be behind a BRC-41 paywall to provide a monetization mechanism for overlay network server operators. The rules for this paywall are determined by the specific server being queried and can be based on any aspect of the query being made. All state consumers must be prepared to furnish a BRC-41 payment for lookup requests if enabled by the server, unless the client knows for certain that a payment will not be charged.

    This means that consumers should be prepared to handle potential payment requirements when making lookup requests, as the server operator may have implemented a BRC-41 paywall to monetize access to the overlay network's state.

    In either case, all lookup provider queries are always protected by BRC-31 authentication, as with BRC-22's /submit route, ensuring there are digitally signed records of all requests and responses between the parties.

    Example Requests and Responses

    Below are examples of an HTTP request and response for the /lookup route.

    Request

    Response

    In this example, a client submits a query to the /lookup API endpoint. The JSON payload contains a provider field specifying the desired lookup service provider and a query field with the specific query parameters.

    The overlay network node processes the query and returns an HTTP response containing an array of BRC-36-style UTXOs that match the query's criteria. The response includes the topic, TXID, output index, output script, number of satoshis, and other BRC-8 fields for each UTXO.

    Implementation

    Developers should extend their BRC-31 protected server to host the POST /lookup API endpoint. For monetization, a BRC-41 paywall may be configured in front of the /lookup endpoint, and may charge for lookups based on the queries being performed or the volume of information requested. Developers should ensure that their implementation adheres to the JSON request and response structures specified in this document.

    BRC-31

    Confederacy Host Interconnect Protocol (CHIP)

    Ty Everett ([email protected])

    Abstract

    We outline the Confederacy Host Interconnect Protocol (CHIP), a peer discovery mechanism for UTXO-based overlay networks. CHIP is an overlay network which tracks active network operators hosting specific topics, facilitating UTXO discovery, providing robust availability guarantees, thus enabling fault tolerance. This document specifies the format for CHIP tokens, their propagation across the network, and the process of using them to find and connect with hosts.

    Motivation

    The standard defines a method for running a server that accepts transactions, admits their outputs into topics, and tracks topical UTXO sets. However, there is a need for a connectivity and peer discovery mechanism for users who want to stay loosely in sync with one another. CHIP addresses this need, ensuring efficient synchronization and data propagation by facilitating the discovery of network operators actively hosting specific topics.

    Specification

    We define the various components of the Confederacy Host Interconnect architecture.

    CHIP Token Format

    CHIP tokens are registered on the Bitcoin SV blockchain as single-satoshi outputs representing hosting advertisements by Confederacy network operators. The token fields are ordered as follows:

    Field
    Meaning

    Token Creation and Submission

    The advertiser creates a transaction output containing the token and submits it to known nodes, including their own. The locking key must be linked to the advertiser's identity key using the and methodologies.

    The advertiser follows these steps to derive the locking key, compute the signature, and advertise the transaction to all known nodes:

    1. Deriving the Locking Key:

      • Use the advertiser's identity key as the sender private key in the key derivation, with the "anyone" public key (1 by G) as the counterparty.

      • Compute the invoice number using the

    There is no need to advertise that nodes host CHIP itself. It is assumed that all nodes which understand and receive CHIP advertisements intrinsically host CHIP, as they are already participating in the CHIP network and processing the advertisements.

    Token Validation and Admission

    Nodes accepting CHIP tokens must validate the identity key's link to the signature-producing key before admitting the output. Invalid tokens must be rejected. The following steps detail the token validation process:

    • Step 1: Extract token fields. Upon receiving a CHIP token, the node should first extract the four fields as defined in the token format. These fields include the CHIP identifier, the advertiser's identity key, the domain name of the HTTPS server hosting the network node, and the topic name hosted by the advertiser.

    • Step 2: Verify the CHIP identifier. Check that the first field of the token is the string CHIP. If this condition is not met, reject the token as invalid.

    • Step 3: Verify the locking key.

    CHIP Lookup Service

    The CHIP lookup service enables network users to access and query for CHIP advertisement UTXOs in a standardized way. By facilitating access to these UTXOs, users can discover other nodes that may have the data they need, enhancing connectivity across the UTXO-based overlay network.

    Provider Name

    The specified provider name for the lookup service is CHIP. This standardized name allows implementations to easily recognize and interact with the service.

    Query Processing

    The lookup service processes queries as JSON objects containing "topic" and "advertiser" keys. These keys are used in an AND stipulation to filter the results based on the provided values. The service searches the UTXOs for matches that satisfy both conditions (if present) and returns the corresponding results.

    Query Fields and AND Stipulation

    The query fields are as follows:

    Field
    Meaning

    The AND stipulation operates by requiring both topic and advertiser conditions to be satisfied for a UTXO to be included in the result set. If only one key is provided, the lookup service will return UTXOs matching that single condition. If both keys are present, the service will only return UTXOs that match both the specified topic and advertiser.

    Query Examples

    Example 1: Query with only "topic"

    In this example, the lookup service will return all UTXOs with the specified "example_topic", regardless of the advertiser.

    Example 2: Query with only "advertiser"

    Here, the service will return all UTXOs from the specified advertiser, regardless of the topic.

    Example 3: Query with both "topic" and "advertiser"

    In this case, the lookup service will return UTXOs that match both the specified topic and advertiser, providing more precise results.

    Discovering Nodes Hosting a Topic of Interest

    This section details the process for an overlay network user to discover nodes hosting a particular topic they are interested in. The user will follow these steps to locate relevant nodes and notify them about a new transaction in the topic:

    • Query the CHIP Lookup Service. The user initiates the process by querying the CHIP lookup service through a known node. The query contains the desired "topic" key, and optionally the "advertiser" key if the user wants to find a specific advertiser hosting the topic. The lookup service returns a list of UTXOs with corresponding CHIP tokens containing relevant domain names and identity keys of advertisers.

    • Contacting Servers and Notifying about the New Transaction. Upon receiving the list of UTXOs, the user extracts the domain names and identity keys of the relevant nodes. The user then contacts each server at their respective domain via the protocol, notifying them about a new transaction in the topic.

    • Verifying Identity Key during Transaction Submission.

    By following these steps, an overlay network user can discover nodes hosting a specific topic of interest and securely engage with them to submit transactions to the relevant topic. This process enhances the connectivity and efficiency of UTXO-based overlay networks and ensures the security of transactions between nodes.

    Implementation

    There are no known implementations of this specification at this time. The specification will be updated when an implementation is published.

    Paymail Payment Destinations

    Abstract

    We specify the widely-used protocols for exchanging payments between users of the Paymail system within the Bitcoin SV network. Paymail is a user-friendly alternative to traditional Bitcoin addresses, leveraging human-readable names at a domain, such as [email protected]. This standard aims to provide a clear and concise specification for wallet implementers to facilitate incoming and outgoing payments using Paymail addresses. BRC-28 encompasses the pre-existing payment destination and payment exchange protocols, ensuring compatibility and interoperability across Bitcoin SV wallet applications.

    Motivation

    The primary motivation behind BRC-28 is to address the usability and complexity issues associated with traditional Bitcoin addresses. These addresses, comprised of long strings of alphanumeric characters, can be difficult to remember and prone to user errors when transcribing or sharing. By introducing the Paymail protocol, which replaces complex addresses with human-readable names, the overall user experience of Bitcoin SV transactions is significantly improved.

    However, for Paymail to be widely adopted and to ensure seamless transactions across wallet applications, a standardized approach is necessary. BRC-28 aims to provide this standardization by specifying the payment destination and payment exchange protocols, allowing wallet implementers to incorporate Paymail support in a consistent and interoperable manner.

    Furthermore, Paymail provides a scalable solution to the problem of blockchain scanning. With traditional addresses, the recipient must scan the blockchain to be notified about their incoming payments. With the peer-to-peer Paymail approach, transactions are handed directly from the sender to the recipient and subsequently broadcasted upon acceptance, removing the need for blockchain scanning services.

    Specification

    The BRC-28 specification comprises two main components: P2P Transactions and P2P Payment Destination. These components work in tandem to facilitate the exchange of Paymail transactions in a peer-to-peer manner, eliminating the need for blockchain scanning services and enabling scalable Bitcoin SV wallet applications.

    P2P Transactions

    1.1 Capability Discovery

    The Paymail provider's .well-known/bsvalias document must be updated to include a declaration of the endpoint for receiving transactions:

    The capabilities.5f1323cddf31 field contains a URL where the sender must POST the transaction data.

    1.2 Client Request

    The sender must replace the {alias} and {domain.tld} placeholders in the URI template provided by capabilities.5f1323cddf31 with a valid Paymail handle. The client must then perform a POST HTTP request with the following body:

    1.3 Server Response

    The server must validate the transaction and respond with the accepted transaction ID and an optional human-readable note.

    P2P Payment Destination

    2.1 Capability Discovery

    The Paymail provider's .well-known/bsvalias document must be updated to include a declaration of the endpoint for generating P2P payment destinations:

    The capabilities.2a40af698840 field contains a URL where the sender must POST the required satoshis for the transaction.

    2.2 Client Request

    The sender must replace the {alias} and {domain.tld} placeholders in the URI template provided by capabilities.2a40af698840 with a valid Paymail handle. The client must then perform a POST HTTP request with the following body:

    2.3 Server Response

    The server must generate a list of outputs and a reference number for the payment and respond with the following structure:

    The BRC-28 specification, encompassing P2P Transactions and P2P Payment Destination, provides a clear and concise protocol for wallet implementers to support Paymail-based transactions in a consistent and interoperable manner. By adhering to this specification, developers can create compatible implementations that facilitate seamless Paymail transactions, benefiting end-users.

    Implementations

    Various implementations have been created which facilitate Paymail payment destination discovery, and the hosting of Paymail servers:

    • is a server-side package that hosts a set of compatible endpoints.

    • is a JavaScript client for interacting with the Paymail protocol.

    • is the Paymail client created by Project Babbage [deprecated (no longer in active use)].

    Auxiliary Information on Host and Capability Discovery

    In the interest of completeness, we provide some auxiliary information that may be useful for implementers wishing to run Paymail servers. While the main objective of BRC-28 is to define the specifications for peer-to-peer payment destinations and transaction submission, we provide this additional information about service and capability discovery so that future implementers can interoperate.

    Paymail Addresses

    Paymail addresses follow the format <alias>@<domain.tld>, similar to email addresses. The <alias> represents a user or an account within a domain, while <domain.tld> represents the domain owner's unique domain name. Paymail addresses must only contain alphanumeric characters, periods, and hyphens, with the @ symbol separating the alias from the domain.

    Paymail Host Discovery

    Paymail Host Discovery is the process of determining the appropriate host to query for Capability Discovery. Host Discovery relies on SRV DNS records to indicate the specific web host to interrogate. Domain owners can create an SRV record with specified parameters to delegate authority to a third-party Paymail service provider or to configure their own Paymail service:

    SRV Record Attribute
    Value

    Paymail Capability Discovery

    Paymail Capability Discovery is the process by which a Paymail client learns the supported features of a Paymail service, as well as their respective endpoints and configurations. Capability Discovery uses a well-known file, a machine-readable JSON-formatted document placed in a predictable location on a web server.

    The well-known file's location should be:

    This file contains the supported capabilities and their associated endpoints, with template strings {alias} and {domain.tld} used to represent the components of a Paymail address. Clients should replace these template strings with the actual values from the Paymail address.

    To perform Capability Discovery, a Paymail client constructs an HTTP GET request to https://<target>:<port>/.well-known/bsvalias after retrieving a Target:Port pair from Host Discovery. A successful request provides the client with the necessary configuration information to interact with the Paymail service and access its supported extension protocols.

    Confederacy Lookup Availability Protocol (CLAP)

    Ty Everett ([email protected])

    Abstract

    We specify the Confederacy Lookup Availability Protocol (CLAP), a protocol for advertising the availability of BRC-24 lookup services on overlay network nodes. CLAP is an extension of BRC-23 that focuses on advertising the availability of lookup services instead of topics. By enabling the discovery of lookup services provided by various network operators, CLAP facilitates efficient and decentralized access to relevant data. This document details the format for CLAP tokens, their propagation across the network, and the process of using them to find and connect with hosts offering lookup services.

    Motivation

    While provides a mechanism for resolving which topics are hosted on which nodes, there is a need for a similar protocol that advertises the availability of lookup services. The underlying motivations for BRC-25 are similar to those for , with the primary goal of facilitating efficient access to and discovery of lookup services in a decentralized manner.

    Specification

    In a similar manner to CHIP, we specify the various components of the CLAP architecture:

    CLAP Token Format

    CLAP tokens are registered on the Bitcoin SV blockchain as single-satoshi outputs representing lookup service advertisements by Confederacy network operators. The token fields are ordered as follows:

    Field
    Meaning

    Token Creation and Submission

    The advertiser creates a transaction output containing the token and submits it to known nodes, including their own. The locking key must be linked to the advertiser's identity key using the and methodologies.

    The advertiser follows these steps to derive the locking key, compute the signature, and advertise the transaction to all known nodes:

    1. Deriving the Locking Key:

      • Use the advertiser's identity key as the sender private key in the key derivation, with the "anyone" public key (1 by G) as the counterparty.

      • Compute the invoice number using the

    There is no need to advertise that nodes host CLAP itself. It is assumed that all nodes which understand and receive CLAP advertisements intrinsically host CLAP, as they are already participating in the CLAP network and processing the advertisements.

    Token Validation and Admission

    Nodes accepting CLAP tokens must validate the identity key's link to the signature-producing key before admitting the output. Invalid tokens must be rejected. The following steps detail the token validation process:

    • Step 1: Extract token fields. Upon receiving a CLAP token, the node should first extract the four fields as defined in the token format. These fields include the CLAP identifier, the advertiser's identity key, the domain name of the HTTPS server hosting the network node, and the service name represented by a provider ID.

    • Step 2: Verify the CLAP identifier. Check that the first field of the token is the string CLAP. If this condition is not met, reject the token as invalid.

    • Step 3: Verify the

    CLAP Lookup Service

    The CLAP lookup service enables network users to access and query for CLAP advertisement UTXOs in a standardized way. By facilitating access to these UTXOs, users can discover other nodes that may have the lookup services they need, enhancing connectivity across the UTXO-based overlay network.

    Provider Name

    The specified provider name for the lookup service is CLAP. This standardized name allows implementations to easily recognize and interact with the service.

    Query Processing

    The lookup service processes queries as JSON objects containing "service" and "advertiser" keys. These keys are used in an AND stipulation to filter the results based on the provided values. The service searches the UTXOs for matches that satisfy both conditions (if present) and returns the corresponding results.

    Query Fields and AND Stipulation

    The query fields are as follows:

    Field
    Meaning

    The AND stipulation operates by requiring both service and advertiser conditions to be satisfied for a UTXO to be included in the result set. If only one key is provided, the lookup service will return UTXOs matching that single condition. If both keys are present, the service will only return UTXOs that match both the specified service and advertiser.

    Query Examples

    Example 1: Query with only "service"

    In this example, the lookup service will return all UTXOs with the specified "example_service", regardless of the advertiser.

    Example 2: Query with only "advertiser"

    Here, the service will return all UTXOs from the specified advertiser, regardless of the service.

    Example 3: Query with both "service" and "advertiser"

    In this case, the lookup service will return UTXOs that match both the specified service and advertiser, providing more precise results.

    Discovering Nodes Hosting a Lookup Service of Interest

    This section details the process for an overlay network user to discover nodes hosting a particular lookup service they are interested in. The user will follow these steps to locate relevant nodes and make a query from the service:

    • Query the CLAP Lookup Service. The user initiates the process by querying the CLAP lookup service through a known node. The query contains the desired "service" key, and optionally the "advertiser" key if the user wants to find a specific advertiser hosting the service. The CLAP lookup service returns a list of UTXOs with corresponding CLAP tokens containing relevant domain names and identity keys of advertisers.

    • Contacting Servers and Performing Queries. Upon receiving the list of UTXOs, the user extracts the domain names and identity keys of the relevant nodes. The user then contacts each server at their respective domain via the protocol, making use of the service to run a query and receive the results.

    • Verifying Identity Key during Lookup. During the UTXO lookup process, the user verifies that the identity key of the advertiser matches the key used by the server for authentication. This step ensures that the server is the intended recipient and maintains the integrity of the lookup process.

    By following these steps, an overlay network user can discover nodes hosting a specific lookup service of interest and securely engage with them to learn about the current state of various overlays. This process enhances the connectivity and efficiency of UTXO-based overlay networks.

    Implementation

    There are no known implementations of this specification at this time. The specification will be updated when an implementation is published.

    BSV Key Derivation Scheme (BKDS)

    Ty Everett ([email protected])

    Abstract

    This technical standard proposes a key derivation method that allows two parties to derive multiple keys for each other in an open-ended manner. The method employs invoice numbers as a simple way for multiple keys to be derived. A sender can derive a public key for a recipient without knowing the recipient's corresponding private key, and the recipient can later use the sender's public key and the same invoice number to derive a corresponding private key. The proposed method removes the limit of 4 billion keys per child that is present in BIP32, improves the privacy of the involved parties by employing ECDH shared secrets, and enables an open-ended invoice numbering scheme for key derivation that can be further standardized for specific use-cases. The method can be used for private invoicing, digital signatures, symmetric cryptography, and other applications in Bitcoin and CBDC ecosystems.

    Enhanced Mandala Token Protocol

    Jake Jones ([email protected])

    Abstract

    This proposal extends BRC-92 (Mandala Token Protocol) with cryptographic commitments to provide tamper-evident token amounts and SPV-friendly verification while maintaining the minimalist design philosophy. The enhancement adds a commitment hash to each token output that cryptographically binds the token amount to its transaction history, enabling lightweight clients to verify token integrity without accessing the full blockchain or trusting overlay networks.

    POST /submit HTTP/1.1
    Host: example-overlay-node.com
    Content-Type: application/json
    X-Authrite: 0.1
    X-Authrite-Identity-Key: ...
    X-Authrite-Signature: ...
    X-Authrite-Nonce: ...
    X-Authrite-YourNonce: ...
    X-Authrite-Certificates: ...
    {
      "rawTx": "0100000001abcdef...",
      "inputs": {
        "...": "..."
      },
      "mapiResponses": [
        {
          "payload": "0100000001abcdef...",
          "signature": "MEQCIGXFM...",
          "publicKey": "036b8c86..."
        }
      ],
      "topics": [
        "example_topic_1",
        "example_topic_2"
      ]
    }
    HTTP/1.1 200 OK
    Content-Type: application/json
    X-Authrite: 0.1
    X-Authrite-Identity-Key: ...
    X-Authrite-Signature: ...
    X-Authrite-Nonce: ...
    X-Authrite-YourNonce: ...
    X-Authrite-Certificates: ...
    {
      "status": "success",
      "topics": {
        "example_topic_1": [0, 2],
        "example_topic_2": [1, 2]
      }
    }
    {
      "basket": "todo tokens",
      "includeEnvelope": true,
      "limit": 25,
      "offset": 0,
      "spendable": true
    }
    [{
      "amount":1000,
      "customInstructions":null,
      "envelope":{
        "rawTx":"010000000135620d3a8fb626b763cb7b9a3c3197eda9bd6709ef1e4ebc2b359607800eaa95020000006b483045022100c3ec1792f1780e453c6ea692271bcc5388fb179d6455897f4b4200706e8b9f150220352cc2ff81a5c698e4626aec8976643134efab91ca1c80729670c2d007c77cfd4121037798f038cb7fc18b9d67baa87ed33122eb7be65b95b0dd304dc476c60043773dffffffff03e803000000000000c4210399322f558d92ced9c45d3bfe7dc5c01b830a4b61d71695ab0a1fa2cd90aba8b9ac2131546f446f44744b7265457a6248594b466a6d6f42756475466d53585855475a473462812d4eeb030fa496c2965f7e0f0b0e825d0547aceb7a9d4c76fd17e795753d8e2e0e82274ab36744a7968a43dc45b1cbdfab6c473045022100a58914da5346960ecb4de964f0f1e1be43a7645a11449c3a209f3fd69b34209b02205d4d4294d04c5f87fb16c2cdc3d9b41f9866fb3d7a690da08089c972d1393d816d75c8000000000000001976a91473a95c0b12e33b3d79f80508200a075bbab0906588ac4ea80200000000001976a91478daf10df51b3ea4c9292a72bf2e1e1d48ebe11288ac00000000",
        "mapiResponses":[{
          "publicKey":"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
          "payload":"{\"apiVersion\":\"1.5.0\",\"timestamp\":\"2023-04-07T08:19:10.2186219Z\",\"txid\":\"900b7e9ced44f8a7605bd4c1b7054b8fb958385998954d772820a8b81eabb56f\",\"returnResult\":\"success\",\"resultDescription\":\"\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"000000000000032b2a17b3003b5cbb484b284bda4ffd7c15edd6c038429840ed\",\"currentHighestBlockHeight\":1545664,\"txSecondMempoolExpiry\":0,\"warnings\":[],\"failureRetryable\":false}",
          "signature":"30440220066e711073f08d6302a33acb2863557b13465f5381a3355eaee9a5e08909abfc0220695fedf9800226d9f430f8a0177c1e4bde8134d350a8eb3bfd0d5d77925cac4d"
        }],
        "inputs":{
          "95aa0e800796352bbc4e1eef0967bda9ed97313c9a7bcb63b726b68f3a0d6235":{
            "rawTx":"0100000001ce31fcf049468a1e3a2cd56c598d5452f6bfbc95bac036eda769531795e3198c020000006a4730440220721e1e12c2540cccf01fed09560daf2dddebec959e39481c6f27bf366d8b3c5d0220040562db8f91b13b7ad33ac9f01adbbfa748c375ff2c8201929828537e7fb81841210306d6a463a7f204b050ffeba596fe9a2466f416b008d6954ce425304660abe450ffffffff0322020000000000001976a914268b68eb0ee5ed10decbf38fa47cdc2e3df7af2b88acc8000000000000001976a91426db399bdfe2ff5e413c60930b3f760a4db625db88ac30ad0200000000001976a9149cbb583bcc1d80d37669e930dca22655d621990088ac00000000",
            "proof":{
              "txOrId":"95aa0e800796352bbc4e1eef0967bda9ed97313c9a7bcb63b726b68f3a0d6235","target":"a4f45102baefabafb1ad7376f754c219411e45439fd31c2b082051f0e58e08e3",
              "targetType":"merkleRoot",
              "nodes":[
                "8d8403f47e3e9a461848b5d45ee173d49ef4afb2c952e26ff2ffa95e2ae96a7c",
                "04f653cc1e2e5376600ec83c93d3ac7309dd29662b69f329511a020c9ecf5b67",
                "3c8a8b183008fa56dfe432ab7ccb10e47e36537c21a152466de7e1a3572a5286",
                "cb798749f39ce21c360cea90973a2eeb4740a7db05b7f42f1b33b81448369753",
                "3fb4036561bb38c0c2096512818bcfc425ead33f0a10272def77d8bf6243ae94"
              ],
              "index":15
            }
          }
        }
      },
      "outputScript":"210399322f558d92ced9c45d3bfe7dc5c01b830a4b61d71695ab0a1fa2cd90aba8b9ac2131546f446f44744b7265457a6248594b466a6d6f42756475466d53585855475a473462812d4eeb030fa496c2965f7e0f0b0e825d0547aceb7a9d4c76fd17e795753d8e2e0e82274ab36744a7968a43dc45b1cbdfab6c473045022100a58914da5346960ecb4de964f0f1e1be43a7645a11449c3a209f3fd69b34209b02205d4d4294d04c5f87fb16c2cdc3d9b41f9866fb3d7a690da08089c972d1393d816d75",
      "spendable":true,
      "txid":"900b7e9ced44f8a7605bd4c1b7054b8fb958385998954d772820a8b81eabb56f",
      "vout":0
    }]
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "You have denied permission for accessing this output basket."
    }
    {
      "status": "error",
      "code": "ERR_CERTIFIER_REJECTED_CSR",
      "description": "The certifier has rejected the CSR and refused to sign the certificate."
    }
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "The user denied the request to reveal these fields to this verifier at this time."
    }
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "You have denied permission for encrypting this data."
    }
    6a2991c9de20e38b31d7ea147bf55f5039e4bbc073160f5e0d541d1f17e321b8
    025ad43a22ac38d0bc1f8bacaabb323b5d634703b7a774c4268f6a09e4ddf79097
    0294c479f762f6baa97fbcd4393564c1d7bd8336ebd15928135bbcf575cd1a71a1
    [252, 203, 216, 184, 29, 161, 223, 212, 16, 193, 94, 99, 31, 140, 99, 43, 61, 236, 184, 67, 54, 105, 199, 47, 11, 19, 184, 127, 2, 165, 125, 9, 188, 195, 196, 39, 120, 130, 213, 95, 186, 89, 64, 28, 1, 80, 20, 213, 159, 133, 98, 253, 128, 105, 113, 247, 197, 152, 236, 64, 166, 207, 113, 134, 65, 38, 58, 24, 127, 145, 140, 206, 47, 70, 146, 84, 186, 72, 95, 35, 154, 112, 178, 55, 72, 124]
    BRC-2 Encryption Compliance Validated!
    [81, 240, 18, 153, 163, 45, 174, 85, 9, 246, 142, 125, 209, 133, 82, 76, 254, 103, 46, 182, 86, 59, 219, 61, 126, 30, 176, 232, 233, 100, 234, 14]
    BRC-2 HMAC Compliance Validated!
    21 <assetId> <amount> OP_DROP OP_2DROP ...
    21 <assetId> OP_2DROP ...
    const details = {
    	entity: 'Local Comedy Troupe',
    	asset: 'Ticket for show on 9/01/2024',
    	address: '412 E 6th St, Austin, TX 78701'
    }
    
    const commitment = hash(details)
    const anyone = new PrivateKey(1)
    const pubkey = identityPublicKey.deriveChild(anyone, commitment)
    <securityLevel>-<protocolID>-<keyID>
    POST /lookup HTTP/1.1
    Host: example-overlay-node.com
    Content-Type: application/json
    X-Authrite: 0.1
    X-Authrite-Identity-Key: ...
    X-Authrite-Signature: ...
    X-Authrite-Nonce: ...
    X-Authrite-YourNonce: ...
    X-Authrite-Certificates: ...
    {
      "provider": "example_provider",
      "query": {
        "topic": "example_topic",
        "search": "example_search_criteria"
      }
    }
    HTTP/1.1 200 OK
    Content-Type: application/json
    X-Authrite: 0.1
    X-Authrite-Identity-Key: ...
    X-Authrite-Signature: ...
    X-Authrite-Nonce: ...
    X-Authrite-YourNonce: ...
    X-Authrite-Certificates: ...
    [
      {
        "txid":"7001295a287fee8e7ad5de58ed30bd61923977ddc9b7a44830ebb9a68b12dc39",
        "vout":0,"outputScript":"4104ca0a8ce950bf2bc85115bd68818455ae2f187efc96c7527dfad98b69531ae65d13cff3e6f07263dcc64c8ccfd03884983a896b0c5887f2ec5bfd7ad739b76119ac213155485250596e4d4850755135546762334146384a5871774b6b6d5a56793568472231485438347a7272467645594658567a6b5343436f6968706d33437754586a74726b200c613f338ad70e228eaee180f65c34d72a63bdf4c9e167dd5bf70a61539e80a8096164766572746973654468747470733a2f2f73746167696e672d6e616e6f73746f72652e626162626167652e73797374656d732f63646e2f54436f5a366269715743634b574b4d6e5065695854620a31383338383430313032043834303046304402205da55600d8f260d760b37491bc3286b9faacd0d408c187e69119ddc1d98bf3fe02207996fda8d6aba1b7494d7fe8a9b7e5111ea492348f11162bc898b3f7ab2ebf486d6d6d6d",
        "topic":"UHRP",
        "satoshis":500,
        "rawTx":"0100000001e09afc3f6ed8842e3f231aac29d325c0f90137a5441bf861c7a9ee7499fafc9a020000006b483045022100cfef7385daedeb6f54a68c1188bf7d9061774f88eb391e132daea49cfcb883c60220010ba950bbb2952a1d4ace35c6721a254774c6370be75e804334be13544e4f3c412102dc35718aeb818a6075a926e8f68bd6656e5fa007a083d8f5b6193b7b1c34e3f7ffffffff03f401000000000000fd53014104ca0a8ce950bf2bc85115bd68818455ae2f187efc96c7527dfad98b69531ae65d13cff3e6f07263dcc64c8ccfd03884983a896b0c5887f2ec5bfd7ad739b76119ac213155485250596e4d4850755135546762334146384a5871774b6b6d5a56793568472231485438347a7272467645594658567a6b5343436f6968706d33437754586a74726b200c613f338ad70e228eaee180f65c34d72a63bdf4c9e167dd5bf70a61539e80a8096164766572746973654468747470733a2f2f73746167696e672d6e616e6f73746f72652e626162626167652e73797374656d732f63646e2f54436f5a366269715743634b574b4d6e5065695854620a31383338383430313032043834303046304402205da55600d8f260d760b37491bc3286b9faacd0d408c187e69119ddc1d98bf3fe02207996fda8d6aba1b7494d7fe8a9b7e5111ea492348f11162bc898b3f7ab2ebf486d6d6d6dc8000000000000001976a9148055582669432149141abcf887fced6881f7404288ac207c1202000000001976a9146a1a5f00deb78b2ef39e9a80d3e3ea2c97d0710c88ac00000000",
        "proof":null,
        "inputs":"{\"9afcfa9974eea9c761f81b44a53701f9c025d329ac1a233f2e84d86e3ffc9ae0\":{\"proof\":{\"flags\":2,\"index\":3,\"txOrId\":\"9afcfa9974eea9c761f81b44a53701f9c025d329ac1a233f2e84d86e3ffc9ae0\",\"target\":\"c99dfb20991b131142a915b086eb6413d78fb472477c31ef06495c7d712dc4e4\",\"nodes\":[\"5206842a42c144617bee40869bd73b0f65ecf6d19c75e73c7106ee2f5b271308\",\"624c68a9e2c8e83df9e55c0bc4b3a560924d6cb027285e6d6499f6445149e4ac\",\"4c02bfcd6098e40ecebab74783e1bd14d8495bccb02e4b5447057de31ed485d6\"],\"targetType\":\"merkleRoot\"},\"rawTx\":\"010000000166dee27f6d4ca528dbd664c1b6a686f9a3b18336ca396bcead7f2065ec0f07ac020000006b483045022100effd3358e1a602898e2a80b0d45b3a01bb36dfc9148b0766bc6e8185f4cf3c0c02203c3d6c6ff180d395b1300b89f96056d9ec915d6cfbf02c7cff2d6f4bb9611d1941210228ec497f7097a26ea1049ef732931d5abc40335e7693cac56d4534f15ff60aefffffffff03204e0000000000001976a9145b296c72cbec349171445808df953c2edaa3a1d388acc8000000000000001976a914d013936b4177bcbb0d934c6348b0d9ec3cc05dac88ac1e7f1202000000001976a914b281d7f257d79aebb910a5ba2c8e787f7ea635ab88ac00000000\"}}",
        "mapiResponses":"[{\"payload\":\"{\\\"apiVersion\\\":\\\"1.5.0\\\",\\\"timestamp\\\":\\\"2023-04-10T20:55:03.2794204Z\\\",\\\"txid\\\":\\\"7001295a287fee8e7ad5de58ed30bd61923977ddc9b7a44830ebb9a68b12dc39\\\",\\\"returnResult\\\":\\\"success\\\",\\\"resultDescription\\\":\\\"\\\",\\\"minerId\\\":\\\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\\\",\\\"currentHighestBlockHash\\\":\\\"00000000000004863e21305bc8cee6dd66b80a443416f14ccc5c74895fdefcac\\\",\\\"currentHighestBlockHeight\\\":1546251,\\\"txSecondMempoolExpiry\\\":0,\\\"warnings\\\":[],\\\"failureRetryable\\\":false}\",\"publicKey\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"signature\":\"304402205cd7c1b8f64de17c5824fec87549ecf46d69f122ed96971878562795d432a00702202097e309da4db38876bcaecafdd9f6234fcee999113a5fd54c909383d223a24f\"}]"
      }
    ]
    BRC-24
    1
    , the client does not check for a counterparty-specific permission grant.
  • The client makes a permission request, which the user accepts.

  • The client computes 1-document signing-1 as the invoice number.

  • The client uses its own private key as the sender, and the public key 1 * G as the counterparty, as the counterparty is anyone.

  • The client derives a child private key as the recipient using the invoice number, and uses the derived key to compute the digital signature.

  • Any verifier can now use 1 as a private key in conjunction with the signer's root public key and the same invoice number to derive the corresponding child public key used for the signature.

  • The verifier can then check the signature against the derived child public key for validity.

  • , the client must check for a counterparty-specific permission grant specific to Bob under this protocol.
  • Alice's client makes a permission request, which Alice accepts.

  • Alice's client computes 2-private document signing-1337 as the invoice number.

  • Alice's client uses her own private key as the sender, and Bob's public key as the counterparty.

  • Alice's client derives a child private key as the recipient using the invoice number, and uses the derived key to compute the digital signature.

  • Bob's client can now use his private key in conjunction with Alice's root public key and the same invoice number to derive the corresponding child public key used for the signature.

  • Bob's client can then check the signature against the derived child public key for validity. No one aside from Alice and Bob can check the signature for validity.

  • BRC-3
    BRC-3
    BRC-36
    BRC-36

    offset

    no

    The number of outputs from the beginning of the list to skip

    spendable

    no

    Always considered to be true, included by some implementations for historical reasons

    envelope

    If envelopes were requested, the BRC-8 Transaction Envelope for this transaction

    BRC-8
    BRC-2
    BRC-52
    BRC-52
    BRC-52

    6

    XDM Wallet Communications Substrate

    7

    Window Wallet Communication Substrate

    8

    Everett-style Transaction Envelopes

    9

    Simplified Payment Verification

    10

    Merkle proof standardised format

    11

    TSC Proof Format with Heights

    12

    Raw Transaction Format

    13

    TXO Transaction Object Format

    14

    Bitcoin Script Binary, Hex and ASM Formats

    15

    Bitcoin Script Assembly Language

    16

    Pay to Public Key Hash

    17

    Pay to R Puzzle Hash

    18

    Pay to False Return

    19

    Pay to True Return

    20

    There is no BRC-20

    21

    Push TX

    22

    Overlay Network Data Synchronization

    23

    Confederacy Host Interconnect Protocol (CHIP)

    24

    Overlay Network Lookup Services

    25

    Confederacy Lookup Availability Protocol (CLAP)

    26

    Universal Hash Resolution Protocol

    27

    Direct Payment Protocol (DPP)

    28

    Paymail Payment Destinations

    29

    Simple Authenticated BSV P2PKH Payment Protocol

    30

    Transaction Extended Format (EF)

    31

    Authrite Mutual Authentication

    32

    BIP32 Key Derivation Scheme

    33

    PeerServ Message Relay Interface

    34

    PeerServ Host Interconnect Protocol

    35

    (unused, will assign next BRC to this number)

    36

    Format for Bitcoin Outpoints

    37

    Spending Instructions Extension for UTXO Storage Format

    38

    User Wallet Data Format

    39

    User Wallet Data Format Encryption Extension

    40

    User Wallet Data Synchronization

    41

    PacketPay HTTP Payment Mechanism

    42

    BSV Key Derivation Scheme (BKDS)

    43

    Security Levels, Protocol IDs, Key IDs and Counterparties

    44

    Admin-reserved and Prohibited Key Derivation Protocols

    45

    Definition of UTXOs as Bitcoin Tokens

    46

    Wallet Transaction Output Tracking (Output Baskets)

    47

    Bare Multi-Signature

    48

    Pay to Push Drop

    49

    Users should never see an address

    50

    Submitting Received Payments to a Wallet

    51

    List of user experiences

    52

    Identity Certificates

    53

    Certificate Creation and Revelation

    54

    Hybrid Payment Mode for DPP

    55

    HTTPS Transport Mechanism for DPP

    56

    Unified Abstract Wallet-to-Application Messaging Layer

    57

    Legitimate Uses for mAPI

    58

    Merkle Path JSON format

    59

    Security and Scalability Benefits of UTXO-based Overlay Networks

    60

    Simplifying State Machine Event Chains in Bitcoin

    61

    Compound Merkle Path Format

    62

    Background Evaluation Extended Format (BEEF) Transactions

    63

    Genealogical Identity Protocol

    64

    Overlay Network Transaction History Tracking

    65

    Transaction Labels and List Actions

    66

    Output Basket Removal and Certificate Deletion

    67

    Simplified Payment Verification

    68

    Publishing Trust Anchor Details at an Internet Domain

    69

    Revealing Key Linkages

    70

    Paymail BEEF Transaction

    71

    Merkle Path Binary Format

    72

    Protecting BRC-69 Key Linkage Information in Transit

    73

    Group Permissions for App Access

    74

    BSV Unified Merkle Path (BUMP) Format

    75

    Mnemonic For Master Private Key

    76

    Graph Aware Sync Protocol

    77

    Message Signature Creation and Verification

    78

    Serialization Format for Portable Encrypted Messages

    79

    Token Exchange Protocol for UTXO-based Overlay Networks

    80

    Improving on MLD for BSV Multicast Services

    81

    Private Overlays with P2PKH Transactions

    82

    Defining a Scalable IPv6 Multicast Protocol for Blockchain Transaction Broadcast and Update Delivery

    83

    Scalable Transaction Processing in the BSV Network

    84

    Linked Key Derivation Scheme

    85

    Proven Identity Key Exchange (PIKE)

    86

    Bidirectionally Authenticated Derivation of Privacy Restricted Type 42 Keys

    87

    Standardized Naming Conventions for BRC-22 Topic Managers and BRC-24 Lookup Services

    88

    Overlay Services Synchronization Architecture

    89

    Web 3.0 Standard (at a high level)

    90

    Thoughts on the Mandala Network

    91

    Outputs, Overlays, and Scripts in the Mandala Network

    92

    Mandala Token Protocol

    93

    Limitations of BRC-69 Key Linkage Revelation

    94

    Verifiable Revelation of Shared Secrets Using Schnorr Protocol

    95

    Atomic BEEF Transactions

    96

    BEEF V2 Txid Only Extension

    97

    Extensible Proof-Type Format for Specific Key Linkage Claims

    98

    P Protocols: Allowing future wallet protocol permission schemes

    99

    P Baskets: Allowing Future Wallet Basket and Digital Asset Permission Schemes

    100

    Unified, Vendor-Neutral, Unchanging, and Open BSV Blockchain Standard Wallet-to-Application Interface

    101

    Diverse Facilitators and URL Protocols for SHIP and SLAP Overlay Advertisements

    102

    The deployment-info.json Specification

    103

    Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol

    104

    HTTP Transport for BRC-103 Mutual Authentication

    105

    HTTP Service Monetization Framework

    106

    Bitcoin Script ASM Format

    107

    Enhanced Mandala Token Protocol

    108

    Identity-Linked Token Protocol

    109

    PCW-1 : Peer Cash Wallet Protocol

    110

    Zero-Friction, Mobile-First Onboarding for MetaNet-Enabled Apps

    Banana-Powered Bitcoin Wallet Control Protocol
    Transaction Creation
    Data Encryption and Decryption
    Digital Signature Creation and Verification
    Input Redemption
    HTTP Wallet Communications Substrate
    BRC-1
    BRC-43
    BRC-43
    BRC-43
    BRC-43
    BRC-43
    BRC-43
    methodology with security level
    2
    , protocol ID
    CHIP
    , and key ID of
    1
    .
  • Derive the signing private key from your identity key using the computed invoice number.

  • Computing the Signature:

    • Use the derived private key to compute the BRC-48 signature over the token fields.

  • Advertising the Transaction:

    • Create a transaction output containing the CHIP token.

    • Submit the transaction to all known nodes, including the advertiser's own node.

  • Utilize the advertiser's claimed
    identity key as the sender public key in the
    key derivation process, with the "anyone" private key (1) as the recipient. Compute the invoice number using the
    methodology with security level 2, protocol ID CHIP, and key ID of 1. Derive the public key from the advertiser's identity key using this invoice number. Ensure that the computed key matches the
    locking key. If the keys are not linkable, reject the token as invalid.
  • Step 4: Verify the BRC-48 signature. Check the signature over the token fields by using the derived public key from the previous step. Ensure that the signature is valid and corresponds to the fields provided in the token.

  • Step 5: Admit the token. If all previous steps have been successfully completed and the token is deemed valid, admit the token into the CHIP topic.

  • During the transaction submission process to the topic, the user verifies that the identity key of the advertiser matches the key used by the server for authentication. This step ensures that the server is the intended recipient and maintains the integrity of the transaction submission process.

    Field 1

    The string CHIP, denoting a CHIP advertisement.

    Field 2

    The BRC-31 identity key of the advertiser creating the token.

    Field 3

    The internet domain name of the HTTPS server hosting the network node.

    Field 4

    The topic name hosted by the advertiser.

    topic

    The topic name hosted by the advertiser, used to filter UTXOs based on the desired topic.

    advertiser

    The BRC-31 identity key of the advertiser, used to filter UTXOs based on the specific advertiser.

    BRC-22
    BRC-48
    BRC-48
    BRC-31
    BRC-42
    BRC-43
    BRC-48
    BRC-48
    BRC-31
    BRC-42
    BRC-43
    BRC-31
    BRC-48
    BRC-24
    BRC-31
    BRC-22
    BRC-31
    BRC-42
    BRC-43
    BRC-48

    Priority

    10

    Weight

    10

    Port

    443

    Target

    <endpoint-discovery-host>

    Service

    _bsvalias

    Proto

    _tcp

    Name

    <domain>.<tld>.

    TTL (Time to Live)

    3600 (recommended for production deployments)

    Class

    IN

    Money Button Express Paymail
    Money Button Paymail Client
    AtFinder
    methodology with security level
    2
    , protocol ID
    CLAP
    , and key ID of
    1
    .
  • Derive the signing private key from your identity key using the computed invoice number.

  • Computing the Signature:

    • Use the derived private key to compute the BRC-48 signature over the token fields.

  • Advertising the Transaction:

    • Create a transaction output containing the CLAP token.

    • Submit the transaction to all known nodes, including the advertiser's own node.

  • locking key.
    Utilize the advertiser's claimed
    identity key as the sender public key in the
    key derivation process, with the "anyone" private key (1) as the recipient. Compute the invoice number using the
    methodology with security level 2, protocol ID CLAP, and key ID of 1. Derive the public key from the advertiser's identity key using this invoice number. Ensure that the computed key matches the
    locking key. If the keys are not linkable, reject the token as invalid.
  • Step 4: Verify the BRC-48 signature. Check the signature over the token fields by using the derived public key from the previous step. Ensure that the signature is valid and corresponds to the fields provided in the token.

  • Step 5: Admit the token. If all previous steps have been successfully completed and the token is deemed valid, admit the token into the CLAP topic.

  • Field 1

    The string CLAP, denoting a Confederacy Lookup Availability Protocol advertisement.

    Field 2

    The BRC-31 identity key of the advertiser creating the token.

    Field 3

    The internet domain name of the HTTPS server hosting the network node.

    Field 4

    The service name, represented by a BRC-24 provider ID.

    service

    The BRC-24 provider ID of the lookup service, used to filter UTXOs based on the desired service.

    advertiser

    The BRC-31 identity key of the advertiser, used to filter UTXOs based on the specific advertiser.

    BRC-23
    BRC-23
    BRC-23
    BRC-48
    BRC-48
    BRC-31
    BRC-42
    BRC-43
    BRC-48
    BRC-48
    BRC-31
    BRC-42
    BRC-43
    BRC-31
    BRC-24
    BRC-48
    BRC-24
    BRC-24
    BRC-31
    BRC-42
    BRC-43
    BRC-48
    Motivation

    This technical standard is proposed to address the need for a standard method for key derivation between parties that enables greater ecosystem interoperability. While BIP321 provided a naive approach, it enabled only one key derivation universe per master public key. Conversely, this specification enables new key universes for every combination of two parties who interact, because the shared secret between their keys is employed. This also protects the privacy of the parties involved from outsiders who do not know the shared secret.

    The proposed key derivation method offers several benefits. It enables two parties to derive many different keys for one another in an open-ended way, thereby providing greater flexibility. The use of invoice numbers as a simple way for multiple keys to be derived makes the method easy to use and enables further standardization. The method also employs ECDH shared secrets to improve privacy, and can be auditable by revealing shared secrets between specific counterparties to tax agencies for an audit to prove transactions. Additionally, higher-order protocol identifiers, key universes, and security levels within Bitcoin wallet and application architectures have been defined for this method.

    Overall, this proposed key derivation method offers an improved approach to key derivation that can be used in various applications. It removes the limitations of existing key derivation methods such as BIP321 and provides greater flexibility, privacy, and auditability.

    Specification

    The key derivation is specified as follows:

    Identity Keys

    Each party has a master private key and a master public key that are derived from the secp256k1 elliptic curve.

    Key Derivation

    • The sender computes the shared secret by multiplying his master private key with the recipient's master public key using elliptic curve point multiplication.

    • The sender uses the shared secret as the key to generate an HMAC over the invoice number.

    • The HMAC is then converted into a scalar using big-endian encoding.

    • The generator point G is multiplied by the scalar to generate a new point on the elliptic curve.

    • The resulting point is added to the recipient's master public key point to produce a new point on the curve.

    • The resulting point is then used to generate a new child public key.

    • To derive the corresponding private key, the recipient computes the shared secret by multiplying his master private key with the sender's master public key using elliptic curve point multiplication.

    • The recipient then generates the HMAC over the invoice number using the shared secret and computes the scalar in the same way as the sender.

    • The scalar is then added to the recipient's master private key to generate the corresponding child private key.

    Invoice Number

    The invoice number is treated as a string and is converted into a buffer using UTF-8 encoding.

    Steps for the Sender

    1. The sender generates a shared secret by multiplying his master private key with the recipient's master public key using elliptic curve point multiplication.

    2. The sender generates an HMAC over the invoice number using the shared secret as the key.

    3. The HMAC is converted into a scalar using big-endian encoding.

    4. The generator point G is multiplied by the scalar to generate a new point on the elliptic curve.

    5. The resulting point is added to the recipient's master public key point to produce a new point on the curve.

    6. The resulting point is then used to generate a new child public key for the given invoice number.

    Steps for the Recipient

    1. The recipient generates the shared secret by multiplying his master private key with the sender's master public key using elliptic curve point multiplication.

    2. The recipient generates the HMAC over the invoice number using the shared secret as the key.

    3. The HMAC is converted into a scalar using big-endian encoding.

    4. The scalar is added to the recipient's master private key (mod N) to generate the corresponding child private key for the given invoice number.

    Security Considerations

    The security of this key derivation method relies on keeping the master private keys secure and the shared secret confidential. Any party with access to the shared secret could potentially derive the child keys as well, so it is important to keep the shared secret confidential. Private keys derived using this method should be treated with the same level of security as any other private key.

    Conclusion

    This specification provides a method for key derivation that enables two parties to derive many different keys for one another in an open-ended way. This method employs invoice numbers as a simple way for multiple keys to be derived and uses the secp256k1 elliptic curve for key derivation. The method is designed to be flexible and auditable, with potential applications including private invoicing,

    Implementations

    This specification has been implemented into both the BSV TypeScript and Go libraries.

    Test Vectors

    Test vectors for this standard are provided:

    For Testing Private Key Derivation

    For Testing Public Key Derivation

    Acknowledgments

    Credit is given to the people who have worked on making these ideas into reality. In particular, we thank Xiaohui Liu for creating the first known implementation of private addresses using this scheme, and Dr. Craig Wright for first describing it.

    References

    • 1: BIP32 Key Derivation Scheme

    1
    Motivation

    The original BRC-92 Mandala Token Protocol provides a minimalist approach to tokenization on BSV, but relies entirely on overlay networks to validate token conservation rules. In real-world usage scenarios, particularly SPV wallets and point-of-sale transactions, users need cryptographic assurance that token amounts haven't been tampered with. This enhancement addresses these limitations while preserving the simplicity that makes BRC-92 attractive.

    Key problems this solves:

    • SPV wallets cannot verify token conservation without trusting overlays

    • No cryptographic proof linking token amounts to their history

    • Potential for amount tampering between transaction creation and overlay submission

    • Lack of standardized verification protocol for lightweight clients

    Specification

    Enhanced Token Output Format

    Building upon BRC-92's structure, we add a cryptographic commitment field:

    Fungible Token Output

    Where:

    • 21 (0x21): UTF-8 exclamation mark prefix (unchanged from BRC-92)

    • assetId: Genesis transaction outpoint (txid:vout) (unchanged)

    • amount: Token amount in Bitcoin number format (unchanged)

    • commitment: NEW - Cryptographic commitment hash

    • ...: Functional locking script (e.g., P2PKH) (unchanged)

    Commitment Construction

    The commitment is calculated as:

    Where:

    • H: SHA-256 hash function

    • ||: Concatenation operator

    • prevTxid: Transaction ID of the input being spent

    • nonce: Optional 32-byte random value for privacy

    NFT Token Output

    For NFTs, the commitment is:

    SPV Verification Protocol

    When transferring tokens in an SPV context, the sender provides:

    Verification Steps

    Recipients MUST perform the following verification:

    1. Commitment Verification: For each input and output, verify:

    2. Conservation Check: Verify that:

    3. Merkle Proof Validation: Verify SPV proofs for recent transactions

    4. Accept/Reject: Transaction is valid if all checks pass

    Backward Compatibility

    This enhancement maintains full backward compatibility with BRC-92:

    • Existing BRC-92 tokens continue to function

    • Overlays that don't recognize commitments can ignore them (treated as extra data)

    • The drop pattern ensures scripts execute identically

    • Migration path: New tokens use commitments, old tokens grandfathered

    Privacy Considerations

    The commitment includes an optional nonce field to prevent amount analysis:

    • Without nonce: Same amounts produce same commitments (linkable)

    • With nonce: Same amounts produce different commitments (unlinkable)

    Design Justification

    Why Commitments Instead of Script Enforcement?

    Bitcoin Script's execution model prevents cross-input/output verification within scripts. Cryptographic commitments provide the next best solution:

    • Tamper-evident: Can't change amounts without breaking commitments

    • SPV-compatible: Verifiable with just transaction data

    • Minimalist: Adds only one hash field

    • Overlay-independent: Cryptographic proof doesn't require trust

    Why Include prevTxid?

    Including the previous transaction ID in the commitment:

    • Creates an unforgeable chain of custody

    • Prevents replay attacks with old commitments

    • Links each token to its complete history

    • Enables proof of lineage back to genesis

    Why Optional Nonce?

    The nonce field balances transparency and privacy:

    • Public tokens (securities): No nonce for full transparency

    • Private tokens (cash-like): Nonce prevents amount correlation

    • User choice: Applications decide based on use case

    Example Transactions

    Token Transfer with Commitments

    Input (100 tokens from previous tx):

    Outputs:

    SPV Verification Example

    Bob receives a payment at a coffee shop:

    1. Alice sends: Transaction + commitment proofs + merkle proof

    2. Bob's wallet verifies (< 100ms):

      • Commitment: H(assetId||30||prevTxid||nonce) == provided_commitment ✓

      • Conservation: 50 in == 30 + 20 out ✓

      • Merkle proof: Transaction exists in blockchain ✓

    3. Bob accepts: Payment verified without blockchain access

    Implementation Considerations

    Wallet Integration

    Wallets implementing this standard should:

    1. Generate commitments when creating token transactions

    2. Store nonces for privacy-enabled tokens

    3. Verify commitments before accepting tokens

    4. Provide SPV proof packages to recipients

    Overlay Network Integration

    Overlay networks can:

    1. Reject transactions with invalid commitments

    2. Use commitments for faster validation

    3. Provide commitment verification as a service

    4. Index tokens by commitment for quick lookups

    Performance Impact

    • Additional data: 32 bytes per output (commitment)

    • Computation: One SHA-256 hash per input/output

    • Verification time: < 1ms per token on modern devices

    • Storage: Negligible increase (< 5% for typical token transactions)

    Security Considerations

    Commitment Forgery

    Forging a commitment requires finding a hash collision:

    • SHA-256 preimage resistance: 2^256 operations

    • Collision resistance: 2^128 operations

    • Practically impossible with current technology

    Replay Attacks

    Including prevTxid prevents replay:

    • Old commitments won't match new transactions

    • Each commitment is unique to its transaction chain

    Amount Tampering

    Changing amounts breaks commitments:

    • Detectable by any verifier

    • Rejected by overlays and recipients

    Migration Path

    1. Phase 1: Wallets add commitment generation (optional)

    2. Phase 2: Overlays prefer commitment-enabled tokens

    3. Phase 3: Recipients require commitments for new tokens

    4. Phase 4: Full ecosystem adoption

    References

    • BRC-92: Mandala Token Protocol

    • BRC-62: Background Evaluation Extended Format (BEEF) Transactions

    • BRC-67: Simplified Payment Verification

    Test Vectors

    Commitment Calculation

    Input:

    Output:

    Conservation Verification

    Valid (conserves tokens):

    Invalid (creates tokens):

    Implementations

    Reference implementations available at:

    • TypeScript: Coming Soon

    • Go: Coming Soon

    • Python: Coming Soon

    {
      "topic": "example_topic"
    }
    {
      "advertiser": "02bc91718b3572462a471de6193f357b6e85ee0f8636cb87db456cb1590f913bea"
    }
    {
      "topic": "example_topic",
      "advertiser": "02bc91718b3572462a471de6193f357b6e85ee0f8636cb87db456cb1590f913bea"
    }
    {
      "bsvalias": "1.0",
      "capabilities": {
        "5f1323cddf31": "https://example.bsvalias.tld/api/receive-rawtx/{alias}@{domain.tld}"
      }
    }
    {
      "hex": "<raw_transaction_hex>",
      "metadata": {
        "sender": "<sender_paymail>",
        "pubkey": "<sender_public_key>",
        "signature": "<signature_of_txid>",
        "note": "<optional_human_readable_note>"
      },
      "reference": "<payment_reference>"
    }
    {
      "txid": "<accepted_txid>",
      "note": "<optional_human_readable_note>"
    }
    {
      "bsvalias": "1.0",
      "capabilities": {
        "2a40af698840": "https://example.bsvalias.tld/api/p2p-payment-destination/{alias}@{domain.tld}"
      }
    }
    {
      "satoshis": <number_of_satoshis>
    }
    {
      "outputs": [
        {
          "script": "<locking_script_hex_1>",
          "satoshis": <satoshis_1>
        },
        {
          "script": "<locking_script_hex_2>",
          "satoshis": <satoshis_2>
        }
      ],
      "reference": "<payment_reference>"
    }
    https://<host-discovery-target>:<host-discovery-port>/.well-known/bsvalias
    {
      "service": "example_service"
    }
    {
      "advertiser": "02bc91718b3572462a471de6193f357b6e85ee0f8636cb87db456cb1590f913bea"
    }
    {
      "service": "example_service",
      "advertiser": "02bc91718b3572462a471de6193f357b6e85ee0f8636cb87db456cb1590f913bea"
    }
    [
      {
        senderPublicKey: '033f9160df035156f1c48e75eae99914fa1a1546bec19781e8eddb900200bff9d1',
        recipientPrivateKey: '6a1751169c111b4667a6539ee1be6b7cd9f6e9c8fe011a5f2fe31e03a15e0ede',
        invoiceNumber: 'f3WCaUmnN9U=',
        privateKey: '761656715bbfa172f8f9f58f5af95d9d0dfd69014cfdcacc9a245a10ff8893ef'
      },
      {
        senderPublicKey: '027775fa43959548497eb510541ac34b01d5ee9ea768de74244a4a25f7b60fae8d',
        recipientPrivateKey: 'cab2500e206f31bc18a8af9d6f44f0b9a208c32d5cca2b22acfe9d1a213b2f36',
        invoiceNumber: '2Ska++APzEc=',
        privateKey: '09f2b48bd75f4da6429ac70b5dce863d5ed2b350b6f2119af5626914bdb7c276'
      },
      {
        senderPublicKey: '0338d2e0d12ba645578b0955026ee7554889ae4c530bd7a3b6f688233d763e169f',
        recipientPrivateKey: '7a66d0896f2c4c2c9ac55670c71a9bc1bdbdfb4e8786ee5137cea1d0a05b6f20',
        invoiceNumber: 'cN/yQ7+k7pg=',
        privateKey: '7114cd9afd1eade02f76703cc976c241246a2f26f5c4b7a3a0150ecc745da9f0'
      },
      {
        senderPublicKey: '02830212a32a47e68b98d477000bde08cb916f4d44ef49d47ccd4918d9aaabe9c8',
        recipientPrivateKey: '6e8c3da5f2fb0306a88d6bcd427cbfba0b9c7f4c930c43122a973d620ffa3036',
        invoiceNumber: 'm2/QAsmwaA4=',
        privateKey: 'f1d6fb05da1225feeddd1cf4100128afe09c3c1aadbffbd5c8bd10d329ef8f40'
      },
      {
        senderPublicKey: '03f20a7e71c4b276753969e8b7e8b67e2dbafc3958d66ecba98dedc60a6615336d',
        recipientPrivateKey: 'e9d174eff5708a0a41b32624f9b9cc97ef08f8931ed188ee58d5390cad2bf68e',
        invoiceNumber: 'jgpUIjWFlVQ=',
        privateKey: 'c5677c533f17c30f79a40744b18085632b262c0c13d87f3848c385f1389f79a6'
      }
    ]
    [
      {
        senderPrivateKey: '583755110a8c059de5cd81b8a04e1be884c46083ade3f779c1e022f6f89da94c',
        recipientPublicKey: '02c0c1e1a1f7d247827d1bcf399f0ef2deef7695c322fd91a01a91378f101b6ffc',
        invoiceNumber: 'IBioA4D/OaE=',
        publicKey: '03c1bf5baadee39721ae8c9882b3cf324f0bf3b9eb3fc1b8af8089ca7a7c2e669f'
      },
      {
        senderPrivateKey: '2c378b43d887d72200639890c11d79e8f22728d032a5733ba3d7be623d1bb118',
        recipientPublicKey: '039a9da906ecb8ced5c87971e9c2e7c921e66ad450fd4fc0a7d569fdb5bede8e0f',
        invoiceNumber: 'PWYuo9PDKvI=',
        publicKey: '0398cdf4b56a3b2e106224ff3be5253afd5b72de735d647831be51c713c9077848'
      },
      {
        senderPrivateKey: 'd5a5f70b373ce164998dff7ecd93260d7e80356d3d10abf928fb267f0a6c7be6',
        recipientPublicKey: '02745623f4e5de046b6ab59ce837efa1a959a8f28286ce9154a4781ec033b85029',
        invoiceNumber: 'X9pnS+bByrM=',
        publicKey: '0273eec9380c1a11c5a905e86c2d036e70cbefd8991d9a0cfca671f5e0bbea4a3c'
      },
      {
        senderPrivateKey: '46cd68165fd5d12d2d6519b02feb3f4d9c083109de1bfaa2b5c4836ba717523c',
        recipientPublicKey: '031e18bb0bbd3162b886007c55214c3c952bb2ae6c33dd06f57d891a60976003b1',
        invoiceNumber: '+ktmYRHv3uQ=',
        publicKey: '034c5c6bf2e52e8de8b2eb75883090ed7d1db234270907f1b0d1c2de1ddee5005d'
      },
      {
        senderPrivateKey: '7c98b8abd7967485cfb7437f9c56dd1e48ceb21a4085b8cdeb2a647f62012db4',
        recipientPublicKey: '03c8885f1e1ab4facd0f3272bb7a48b003d2e608e1619fb38b8be69336ab828f37',
        invoiceNumber: 'PPfDTTcl1ao=',
        publicKey: '03304b41cfa726096ffd9d8907fe0835f888869eda9653bca34eb7bcab870d3779'
      }
    ]
    commitment == H(assetId || amount || prevTxid || nonce)
    sum(input_amounts) == sum(output_amounts)
    21 <assetId> <amount> <commitment> OP_2DROP OP_2DROP OP_DROP ...
    commitment = H(assetId || amount || prevTxid || nonce)
    21 <assetId> <commitment> OP_2DROP OP_DROP ...
    commitment = H(assetId || prevTxid || metadata_hash)
    {
      "transaction": "hex_encoded_transaction",
      "tokenProofs": {
        "inputs": [
          {
            "index": 0,
            "amount": 100,
            "commitment": "abc123...",
            "prevTx": "def456...",
            "merkleProof": "..."
          }
        ],
        "outputs": [
          {
            "index": 0,
            "amount": 60,
            "commitment": "ghi789..."
          },
          {
            "index": 1,
            "amount": 40,
            "commitment": "jkl012..."
          }
        ],
        "conservationProof": {
          "totalIn": 100,
          "totalOut": 100
        }
      }
    }
    Previous output:
    21 <assetId> <100> <H(assetId||100||prev_prev_txid||nonce)> OP_2DROP OP_2DROP OP_DROP
    Output 0 (60 tokens to Bob):
    21 <assetId> <60> <H(assetId||60||current_input_txid||nonce1)> OP_2DROP OP_2DROP OP_DROP P2PKH(Bob)
    
    Output 1 (40 tokens change to Alice):
    21 <assetId> <40> <H(assetId||40||current_input_txid||nonce2)> OP_2DROP OP_2DROP OP_DROP P2PKH(Alice)
    assetId = "abc...def:0"
    amount = 100
    prevTxid = "123...456"
    nonce = "000...000"
    commitment = SHA256("abc...def:0" || 100 || "123...456" || "000...000")
               = "a7b8c9d0e1f2..."
    Inputs: [50, 30, 20] (sum = 100)
    Outputs: [60, 40] (sum = 100)
    Result: VALID ✓
    Inputs: [50, 30] (sum = 80)
    Outputs: [60, 40] (sum = 100)
    Result: INVALID ✗
    Burn

    Transaction Extended Format (EF)

    Abstract

    Regular Bitcoin transactions do not contain all the data that is needed to verify that the signatures in the transactions are valid. To sign an input of a Bitcoin transaction, the signer needs to know the transaction ID, output index, output satoshis and the locking script of the input transaction. When sending a Bitcoin transaction to a node, only the previous transaction ID and the output index are part of the serialized transaction, the node will look up the locking script and output amount of the input transaction.

    We propose an Extended Format (EF) for a Bitcoin transaction, that includes the locking script and the amount in satoshis of all inputs of the transaction. This allows a broadcast service to validate all aspects of a transaction without having to contact a node or an indexer for the utxos of the inputs of a transaction, speeding up the validation.

    Copyright

    This BRC is licensed under the Open BSV license.

    Motivation

    Verifying that a transaction is valid, including all signatures, is not possible at the moment without getting the unspent transaction outputs (utxos) from the transactions that are used as inputs from a Bitcoin node (or a Bitcoin indexer). This lookup of the utxos always happens inside a Bitcoin node when validating a transaction, but for a broadcast service to be able to fully validate a transaction (including the fee being paid) it also needs to look up the utxos being spent, which complicates scalability, since this lookup needs to happen on a node (via RPC), that might be too busy to react within an acceptable time frame.

    A broadcast service would be able to validate a transaction almost in full if the sender would also send the missing data (previous locking scripts and satoshi outputs) from the utxos being used in the transaction. When creating a new transaction, the previous locking scripts and satoshi outputs are needed to be able to properly sign the transaction, so the missing data is available at the time of the transaction creation. Serializing the transaction to Extended Format, instead of the standard format, is at the point of creating the transaction no extra work, but does make it much easier for a broadcast service to validate the transaction when being received, before sending the transaction to a node.

    The main motivation for this proposal is therefore scalability. When incoming transactions contain all the data that is needed to validate them, without having to contact an external service for missing data, the broadcast service becomes much more scalable.

    Specification

    Current Transaction format:

    Field
    Description
    Size

    The Extended Format adds a marker to the transaction format:

    Field
    Description
    Size

    The Extended Format marker allows a library that supports the format to recognize that it is dealing with a transaction in extended format, while a library that does not support extended format will read the transaction as having 0 inputs, 0 outputs and a future nLock time. This has been done to minimize the possible problems a legacy library will have when reading the extended format. It can in no way be recognized as a valid transaction.

    The input structure is the only additional thing that is changed in the Extended Format. The current input structure looks like this:

    Field
    Description
    Size

    In the Extended Format, we extend the input structure to include the previous locking script and satoshi outputs:

    Field
    Description
    Size

    Backward compatibility

    The Extended Format is not backwards compatible, but has been designed in such a way that existing software should not read a transaction in Extend Format as a valid (partial) transaction. The Extended Format header (0000000000EF) will be read as an empty transaction with a future nLock time in a library that does not support the Extended Format.

    Implementation

    The Extended Format has been implemented in and a standalone JavaScript library .

    Group Permissions for App Access

    Ty Everett ([email protected])

    Abstract

    This specification outlines the architecture and structure of permissions granted to apps. It focuses on the grouping of permissions to provide a concise overview for users. The key permissions include Protocol Permissions, Spending Authorizations, Basket Access, and Certificate Field Access Grants.

    Motivation

    As applications become more integrated with user data and cryptographic operations, the need for a clear and concise permission system has never been greater. This specification seeks to simplify user decisions by grouping permissions, ensuring transparency and user autonomy over their identities, their data and their digital assets.

    Specification

    Overview of Permission Types

    There are four primary permission types that apps can be granted by users, each with its significance, function, and associated specifications:

    1. Protocol Permissions (BRC-43): This permission grants an application the ability to utilize a user's keys to execute cryptographic operations (such as BRC-2 encryption or BRC-3 digital signatures).

    2. Spending Authorizations (BRC-1): As the name suggests, this allows apps to transact or spend a predefined number of satoshis over a specified time frame, within BRC-1 transactions.

    3. Basket Access (BRC-46): This pertains to the app's capability to insert into and spend UTXO-based tokens from specific BRC-46 Output Baskets. The significance of this permission is to manage token operations within the app ecosystem. Each "basket" can be thought of as a container or grouping for tokens, and BRC-46 provides the framework for how apps can interact with these baskets, ensuring a structured approach to token management.

    Group Permission Trigger Methodology

    • Applications initiate the permission request process via the waitForAuthentication function, which is part of the BRC-100 suite.

    • Wallets determine the group permissions from the application's manifest.json file.

    • The user receives a prompt detailing the permissions. They can choose to accept or deny each or all permissions. The wallet then applies their choices.

    Manifest File - manifest.json

    • The file is to be served over HTTPS and requested from the application by the wallet. HTTP is only accepted when running on localhost for development purposes.

    • The existing babbage key is expanded to include the groupPermissions key.

    • The groupPermissions

    Definition for groupPermissions key in manifest.json

    The groupPermissions key is an object that encompasses various types of permissions, which the app might request from a user. This key contains four sub-keys: protocolPermissions, spendingAuthorization, basketAccess, and certificateAccess.

    1. protocolPermissions is an array of objects, where each object defines a specific Protocol Permission. Each object contains three fields: protocolID (a protocol ID array with two elements, the first a security level and the second a protocol string), counterparty (a string in hexadecimal format representing a public key, required only if the security level of the protocolID is 2), and description (a short text explaining the purpose of this request).

    NOTE: We do not support privileged key use in group permissions for security reasons. For the purpose of grouped permission requests, privileged is always false. By nature, every use of a privileged key must be requested on a one-off basis. Thus privileged operations can never be covered by a grouped permission scheme.

    1. spendingAuthorization is an object that provides details about the satoshis an app is requesting authorization to spend. It has three fields: amount (a number indicating the amount in satoshis), duration (a number representing the time in seconds for the authorization's validity), and description.

    2. basketAccess is an array of objects, where each object denotes the access to a specific BRC-46 basket. The objects here have two fields: basket (the name of the BRC-46 basket) and description

    With this structured approach, app developers can seamlessly integrate their permission requests within their manifest.json, and users can be assured of a clear understanding of the permissions they're granting.

    For the avoidance of doubt, the following sections provide tables that define each specific field, and example data structures.

    Table 1: General Structure

    Key Name
    Value Type
    Description

    Table 2: Protocol Permissions Object Structure

    Field Name
    Value Type
    Description

    Table 3: Spending Authorization Object Structure

    Field Name
    Value Type
    Description

    Table 4: Basket Access Object Structure

    Field Name
    Value Type
    Description

    Table 5: Certificate Access Object Structure

    Field Name
    Value Type
    Description

    Examples

    1. protocolPermissions Example:

    2. spendingAuthorization Example:

    3. basketAccess Example:

    4. certificateAccess Example:

    App developers should prioritize user understanding and transparency when requesting permissions. The description field must be utilized effectively to convey the reason for the request, allowing users to make informed decisions.

    This approach ensures a streamlined and transparent process for apps to request and for users to grant permissions. It promotes a higher level of trust and clarity between applications and their users.

    Compound Merkle Path Format

    Deggen ([email protected]) Damian Orzepowski ([email protected])

    Abstract

    We propose a binary format for Compound Merkle Paths (CMP hereon) optimized for minimal data bandwidth during transmission.

    Explainer Video

    Copyright

    This BRC is licensed under the Open BSV license.

    Motivation

    Current format standards do not cover merkle paths for multiple txids within the same block. This would help reduce the overall size of data needed to express any set of paths from the same block. The larger the set the bigger the space saving.

    Specification

    For each level of the merkle path the opposite hash from the one which can be calculated is provided.

    Data Types

    Field
    Description
    Size

    Formatting Syntax

    1. offset and leaf are repeated for nLeaves at each height

    2. height does not need to be repeated, the inference is that height starts as the max height of the tree and is decremented by one each time we reach the end of the current set of leaves. Once height === -1

    Example

    Important Note

    We must include the txid and offset within a block at height 0. This is the most efficient way to store the index data required to pull out individual paths when given only a txid. In the example below we encode txids at indices 0 and 3:

    index
    txid

    By convention we reverse the bytes of a txid hex string so these sequences will be seen in their inverse endian form below.

    Hex

    Bytewise Breakdown

    Implementation

    Let's start by dumping this format as hex into a Buffer and parsing it into an object with a Buffer Reader. Then we construct an object

    JSON Encoding of a Compound Merkle Path

    If we JSON encode the leaves we get the following. Height is encoded as the position of the leaf object within the outermost array.

    You can derive individual paths for particular transaction indices as necessary using the following algorithm:

    Reading index 3 from the Compound Merkle Path.

    Which yields:

    Important to understand that we only kept the paths for indices 0 and 3 for this particular example. If you attempt to run the algo above for any other indices, an error would be thrown. This allowed us to keep 7 hashes out of 14 total. Keeping each path separately we'd have to keep minimum 6 hashes, and if we added another index then the compound method would only require one more hash, whereas saving individual paths would require another 3. The total bandwidth saving would be significant if we had thousands of transactions all in the same block.

    Merkle Proof

    We use this to prove inclusion in a block by running a Merkle Proof algorithm on the txid, index, and path. We arrive at a Merkle root hash. This can then be used as the key in a Block Header lookup to determine whether the txid is included within a block which is part of the longest chain of work.

    Transaction Creation

    Ty Everett ([email protected])

    Abstract

    We define a concise, transport-independent method by which applications can request the creation of Bitcoin transactions. We specify the use of BRC-8 transaction envelopes, and provide an open-ended and extensible approach to output stipulation by the requesting application. We define the formats for request, response and error messages exchanged between application and wallet software.

    Motivation

    The motivation behind this Bitcoin wallet transaction creation specification is to provide a standardized method for third-party applications to communicate with Bitcoin wallets. This specification aims to enable applications to request the creation of Bitcoin transactions in a concise and transport-independent way, and to allow wallets to focus on wallet and Bitcoin infrastructure, rather than application-specific functionality — conversely, applications can avoid re-inventing the wheel and the need to become their own Bitcoin wallet and infrastructure providers.

    By standardizing the communication protocol between applications and wallets, this specification aims to simplify the development of Bitcoin-related applications, reduce development time and costs, and improve the user experience of Bitcoin-powered applications. Additionally, this specification aims to promote interoperability between different wallets and applications, making it easier for users to switch between wallets and for applications to work with multiple wallets.

    Implementing this specification will provide a standard way for web and mobile applications to interface with on-device Bitcoin wallets, improving the security of Bitcoin-related operations and enabling users to better control their Bitcoin transactions. With this specification, applications can avoid the overhead of creating their own Bitcoin wallets, and wallets can focus on their core functionality of managing Bitcoin keys, signing transactions, and interacting with the Bitcoin network.

    Overall, this specification aims to provide a simple, open-ended, and extensible approach to Bitcoin transaction creation, with a transport-independent method of communication that enables wallets and applications to work together seamlessly.

    Pre-Requisites

    In order to implement this specification, Bitcoin wallet software must be able to perform the following functions:

    • Create Bitcoin transactions with any number of outputs that use arbitrary Bitcoin scripts and amounts.

    • Prompt the user for acceptance of transactions requested by third-party applications.

    • Unlock a sufficient number of UTXOs to fund the transaction and capture left-over change outputs.

    • Provide merkle proofs on all inputs to build the

    Wallets that meet these pre-requisites will be able to fulfill the requirements of this specification.

    Scope

    The scope of this specification is the definition of standard JSON formats for requesting the creation of a Bitcoin transaction, providing the completed transaction once created, and any errors that prevent the transaction from being created.

    The specification is intended to be transport-independent, so considerations related to how these messages are communicated, or matters related to the security or authenticity of such communications, are beyond the scope of this specification.

    We have sought to keep the base version of this specification as minimal as possible, while still providing all the information needed by applications. Therefore, we have decided to exclude arbitrary input redemption from this specification, and move it to an extension — namely, . We have also chosen to exclude transaction output tracking from the base specification, moving it to .

    Specification

    We specify that there are two relevant parties: an application and a Bitcoin wallet. The application is software that runs on an end-user device (such as a webpage, mobile app, or desktop app) that wants to make use of Bitcoin without building wallet infrastructure themselves. The wallet is software that runs on an end-user device that specializes in the management of a user's Bitcoin-related identity information, private keys, facilitates the transaction creation and signing process, and communicates with the Bitcoin network.

    We specify that there exists some abstract communications channel (beyond the scope of this specification) that enables the application and the Bitcoin wallet to communicate in a secure and authenticated manner. This mechanism must facilitate the application making a request to the Bitcoin wallet, and the wallet providing a response back to the application.

    We specify that JSON is the format that will be used for the messages exchanged in accordance with this specification. We further specify that there exists some out-of-band means for the application to indicate to the Bitcoin wallet that it intends to invoke and utilize this protocol, as opposed to some other protocol.

    For example, if the underlying communications method was HTTP (), the application could indicate its intention to use this protocol by sending requests to /v1/createAction instead of /v1/foobar. In effect, this means that there is no need for JSON fields in this specification denoting the message type, since both parties have already established that they are exchanging messages according to the protocol. Specific communication mechanisms that facilitate this are defined by other standards such as , and .

    Transaction Creation Request

    We specify that the first message exchanged under this protocol originates from the application, and constitutes a request by the application that a Bitcoin transaction be created by the Bitcoin wallet, as specified by the application.

    The Transaction Creation Request comprises a JSON object with the following fields, all of which are required:

    Field
    Description

    Output Objects are JSON objects that have the following fields:

    Field
    Description

    This provides the wallet with enough information to create the transaction requested by the application. Here is an example of a simple Transaction Creation Request:

    In this example, the application is stipulating that one output should be created, containing 3301 satoshis, and that the output should be locked using a pay-to-public-key-hash () locking script.

    The application also provides a simple description that can be used by the wallet when prompting the user for authorization to proceed with the creation of the transaction, or later when showing the transaction in a list.

    Transaction Creation Response

    If the transaction is successfully created by the Bitcoin wallet according to the instructions provided by the application, we specify that the Bitcoin wallet assembles a Transaction Envelope and returns it to the user. We specify that, in addition to the required envelope fields, a txid field is also included in the returned Envelope Object for the convenience of the application.

    For added clarity, we denote a table comprising the standard Transaction Envelope fields with our additional txid field:

    Field
    Description

    Here is an example of a simple Transaction Creation Response:

    Transaction Creation Error

    If the Bitcoin wallet is unable to fulfill the Transaction Creation Request for any reason, we specify that it should respond with a JSON-formatted Transaction Creation Error. The fields for the object are specified as follows:

    Field
    Description

    One example of a Transaction Creation Error is given below:

    Implementations

    This specification has been implemented into various wallets and applications:

    • The Babbage MetaNet Client implements , the local HTTP substrate including this specification. Transaction Creation Request objcts are sent to the client, which then returns either a Transaction Creation Response or a Transaction Creation Error, after prompting the user.

    • Babbage has implemented a ToDo List application that creates Transaction Creation Request objects which are then received and processed by any wallet software running on a user device that implements this specification.

    • The Ninja Bitcoin wallet, through its getTransactionWithOutputs function, accepts a Transaction Creation Request and returns either a Transaction Creation Response or a Transaction Creation Error.

    References

    • 1: Transaction responses are

    PeerServ Message Relay Interface

    Ty Everett ([email protected])

    Abstract

    This document introduces a message box architecture and relay interface to enable data exchange between two parties using a authenticated server. This system allows for message exchange and forwarding between parties who might be offline or unable to establish a direct peer-to-peer connection. While the use of a server as a go-between for peer-to-peer exchange is not novel, this system offers enough flexibility to support federation, removing the need for a single central server.

    HTTP Transport for BRC-103 Mutual Authentication

    • Ty Everett ([email protected])

    • Brayden Langley ([email protected])

    1. Abstract

    This specification defines how to

    HTTP Wallet Communications Substrate

    • Brayden Langley ([email protected])

    • Ty Everett ([email protected])

    Abstract

    positive integer VI = [[VarInt]]

    1 - 9 bytes

    list of outputs

    Transaction Output Structure

    qty with variable length per output

    nLocktime

    if non-zero and sequence numbers are < 0xFFFFFFFF: block height or timestamp when transaction is final

    4 bytes

    Extended Format transaction Input Structure

    qty with variable length per input

    Out-counter

    positive integer VI = [[VarInt]]

    1 - 9 bytes

    list of outputs

    Transaction Output Structure

    qty with variable length per output

    nLocktime

    if non-zero and sequence numbers are < 0xFFFFFFFF: block height or timestamp when transaction is final

    4 bytes

    Script

    -many bytes

    Sequence_no

    Used to iterate inputs inside a payment channel. Input is final when nSequence = 0xFFFFFFFF

    4 bytes

    Script

    -many bytes

    Sequence_no

    Used to iterate inputs inside a payment channel. Input is final when nSequence = 0xFFFFFFFF

    4 bytes

    Previous TX satoshi output

    Output value in satoshis of previous input

    4 bytes

    Previous TX script length

    Non negative integer VI = VarInt

    1 - 9 bytes

    Previous TX locking script

    Script

    <script length>-many bytes

    Version no

    currently 2

    4 bytes

    In-counter

    positive integer VI = [[VarInt]]

    1 - 9 bytes

    list of inputs

    Transaction Input Structure

    qty with variable length per input

    Version no

    currently 2

    4 bytes

    EF marker

    marker for extended format

    0000000000EF

    In-counter

    positive integer VI = [[VarInt]]

    1 - 9 bytes

    Previous Transaction hash

    TXID of the transaction the output was created in

    32 bytes

    Previous Txout-index

    Index of the output (Non negative integer)

    4 bytes

    Txin-script length

    Non negative integer VI = VarInt

    1 - 9 bytes

    Previous Transaction hash

    TXID of the transaction the output was created in

    32 bytes

    Previous Txout-index

    Index of the output (Non negative integer)

    4 bytes

    Txin-script length

    Non negative integer VI = VarInt

    1 - 9 bytes

    go-bt
    bitcoin-ef

    Out-counter

    list of inputs

    Txin-script / scriptSig

    Txin-script / scriptSig

    Certificate Field Access Grants (BRC-52): This is about identity verification. The permission allows an app to reveal specific fields from a BRC-52 identity certificate to designated verifiers. It's a crucial step in processes that require identity verification or authentication.

    key holds four subsequent keys representing the categories of permissions:
    protocolPermissions
    ,
    spendingAuthorization
    ,
    basketAccess
    , and
    certificateAccess
    .
    .
  • certificateAccess is an array of objects that represent the different certificate types an app wants access to. Each object here consists of type (indicating the certificate type), fields (an array of strings naming the fields the app wants to reveal), verifierPublicKey (a string in hex format, representing the public key of the verifier), and description.

  • Full manifest.json Example:

    protocolPermissions

    Array of Objects

    Contains Protocol Permissions requests.

    spendingAuthorization

    Object

    Contains Spending Authorization details.

    basketAccess

    Array of Objects

    Contains Basket Access requests.

    certificateAccess

    Array of Objects

    protocolID

    Array

    BRC-43 protocol ID array with two elements. First the security level between 0 and 2, followed by the protocol string.

    counterparty

    String (Hexadecimal)

    Public key, 33-byte in hex format. Only required if protocolID security level is 2.

    description

    String

    Justification for the request, less than 50 characters.

    amount

    Positive Number

    Satoshis being authorized for the app to spend.

    duration

    Positive Number

    Time in seconds for the authorization's validity.

    description

    String

    Justification for the request, less than 50 characters.

    basket

    String

    Name of the BRC-46 basket.

    description

    String

    Justification for the request, less than 50 characters.

    type

    String (base64)

    Certificate type field of a BRC-52 identity certificate.

    fields

    Array of Strings

    Array of field names being requested for revelation.

    verifierPublicKey

    String (Hexadecimal)

    Public key of the verifier in 33-byte hex format.

    description

    String

    Contains Certificate Field Access Grant requests.

    Justification for the request, less than 50 characters.

    formatted response.

    description

    A present-tense, human-readable description of the action being performed or represented by this transaction.

    outputs

    An array of Output Objects.

    script

    A hex-formatted Bitcoin output script, as defined in BRC-14.

    satoshis

    The number of satoshis that are to be in the output, given as a positive integer.

    rawTx

    The BRC-12 transaction in hex format

    inputs

    An object whose keys are the TXIDs of all inputs to this transaction and whose values are BRC-8 envelopes for the respective transactions (the child envelopes are not required to contain the extra txid field), (required unless proof is provided)

    mapiResponses

    An array of objects where each object comprises a positive endorsement of the transaction from a Bitcoin miner (required unless proof is provided)

    proof

    A BRC-10 merkle proof for the transaction in JSON format (required unless inputs and mapiResponses are given)

    txid

    The Bitcoin TXID associated with this transaction

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_NOT_SUFFICIENT_FUNDS".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    BRC-4
    BRC-46
    BRC-1
    BRC-5
    BRC-1
    BRC-5
    BRC-6
    BRC-7
    BRC-1
    BRC-16
    BRC-8
    BRC-8
    BRC-8
    BRC-5
    BRC-8 Transaction Envelopes
    BRC-8
    1
      BIP: 239
      Layer: Applications
      Title: Transaction Extended Format (TEF)
      Author: 
          Simon Ordish (@ordishs)
          Siggi Oskarsson (@icellan)
      Comments-Summary: No comments yet. 
      Comments-URI: - 
      Status: Proposal 
      Type: Standards Track 
      Created: 2022-11-09
    {
      "babbage": {
        "groupPermissions": {
          "protocolPermissions": [
            {
              "protocolID": [2, "Convo"],
              "counterparty": "...",
              "description": "For encrypted messaging."
            }
          ],
          "spendingAuthorization": {
            "amount": 10000,
            "duration": 3600,
            "description": "For in-app purchases."
          },
          "basketAccess": [
            {
              "basket": "BRC-46 Gold",
              "description": "For in-game items."
            }
          ],
          "certificateAccess": [
            {
              "type": "...",
              "fields": ["Name", "DOB"],
              "verifierPublicKey": "...",
              "description": "For age verification."
            }
          ]
        }
      }
    }
    {
      "protocolID": [2, "Convo"],
      "counterparty": "...",
      "description": "For encrypted messaging."
    }
    {
      "amount": 10000,
      "duration": 3600,
      "description": "For in-app purchases."
    }
    {
      "basket": "BRC-46 Gold",
      "description": "For in-game items."
    }
    {
      "type": "...",
      "fields": ["Name", "DOB"],
      "verifierPublicKey": "...",
      "description": "For age verification."
    }
    {
      "description": "Pay John Galt 3,301 satoshis",
      "outputs": [{
        "script": "76a914b10f7d6c7fda3285e9b98297428ed814374cbd4088ac",
        "satoshis": 3301
      }]
    }
    {
      "rawTx": "01000000017c36b9ed1c6284079fa9b2111d47e934460d2af631ceda3ffc1bf0587129d1b7020000006b483045022100c655d8c0bfc895c861dda240010c23d5267fd4414894794d3f3591fb7d59fe090220627246ff28e1776c34fd09fbbcfc5bb2efa8090350b35192f1638dd9143ea2a8412102c6848b9988deb921e645fbac47f196e7bec44a6f8612874632240aadc4a35b5bffffffff03e50c0000000000001976a914b10f7d6c7fda3285e9b98297428ed814374cbd4088acc8000000000000001976a914652138f4b89dd615def2c3aa7e13bc1900b5cff588ac1f450000000000001976a91428e5b6157e4a72d8bc8d2374f7acec1388be52f988ac00000000",
      "inputs": {
        "b7d1297158f01bfc3fdace31f62a0d4634e9471d11b2a99f0784621cedb9367c": {
          "proof": {
            "index": 16349,
            "txOrId": "b7d1297158f01bfc3fdace31f62a0d4634e9471d11b2a99f0784621cedb9367c",
            "targetType": "header",
            "target": "00c0322ac50d5e7f9cb2f9be53a34f78fe1cdd7029a03eeeb50b780000000000000000002cb6066c3101dddf29a7853051487bada9adeb9807d2ab4360ca47d3c30581138d9a1264eb370d1802029180",
            "nodes": [
              "95733f96fa3a1f0ba779627d7dc62891f6eee8a13eb0e5a5610bf0d5d1686401",
              "ac95afde3cb7d2f639e3a36d07db7b0becc4bbcb393dce51e322adc38f78c5a1",
              "4054dae1209fa48797dc459239eb396b6220618c9a8bd93776f7485f14759fb7",
              "8f6327bf637241b3e5b029475f3bf5856b263248fa18272e04ec8dae35131351",
              "4da5d84ccde803ba4515ee1f8912b49c738bbc145850d1f88885474ff57d1f58",
              "ec1e6e5c0f50ac2eb8e493c1c372aedde359cbf706643a6bdfaa3aebf4996f01",
              "cedf75aa7314f898121bccdf27eb8b6769262324460a98bf84cdaa6a0379895e",
              "246a798ac6e7e3a5893cb24aa26ca92f71309f41200e1fafbad33a138ea709d6",
              "a5df0501e2c74677b0201fa2b2a6b9cf4156f8266bbc73767e4a784d0793d557",
              "774bdbf5a5992baf1aea1cb80afb68ed93d03aba37b16b57c9fb4cf596e522e6",
              "b621a1f5f431843ed450a09c9a09f245290db204ffe2068732b7c278f4fa2605",
              "93dd7a58841fa52e8d1ac8e5d4bef852450a716c79a603dd4b85772abd0cc0db",
              "57860c6a1f278979fc4540c98f43dc41d64c6f52dffa6aaaf7b07d206e8ca5b5",
              "5de27bdb3b0123c2149d3cc8a54cab926ddc50f93639b02be0885ff9c4365fc8",
              "5cdd1beb2c59b2dbf9be5790633c0a58ea274e2669f52226343648c1a1ca31cc",
              "560490ecae5c1d075dbaf6ee26b61bd758bfbadd09a6cee475156f1b0a3fc9c7"
            ]
          },
          "rawTx": "01000000011a348074d8fe477dec48fe3c07b493371c9fa8b5a49d5d0424916a65b65e77be020000006b4830450221009acfd97f48c819d0fe0ae59df2110eb8a7f6defe948bcf556562b4d1f5e7129602202586aa5f2cb767eba3978aa3185f09e8ec745fcb1111296ca42fb384f7355b6c412102466ef576171e0e0684081f2a99b5e6b5786dac80b5d6d64fec3b033628763a4fffffffff0394070000000000001976a914d75cf5dc3ce0767b005b71b2a8705809ba4b815088acc8000000000000001976a914931c8716ddfb85f4ea4bbdad395d27bd6323b57688acea520000000000001976a914dbdbf9c3216c9cf526e18bc9f976018881972fff88ac00000000"
        }
      },
      "mapiResponses": [
        {
          "payload": "{\"apiVersion\":\"\",\"timestamp\":\"2023-03-17T05:09:51.554Z\",\"txid\":\"737a1e90af9745da3f22ef74bc71a089c5e2a76e9662a0c9fa5b7cf94fe32e75\",\"returnResult\":\"success\",\"resultDescription\":\"\",\"minerId\":\"03ad780153c47df915b3d2e23af727c68facaca4facd5f155bf5018b979b9aeb83\",\"currentHighestBlockHash\":\"00000000000000000138b377cab18dc72cc7ac38d6631949c9694071855bcce8\",\"currentHighestBlockHeight\":783508,\"txSecondMempoolExpiry\":0}",
          "publicKey": "03ad780153c47df915b3d2e23af727c68facaca4facd5f155bf5018b979b9aeb83",
          "signature": "304402201529238a9cf64b02dad0d4573ef5a0780bddb2fe6d6afdca1473e340a6e1512202204845c0721bdb8b6b8ec0e255f120e5749c373a8e2fe13fed208c3154197846c0"
        },
        {
          "payload": "{\"apiVersion\":\"1.5.0\",\"timestamp\":\"2023-03-17T05:09:51.7263993Z\",\"txid\":\"737a1e90af9745da3f22ef74bc71a089c5e2a76e9662a0c9fa5b7cf94fe32e75\",\"returnResult\":\"success\",\"resultDescription\":\"\",\"minerId\":\"030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e\",\"currentHighestBlockHash\":\"00000000000000000138b377cab18dc72cc7ac38d6631949c9694071855bcce8\",\"currentHighestBlockHeight\":783508,\"txSecondMempoolExpiry\":0,\"warnings\":[],\"failureRetryable\":false}",
          "publicKey": "030d1fe5c1b560efe196ba40540ce9017c20daa9504c4c4cec6184fc702d9f274e",
          "signature": "3044022013546dbe4b9f402ae684f3ac51bbdef5ebe5a1b1abd646b04b9a35e94515a29e022041f4b047caa6d49d1fc4ff202646939d91abd661776d75d9e5dee6b2b355645a"
        }
      ],
      "txid": "737a1e90af9745da3f22ef74bc71a089c5e2a76e9662a0c9fa5b7cf94fe32e75"
    }
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "You have denied permission for creating this Bitcoin transaction."
    }

    Each leaf is a 32 byte hash

    32 bytes

    we stop parsing.
  • nLeaves is repeated for each height, followed by the corresponding offset and leaf for each.

  • height

    The height of the tree up to a max 64

    1 byte

    nLeaves

    VarInt number of leaves at this height

    1-9 bytes

    offset

    VarInt offset from left hand side within tree

    1-9 bytes

    0

    e86ec5732f55490a73677fe88a37c875cea49f572e4bc822b83fe96093bb008c

    3

    3b5a16dc41bbed3e58ad2a9017fb8954e7541975e2a4f37343761d96f431b3e5

    leaf

    Motivation

    The Bitcoin whitepaper reveals that no existing mechanism allows payment exchange over a communication channel. Bitcoin addresses this issue by introducing a distributed timestamp server. However, obstacles such as NAT traversal issues and slow CGA adoption hinder the creation of channels for peer-to-peer general message exchange. The current internet infrastructure is not conducive to reliable peer-to-peer message exchange, lacking a proper mechanism for such exchanges between peers. This standard proposes a solution built on a BRC-31 authenticated server, which enables a simple message box architecture and relay system for peers who may not always be online.

    Specification

    The system involves a sender, a recipient, and a server. The server enforces BRC-31 authentication and identifies all parties (senders and recipients) based on their identity keys. The server offers several interfaces to facilitate message delivery, receipt, and acknowledgment between the sender and recipient through various message boxes.

    The server operates over HTTPS at an internet domain name and enforces BRC-31 authentication for all requests. It implements the following three endpoints:

    POST /sendMessage

    Send a message to a recipient's message box.

    Request Parameters

    Parameter
    Type
    Description

    message

    object

    Message object containing all relevant information

    message.recipient

    string

    The recipient's public key

    message.messageBox

    string

    The name of the recipient's message box

    Example Request:

    Response Parameters

    Parameter
    Type
    Description

    status

    string

    The status of the message sending operation

    Example Response:

    POST /listMessages

    List messages from the specified message box.

    Request Parameters

    Parameter
    Type
    Description

    messageBox

    string

    The name of the message box to retrieve messages from

    Example Request:

    Response Parameters

    Parameter
    Type
    Description

    status

    string

    The status of the message listing operation

    messages

    array

    Array of message objects

    messages[].messageId

    integer

    Unique identifier for the message

    Example Response:

    POST /acknowledgeMessage

    Acknowledge that a message has been received. After acknowledgment, the server deletes a message.

    Request Parameters

    Parameter
    Type
    Description

    messageIds

    array

    Array of message IDs to acknowledge

    Example Request:

    Response Parameters

    Parameter
    Type
    Description

    status

    string

    The status of the message acknowledgment operation

    Example Response:

    Message Authenticity and Digital Signatures

    We leave it to higher-level protocols and systems to implement appropriate digital signature schemes and message authenticity checks for their relevant use-cases. Notably, all senders and all recipients use BRC-31 authentication to communicate with the server. The messages exchanged between the parties over the server could form a second-layer BRC-31 channel, between the two users themselves.

    Federation and Synchronization

    BRC-34 and BRC-35 define the mechanism by which multiple servers can discover and route messages to one another, making use of an overlay network. When properly implemented, this enables two parties to exchange messages with one another even when not using the same server.

    Monetization

    We leave open the possibility for monetization by future specifications via BRC-41 when server operators relay or synchronize messages. When implemented, BRC-41 acts as a drop-in replacement for BRC-31 and the server operators decide on a price. Participants choose which servers they are willing to pay to interact with.

    Limitations

    This messaging system is not intended for long-term storage, but only for transport of messages. It should not be used, for example, to maintain a reliable list of all messages in a messaging application, only to facilitate the delivery of those messages to recipients. Once a recipient receives a message, they should generally store or act upon it in some way and then acknowledge it, removing it from the server.

    Implementations

    The message relay architecture has been implemented in the PeerServ API, created by the Babbage Team.

    BRC-31
    transport
    BRC-103 [1] mutual authentication messages via
    HTTP
    . It introduces:
    • A .well-known/auth endpoint for non-general BRC-103 messages (e.g. handshake, certificate requests).

    • A mechanism for embedding “general” messages in normal HTTP requests/responses using custom x-bsv-auth headers and an encoded request/response “payload.”

    • Clear rules for which HTTP headers are included in the signature and which are excluded, ensuring consistent signing and verification on both client and server.

    • An approach for referencing the remote peer’s identity key and session parameters in standard HTTP requests/responses.

    By adopting this scheme, implementers can re-use BRC-103’s cryptographic handshake and selective certificate exchange logic in a typical browser–server or server–server HTTP environment.


    2. Introduction

    BRC-103 [1] defines a peer-to-peer mutual authentication flow but leaves the transport unspecified. This document describes an HTTP layering for that flow. It details:

    • Endpoints and message paths for BRC-103 handshake messages.

    • A scheme for “general” messages that carry an entire HTTP request/response inside a single BRC-103 message.

    • Custom HTTP headers that store BRC-103 parameters (nonces, signatures, identity keys, requested certificates, etc.).

    • Mechanisms to handle typical web scenarios such as 402 Payment Required or other status codes.

    Where BRC-103 gives a general outline (initialRequest, initialResponse, general, certificateRequest, certificateResponse), BRC-104 explains how those messages appear as HTTP requests and HTTP responses.

    3. Relationship to BRC-103

    • Mandatory Prerequisite: Implementers MUST implement or rely on BRC-103’s handshake, message types, and signature logic.

    • This specification extends BRC-103 by mapping each BRC-103 message type onto HTTP requests and responses, describing /.well-known/auth usage, specialized headers (x-bsv-auth-*), and the structured “payload” approach for general messages.

    Whenever conflicts arise, BRC-103 is authoritative on handshake semantics and certificate exchange. BRC-104 only clarifies how to wrap those messages in HTTP.

    4. Terminology & Definitions

    • BRC-103 Message: One of initialRequest, initialResponse, certificateRequest, certificateResponse, or general.

    • Non-General Message: A BRC-103 message of type initialRequest, initialResponse, certificateRequest, or certificateResponse.

    • General Message: A BRC-103 message of type general, used to transmit an entire HTTP request or response under the authenticated session.

    • Peer: A user agent (client) or server implementing the protocol.

    • x-bsv-auth- Headers: A family of custom HTTP headers that store BRC-103 parameters (identity key, nonce, signature, etc.).

    • x-bsv-payment Header: An optional header used for embedding BSV payment data (e.g. 402 flows).

    • .well-known/auth Endpoint: The canonical path for sending non-general messages as JSON in a POST body.

    5. High-Level Overview

    1. Non-General BRC-103 messages (initialRequest, initialResponse, certificateRequest, certificateResponse) are sent as:

      • HTTP POST to /.well-known/auth, with a JSON-serialized AuthMessage in the request body.

      • The server processes it, possibly returning an AuthMessage in JSON.

    2. General BRC-103 messages are carried by a normal HTTP request to any path (e.g., /api/v1/orders), but encoded within custom headers plus a raw binary “payload.”

    3. The server intercepts that request, reconstructs the “general” BRC-103 message, verifies signatures, and eventually returns a corresponding “general” BRC-103 response.

    This layering effectively merges the BRC-103 handshake and certificate logic with standard HTTP request/response cycles.

    6. Detailed Specification

    6.1 HTTP Endpoints

    MUST define at least one endpoint:

    • POST /.well-known/auth

      • Accepts a JSON body representing a BRC-103 AuthMessage (any non-general type).

      • The server verifies the BRC-103 signature. On success, it MAY respond with another non-general BRC-103 message as JSON (e.g. initialResponse or certificateResponse).

      • If the handshake is incomplete or invalid, the server responds with an HTTP 4xx.

    Other resource endpoints (e.g. /myapp/orders) MAY handle general messages. The request body is an ordinary HTTP request body, while key BRC-103 fields (signature, identityKey, etc.) are placed in custom headers and an encoded “payload.”

    6.2 Header Conventions

    BRC-104 introduces the following headers:

    1. x-bsv-auth-version: The BRC-103 version string (e.g. "1.0").

    2. x-bsv-auth-identity-key: The sender’s public identity key (33-byte compressed secp256k1 pubkey, typically hex).

    3. x-bsv-auth-nonce & x-bsv-auth-your-nonce: 32-byte ephemeral nonces used in BRC-103’s handshake.

    4. x-bsv-auth-signature: ECDSA signature in hex, verifying the message.

    5. x-bsv-auth-request-id: A client-generated 32-byte random ID (base64) to correlate request/response pairs in “general” messages.

    6. x-bsv-auth-message-type: (Optional) The BRC-103 message type if returning a certificateRequest or certificateResponse via HTTP.

    7. x-bsv-auth-requested-certificates: (Optional) JSON-encoded RequestedCertificateSet for certificate requests.

    x-bsv-auth- headers MUST be excluded from the set of user-signed headers. They are ephemeral parameters or are used for BRC-103 signature itself.

    6.3 Signed Fields & Excluded Fields

    When building a “general” message, the BRC-103 specification requires a signature across certain fields. In BRC-104:

    • Included in signature:

      • Request method (GET, POST, etc.).

      • Request path and query string.

      • “Whitelisted” headers only:

        • authorization (client and server)

        • content-type (client-only)

        • Any header with prefix x-bsv- except x-bsv-auth-...

      • Request body bytes.

    • Excluded:

      • Non-whitelisted headers (like x-bsv-auth-*, accept)

      • Cookies, user-agent, etc.

    Servers do not sign content-type because certain server middleware tends to modify the content-type header. For example, express appends charset=utf-8 to the content-type resulting in ambiguity over the pre-image being signed.

    Clients however do not generally modify the content-type header in requests which allows it to be included in the pre-image being signed.

    The order of included headers will be lexicographical to ensure matching preimages on both sides.

    6.4 Request/Response Flow for “General” Messages

    Client perspective:

    1. Construct an HTTP request as usual, but store the entire method, path, query, selected headers, and body inside a “payload” field in the BRC-103 general message.

    2. The BRC-103 identity key, version, nonce, etc., go into x-bsv-auth-* headers.

    3. Send the request over standard HTTP.

    4. The server verifies authenticity, processes the request, and returns a BRC-103 “general” message in the response:

      • The server includes x-bsv-auth-version, x-bsv-auth-signature, x-bsv-auth-identity-key, etc.

      • The actual response status code, headers, and body are re-encoded as a “payload.”

    Server perspective:

    1. On receiving the request, parse the x-bsv-auth-* headers (nonce, signature, identityKey, etc.).

    2. Construct the “general” BRC-103 message from the payload.

    3. If signature checks pass, handle the HTTP request in memory (similar to a normal route).

    4. Instead of sending the result directly to the wire, embed your final status code, headers, and body in a new “general” BRC-103 message.

    5. Write it back in x-bsv-auth-* headers + the binary payload within the same HTTP response.

    6.5 Request/Response Flow for “Non-General” Messages

    Non-general BRC-103 messages—like initialRequest, initialResponse, certificateRequest, certificateResponse—MUST be exchanged via:

    1. POST /.well-known/auth, with a JSON body:

    2. The server decodes the AuthMessage, verifies it, and possibly replies with another AuthMessage in JSON form:

    3. On success, the client merges that result into the BRC-103 session state.

    6.6 Authentication Failure Handling

    • If the handshake or signature fails, the server MUST return 401 Unauthorized (or another 4xx suitable code) with a JSON body describing the error.

    • If the user sets invalid data, the server MAY respond with 400 Bad Request.

    6.7 General Message Encoding Rules

    When sending a “general” message:

    6.7.1 Path Encoding Rules

    • If the path has a value, it must be serialized as UTF-8 bytes with a length prefix.

    • If the path is empty, it must default to /, serialized as UTF-8 bytes with a length prefix.

    6.7.2 Query Parameter Encoding Rules

    • If query parameters are present, the entire query string (including the leading ?) must be serialized as UTF-8 bytes with a length prefix.

    • If no query parameters are present, specify a length of -1 in the payload.

    6.7.3 Body Encoding Rules

    The body is included raw in the BRC-103 payload, but only after a length prefix.

    a. If the content-type is application/json:

    • The JSON object must be stringified and converted to UTF-8 bytes.

    • If the body is empty, an empty JSON object {} should be stringified and converted to UTF-8 bytes.

    b. If the body consists of binary data (e.g. images):

    • The binary is included directly as bytes.

    • If the body is empty, specify a length of -1 in the payload.

    The same rules apply to the server’s response body in a “general” response message.

    6.8 Signature Preimage Calculation for HTTP Request Messages

    BRC-103 specifies that the preimage is constructed by concatenating these fields in a fixed order:

    1. x-bsv-auth-request-id (32 bytes, base64-decoded).

    2. Request method: length + UTF-8 bytes.

    3. Path: length + UTF-8 bytes (use / if the path is empty).

    4. Query string (including ?): length + UTF-8 bytes (or -1 if none).

    5. Included headers: count them in the order they are transmitted. For each header:

      • VarInt of key length, followed by key bytes

      • VarInt of value length, followed by value bytes

    6. Body: length + body bytes (or -1 if none).

    Finally, sign the preimage using the identity key. The server reconstructs the same preimage from the request data and verifies the signature contained in x-bsv-auth-signature.

    6.9 Signature Preimage Calculation for HTTP Response Messages

    In response to client request the server creates a BRC-103 payload as follows:

    1. x-bsv-auth-request-id (echoing back the client's requestId as seen on line 174).

    2. Response status (varInt)

    3. Included headers count, given in order of transmittal over the wire. For each header:

      • VarInt of key length, key bytes

      • VarInt of value length, value bytes

    4. Body length + body bytes (or -1 if none).

    7. Implementation Notes & Examples

    7.1 Client-Side Example

    A reference “client” does the following:

    • When sending a non-general message (e.g. handshake, certificate request), it:

      1. Performs POST /.well-known/auth with Content-Type: application/json.

      2. Embeds the entire AuthMessage (BRC-103 structure) in JSON.

    • When sending a general message:

      1. Serializes method, path, query, whitelisted headers, and body into a BRC-103 payload.

      2. Supplies x-bsv-auth-version, x-bsv-auth-identity-key, x-bsv-auth-nonce, x-bsv-auth-your-nonce (if applicable), x-bsv-auth-signature, and x-bsv-auth-request-id in the request headers.

    7.2 Server-Side Example

    1. Intercept POST /.well-known/auth requests, parse them as JSON, treat them as BRC-103 “non-general.”

    2. For other paths, it checks for x-bsv-auth-request-id to see if it’s a “general” message.

    3. It re-routes the normal Express request logic so that instead of returning data directly, the server packs the data into a BRC-103 “general” message and responds accordingly.

    This approach ensures a typical server can remain mostly unmodified, while the middleware handles the signature verification and re-encoding of the final response.

    8. Security Considerations

    • Replay Attacks: The nonce fields in BRC-103 ensure freshness. Servers MUST reject repeated nonces.

    • Header Injection: Only a fixed set of headers is signed. If malicious headers are injected, they are outside the signature scope. Implementers should sanitize or ignore unknown headers.

    • Transport Encryption: BRC-104 does not replace TLS. Implementers SHOULD still use HTTPS to hide private or sensitive information from eavesdroppers.

    • Certificate Revocation: If identity certificates are used, the logic for checking revocationOutpoints remains as in BRC-103.

    References

    • BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol (provides handshake and message definitions).

    The Bitcoin Wallet HTTP Interface is a standard interface that enables applications to connect with Bitcoin wallets to facilitate certain functionality. The interface provides a unified way for applications to request the creation of a Bitcoin transaction, encryption, digital signature creation, and other features provided by the wallet. By standardizing the interface, applications can support multiple wallets and give the user greater control over their Bitcoin-related activities.

    Motivation

    The motivation for this standard interface is to provide a common way for applications to connect with Bitcoin wallets. Currently, many Bitcoin wallets provide their own APIs, which makes it difficult for applications to support multiple wallets. The Bitcoin Wallet HTTP Interface standardizes the way that applications can interact with wallets, enabling them to be more easily integrated into various applications. This interface is designed to be flexible enough to support a range of wallets and use cases, while also providing a secure and standardized method of communication.

    Specification

    We define a standard HTTP substrate by which wallets can provide a communication channel to applications for the necessary tasks such as creating transactions, creating certificates, signature verification, and more.

    All implementors of the HTTP substrate should conform to the following standard for the wallet HTTP API that allows applications to communicate in a predefined and standard way.

    Host

    We define the wallet HTTP server to support communication over localhost on port 3301. New API versions can be specified as needed using the standard of v1, v2, etc.

    Example Encrypt Request URL: http://localhost:3301/v1/encrypt

    Standard HTTP Requests

    We define standardized HTTP requests that applications can use to communicate with wallets for performing various tasks.

    Message Type
    Request Method
    Route Name
    URL Query String Params
    Request Body
    Response Body

    Transaction Creation

    POST

    createAction

    No Params

    JSON

    JSON

    Encryption

    JavaScript Code Example

    Implementation

    Implementers of applications and wallets will need to create and process HTTP requests in the manner described, according to the various fields and properties as required by BRC-56, and in a manner consistent with the reference implementation, which is the Babbage SDK's HTTP substrate functionality.

    Background Evaluation Extended Format (BEEF) Transactions

    Deggen ([email protected]) Damian Orzepowski ([email protected]) Wojciech Regulski ([email protected]) Arkadiusz Osowski ([email protected])

    Abstract

    We propose a binary format for sending Transactions between peers to allow Simple Payment Verification (SPV). The format is optimized for minimal bandwidth while maintaining data required to independently validate the transaction in full.

    Assumption: Every user has an independent source of Block Headers indexed by Merkle Root.

    The simplest form is two transactions, one confirmed in a block which has a corresponding Merkle path and includes an output which is being spent in the second. The second is a newly signed transaction which constitutes the actual payment.

    In cases where one or more inputs are not yet mined, each ancestral transaction is included. We step back through the Transaction DAG until every input has a corresponding parent transaction with a Merkle path.

    This format is aligned with Dr. Craig Wright's explanation of SPV from this . He makes reference to a new paradigm, this format is an attempt to bring forth that paradigm.

    Users can adopt this format to transmit the data required to independently verify that a transaction is valid and is spending a real utxo from an existing block. The control mechanism to ensure no previous spend of the utxo is the economics and law. The format is intended for micropayments, so the risk is low. It is also the case that there is a cost to faking the data, since the attacker would really have to have previously owned an actual utxo. Any malfeasant would be signing incriminating evidence and sending it directly to the plaintiff if they were to defraud someone using this format. Without Merkle paths the data would be easier to fake, and there is no skin in the game required since the data could be randomly generated. Considering all these factors, the validation process is detailed in a later section.

    Copyright

    This BRC is licensed under the Open BSV license.

    Motivation

    Simplified Payment Verification formats for transmitting transactions between peers has yet to see wide adoption. This proposal advocates for complete ecosystem adoption of the principles of SPV; acknowledges that the system is secured by economic incentives, and law; and lays out a binary format for transmitting the data between parties optimizing for minimal bandwidth.

    Three prior formats should be mentioned:

    Extended Format incorporates the utxo script for script evaluation and satoshis for checking amounts. This format would still work when sending to nodes as they have a utxo lookup which is indexed by a hash of the extended data, meaning that invalid EF data would be detected immediately.

    which was created for use within the , this uses an array of rawtxs, Merkle proofs, and Mapi responses to transport the data required for SPV.

    Everett-style Transaction Envelopes uses a recursive JSON format which is otherwise similar to the above format originally designed for use within . One of the ideas which this proposal highlights is that the target of merkle proofs could be height rather than blockhash or root, to save on bytes. Thinking along these lines, we propose that no target be provided at all, and the root simply be calculated at the receieving end as needed. Using the root to look up headers also avoids any implementation complexity associated with competing blocks. For example, when a competing block encapsulates the transactions it may not have the same height, if all transactions are being stored with paths at a height rather than blockhash or merkle root (which are unique to specific versions of a block) then updating a set of the transactions with merkle paths from the new block will be difficult to sort out. If they're indexed by blockhash then it would be trivial to set them all as "in need of updated paths" without the need for disambiguation.

    Mapi is to be deprecated in the near future, so any new recommended formats should not include Mapi Responses as part of the solution.

    The array of rawtxs within the Tx Ancestors spec makes some sense in that there are strange cases where the same rawtx has two outputs which are spent in different transactions, both within the ancestry of the tx we are validating. You don't want to have embedded a copy of the same proof twice, hence a hash map would make more sense than just including the merkle path bytes in the tx itself. Everett-style Transaction Envelope deals with this well even given its recursive object design. Txids are used as pointers to existing transactions when complex dependency graphs occur. This proposal uses the same thinking, but for a binary format lists are used rather than recursive objects.

    The ordering of data has streaming validation in mind - an idea raised in EF - such that a receiver can start processing the validation immediately on receipt of the first few bytes, and any later bytes rely on previous bytes for their validation to even begin.

    • Merkle Paths

    • Oldest Tx Anchored by Path

    • Newer Txs depending on Oldest parent

    • Newest Tx

    As soon as the Merkle Paths are receieved we can calculate the roots and lookup their blockheaders. If they're not valid then validation can stop there - rejected. Then we look at the oldest ancestor - if it's valid then its children can be validated, and so on until we reach the most recent tx.

    Specification

    BEEF combines thinking from several formats into one binary stream, prefixed with a very specific version number for disambiguation.

    • Raw Transaction Format:

    • BSV Universal Merkle Path (BUMP):

    The encoding version number 4022206465 is chosen such that when seen in hex encoded as 4 bytes little endian it reads: 0100BEEF. This is to allow multiple versions to be defined in future while keeping the data minimal and leaving an obvious sequence which developers can eyeball. Often Bitcoin developers will see a sequence 0100000000... for rawtx. When they instead see 0100BEEF... they will know this data is BEEF format when debugging and so on. If there are future improvements then the next version would be 0200BEEF for example, this marker will remain "BEEF" for tens of thousands of versions until we reach 4022271999 which is obviously much more than would ever be required.

    Field
    Description
    Size

    Ordering

    Order is important - we must ensure that we end with the tx being evaluated, and its inputs are above, and their inputs are above that. is a well known solution to the problem in Graph Theory. Running this on the transaction DAG subset is recommended for complex transaction chains where order is not clear. Example below to demonstrate with extraneous data removed for clarity.

    BEEF Example

    Hex

    Bytewise Breakdown

    Validation Process

    1. We parse the BUMPs storing each in an array so that we can address them by index later.

    2. We parse each transaction.

      1. RawTx bytes double sha256 to get the txid.

      2. Store in hashmap from txid => parsedTx

    Implementation

    The format will be built into BUX to begin real world testing. Thereafter common libraries such as and for easy incorporation into existing stacks.

    HTTP Service Monetization Framework

    • Ty Everett ([email protected])

    • Brayden Langley ([email protected])

    1. Abstract

    This document specifies an HTTP-based micropayment framework that extends (mutual authentication and certificate exchange) and (HTTP transport for BRC-103). It defines how a server can advertise payment requirements for a given HTTP request and how a client can respond with a BSV transaction fulfilling these requirements. By leveraging:

    • HTTP 402 Payment Required responses

    • Nonce-based derivation prefixes ()

    • BRC-103 Identity keys

    this specification enables an authenticated, verifiable mechanism to monetize any web service with micropayments. The server could even cryptographically bind each payment to the mutual-authenticated session, ensuring that the payment correlates uniquely to the requested action.

    2. Motivation

    Current HTTP-based APIs often rely on subscription models or external billing/invoicing solutions. This approach can be cumbersome for fine-grained (micropayment-level) usage-based billing. By contrast, BSV Blockchain capabilities allow on-chain micropayments. However, bridging these seamlessly into existing HTTP flows requires:

    • Standardized BSV wallet functionality ()

    • A standard approach to advertise payment requirements (HTTP 402)

    • A mechanism to tie a user’s payment to their session identity (via BRC-103 identity keys)

    • Nonce-based replay protection (ensuring the same payment is not reused maliciously)

    BRC-105 addresses these needs by specifying how a BRC-103–authenticated server can request and verify a BSV payment from the client within a standard HTTP request–response cycle. Clients can use specialized 402-handling agents (e.g. AuthFetch or custom code) to automatically respond to 402 Payment Required, building and broadcasting a transaction on the user’s behalf.

    3. Terminology & Definitions

    • Payer (or Client): The party sending the HTTP request, who must pay the server if required. They are already mutually authenticated to the server via BRC-103/104.

    • Payee (or Server): The HTTP endpoint receiving the request, which may respond with 402 Payment Required, specifying the needed payment details.

    • Derivation Prefix: A random nonce string used to derive or reference a unique public key / payment output. Defined in .

    4. Relationship to BRC-103 and BRC-104

    BRC-103 defines mutual authentication and certificate exchange but does not define how to handle micropayments. BRC-104 applies BRC-103 to HTTP, detailing how to wrap BRC-103 handshake data in HTTP messages.

    BRC-105 sits on top of BRC-104, specifying a payment layer for monetizing HTTP endpoints. It reuses:

    • identityKey: The user’s 33-byte compressed public key from the BRC-103 session.

    • Nonce generation: The server can generate derivation prefixes that are cryptographically bound to its identity key, used by the parties to derive an ephemeral key pair for the payment.

    • HTTP 402 status code**: A recognized but typically unused code, repurposed here for BSV micropayments.

    5. Payment Protocol Overview

    5.1 Payment Steps Summary

    1. Client Authenticates

      • The client (payer) establishes a BRC-103 session with the server (payee) using BRC-104. This ensures both parties have authenticated and exchanged any necessary certificates to establish identity.

    2. Server Determines Price

    5.2 Payment Headers

    • x-bsv-payment-version

      • The current supported version is 1.0.

      • If a client does not explicitly support the server's indicated version, the client MUST NOT submit a payment.

    6. Detailed Protocol Flow

    6.1 Request

    6.1.1 Normal Request With Potential Payment

    A mutually authenticated request arrives (client has previously performed BRC-103 handshake). The request may or may not contain x-bsv-payment data:

    • If no payment is needed (the server’s calculateRequestPrice returns 0), proceed normally.

    • If the request has a non-zero price and the client did not supply x-bsv-payment, or the payment is invalid, the server responds with 402 Payment Required.

    6.2 Server’s 402 Response

    When the server determines a payment is needed but not yet provided or invalid:

    1. HTTP Status: 402 Payment Required.

    2. Headers:

      • x-bsv-payment-version: 1.0

    After receiving this, the client is expected to construct and broadcast a payment transaction referencing this prefix.

    6.3 Client Payment Submission

    Subsequent request includes the header x-bsv-payment, JSON:

    • derivationPrefix: Must match what the server gave in the 402 response.

    • transaction: A fully signed transaction paying an output script derived from the prefix, acceptable on the BSV network.

    6.4 Server Payment Verification

    Upon receiving x-bsv-payment, the server:

    1. Ensures the prefix is the same as previously advertised (and not used before).

    2. Validates the transaction using wallet.internalizeAction() or similar. Steps might include:

      • Ensuring the output script pays to the correct derivation from derivationPrefix.

    If validated, the server MUST proceed to handle the request logic, and is obliged to provide the requested service, according to what the client has paid for.

    6.5 Response to Payment-Funded Request

    If payment is successful, the server responds with a normal (e.g., 200 OK) plus any business logic response body. The server may add:

    • x-bsv-payment-satoshis-paid: <value>

    • Possibly additional data about the transaction or usage.

    7. Example Implementation

    7.1 Server-Side Steps

    1. Auth Check (BRC-103/104)

      • If not authenticated, respond 401 Unauthorized.

    2. Calculate Price

    7.2 Client-Side Steps

    1. Send Request

      • If server returns 402, parse x-bsv-payment-version + x-bsv-payment-satoshis-required + x-bsv-payment-derivation-prefix.

    2. Construct Payment

    8. Security Considerations

    1. Replay Attacks

      • The server and its wallet must ensure each derivationPrefix can only be used once. Typically, this prefix is stored in a wallet database or in-memory structure. Once a valid transaction is processed, subsequent attempts to reuse the prefix or submit the same transaction for multiple requests must fail.

    2. Man-in-the-Middle


    9. Extensibility & Future Work

    • Advanced Pricing: BRC-105 does not define how to calculate price. Implementation can adopt static or dynamic logic.

    • Refund Handling: Out of scope for this version. The server might store overpayments or offer on-chain refunds via additional flows.

    • Multi-Output Payments: Some use cases might require paying multiple outputs. The basic 402 flow still applies but must be extended with more sophisticated transaction logic.

    10. References

    • : Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol

    • : HTTP Transport for BRC-103

    • : Derivation-based Payment Protocol

    11. Conclusion

    BRC-105 introduces a standard approach to HTTP-based micropayment flows, leveraging the authentication and transport models defined in BRC-103 and BRC-104. By responding with 402 Payment Required and specifying a nonce-based derivation, the server ensures each payment is uniquely bound to the mutual-authenticated session and request. This framework enables straightforward pay-per-use APIs and extends the BSV ecosystem with a robust, standardized mechanism for monetizing web services at scale.

    Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol

    Ty Everett ([email protected])

    1. Abstract

    This document specifies a peer-to-peer protocol for mutual authentication and signed data exchange. The protocol uses certificates, nonce-based challenges, and digital signatures to protect the integrity and authenticity of messages, enabling:

    • Selective field disclosure of certificates without revealing unnecessary information.

    • Highly extensible message types, suitable for a variety of use cases such as transaction coordination, identity verification, and arbitrary data sharing.

    • Interchangeable transport layers, which can be HTTP, NFC, WebSockets, or any mechanism supporting bidirectional message exchange.

    The specification provides a standard approach for issuance, storage, retrieval, and verification of identity certificates, as well as the end-to-end handshake and messaging protocols between peers.

    2. Motivation

    Secure interactions among different wallets and services are critical. These interactions typically require:

    • Proving identity in a privacy-preserving manner, possibly revealing only some data fields (e.g. “I am over 18” without revealing full date of birth).

    • Ensuring that both parties are authenticated to each other (mutual authentication), reducing the risk of man-in-the-middle or impersonation attacks.

    A standard protocol for mutual authentication and certificate exchange addresses these needs and fosters interoperability between applications, wallets, and vendors.

    3. Terminology & Definitions

    • Wallet: An interface or application managing the user’s keys, capable of signing, encrypting, and decrypting data in conformance with .

    • Certificate: A data structure that attests to certain user attributes, signed by a certifier.

    • Master Certificate: A special form of certificate that has been encrypted field-by-field, each with a unique symmetric key, stored in an internal keyring.

    4. Certificates and Selective Disclosure

    4.1 Certificate Format

    Certificates are stored and transmitted in a binary format to optimize size and parsing consistency. We specify each field in table form, together with how it is conventionally represented when not in binary. The binary format is always used for signing and verification, but the conventions are useful for human readability. A certificate has the following primary fields:

    Field Name
    Type
    Description

    Important: Each certificate field is encrypted with a field-specific key. The encrypted version is signed.

    4.2 Master Certificate

    A Master Certificate includes a master keyring. Each field in the certificate is encrypted with a unique symmetric key. Those keys, in turn, are encrypted for the certificate holder (subject). Hence, a master certificate is able to decrypt any of its own fields locally but can selectively re-encrypt only some fields for a verifier.

    4.3 Verifiable Certificate

    A Verifiable Certificate is derived from a master certificate. It still contains all fields in ciphertext form (so that signatures can be verified) but also includes a “verifier-specific keyring.” For fields the subject wishes to disclose, the subject decrypts the corresponding symmetric key from the master keyring and re-encrypts it for the verifier. Consequently, the verifier can decrypt only those chosen fields.

    4.4 Selective Field Encryption

    1. Master Keyring Generation

      • For each field f, create a random symmetric key K_f.

      • Encrypt the field’s plaintext using K_f, store as Fields[f] = E(K_f, fPlaintext).

    4.5 Creation and Verification Processes

    Certificate Creation

    1. User (subject) or certifier forms certificate fields (including Type, SerialNumber, etc.).

    2. Each field is encrypted.

    3. The certifier signs the certificate data.

    Certificate Verification

    1. A party verifying a certificate reassembles the binary structure.

    2. Checks the signature against the “signature preimage” (all primary certificate fields except the signature itself, and not including their verifier keyring).

    3. Considers the RevocationOutpoint to confirm the certificate is not on-chain revoked (if it is not 36 zero bytes).

    Selective Disclosure

    • The subject issues a Verifiable Certificate containing:

      • Original field ciphertext.

      • Re-encrypted field keys for fields to reveal.

      • The certifier’s signature.

    The verifier can decrypt each revealed field’s ciphertext with the provided key, verifying the signature across the entire certificate to ensure authenticity.

    5. Peer-to-Peer Messaging Overview

    5.1 Message Types

    Each message exchanged between peers contains:

    • Version: The protocol version string (e.g. “0.1”).

    • MessageType: One of: initialRequest, initialResponse, certificateRequest, certificateResponse, general.

    5.2 Transports

    The protocol does not mandate a specific transport. Any medium that can:

    1. Deliver messages in a reliable or semi-reliable manner, and

    2. Allow receiving peer messages,

    can be used. HTTP requests, WebSockets, Bluetooth, NFC, or local function calls are all valid.

    5.3 Session & Nonce Management

    A peer typically maintains a session record containing:

    • isAuthenticated: Whether the peer is recognized as fully authenticated.

    • sessionNonce: A locally generated random 256-bit value.

    • peerNonce: The peer’s random 256-bit value.

    • peerIdentityKey: The peer’s public identity key.

    A session is created or updated whenever a handshake starts or completes. Nonces and signatures ensure that replaying old messages fails.

    6. Mutual Authentication Protocol Flow

    6.1 Handshake Sequence

    The handshake typically has two messages in the simplest form: an initialRequest and an initialResponse.

    1. initialRequest

      • Sender (A) generates a random nonce (A_Nonce).

      • A sends initialRequest containing:

    6.2 Nonce Creation & Verification

    • Each party uses a cryptographically secure random generator for the nonce (e.g., 32 bytes).

    • The verifying side must ensure the nonce is matched or “echoed” in subsequent messages.

    • Optionally, one may use an HMAC-based approach to bind nonces to their key, avoiding the need to keep track of all nonces that they created.

    6.3 Message Signing & Verification

    Signature ensures authenticity. The signing steps:

    1. Collect relevant data from the message. For instance, a general message might sign the raw payload array plus ephemeral fields such as (requestNonce + peerNonce) to bind the message to the session.

    2. Use the BKDS-based BRC-100 signature creation and verification mechanisms.

    3. Place the resulting signature in the message’s signature field.

    Verification:

    1. Recompute the same message preimage.

    2. Verify the signature with the alleged identityKey.

    3. If valid, accept the message. Otherwise, reject or treat as an error.

    6.4 Certificate Requests & Responses

    After or during handshake, a peer may request:

    • certificateRequest: “Please provide certificate(s) of type(s) X, issued by Y (or Z).”

    • certificateResponse: Peer responds by attaching a list of verifiable certificates that match the requested type and certifier.

    Request:

    • Contains a RequestedCertificates structure:

      • certifiers: array of public keys representing permissible certifiers.

      • types: a dictionary of certificateTypeID -> array of fields requested.

    Response:

    • Contains an array of VerifiableCertificates, each possibly containing:

      • Encrypted fields.

      • Re-encrypted keys for the requester.

      • The certifier’s signature.

    6.5 General Message Exchange

    Once both sides have completed the handshake (i.e. set isAuthenticated=true in their session records), they can exchange arbitrary data:

    • messageType = "general"

    • payload can be any binary or text data encoded consistently.

    • The message includes a fresh nonce and references the peer’s nonce for ephemeral binding to the session.

    7. Error Handling & Security Considerations

    1. Replay Attacks:

      • Nonces must be unique and used once. The receiver ensures that the same nonce is not accepted more than once.

    2. Man-in-the-Middle:

      • The handshake uses mutual signature verification. If a middle party tries to modify data, the signature verification fails.


    8. Implementation Notes

    • Data Types:

      • Nonces are 32 bytes.

      • Public keys are 33 bytes in compressed DER format.

      • Certificate fields may vary in size, so a length-prefix technique (varint) is standard.

    9. Acknowledgments

    This protocol is heavily inspired by existing cryptographic handshake approaches (SSH, TLS) and identity-certificate systems (X.509), adapted for a BSV-based environment. Contributors within the ecosystem have refined these ideas to align with BKDS, peer-to-peer exchange, selective disclosure, and other needs.

    XDM Wallet Communications Substrate

    Ty Everett ([email protected])

    Abstract

    Cross-document messaging enables web-based applications to communicate with one another in a secure manner, without allowing the two applications to manipulate each other's DOM trees. It defines a mechanism by which messages can be sent and received, with browser-based attestation of the origin of each message. We define the framework and conventions for operating a wallet over XDM, enabling a parent page that runs a wallet to communicate with one or multiple child pages that run applications.

    Direct Payment Protocol (DPP)

    Abstract

    The Direct Payment Protocol (DPP) is a comprehensive standard for invoice-based peer-to-peer payments on the Bitcoin SV network, encompassing the evolution of BIP70 through BIP270 and its related invoicing standards, including BIP271, BIP272, BIP273, BIP274, BIP275, and BIP282. The DPP harmonizes extensions to these standards, allowing for various payment options and combinations, while maintaining a well-maintained and up-to-date source of information for developers and industry players. The protocol facilitates communication between a payment host (e.g., merchant, payment processor, recipient's wallet) and sender (e.g., customer, acquaintance, IoT device) to enhance customer experience, simplify wallet infrastructure, enable advanced wallet features, and improve wallet security against payment process attacks.

    020101cd73c0c6bb645581816fa960fd2f1636062fcbf23cb57981074ab8d708a76e3b02003470d882cf556a4b943639eba15dc795dffdbebdc98b9a98e3637fda96e3811e01c58e40f22b9e9fcd05a09689a9b19e6e62dbfd3335c5253d09a7a7cd755d9a3c04008c00bb9360e93fb822c84b2e579fa4ce75c8378ae87f67730a49552f73c56ee801da256f78ae0ad74bbf539662cdb9122aa02ba9a9d883f1d52468d96290515adb02b4c8d919190a090e77b73ffcd52b85babaaeeb62da000473102aca7f070facef03e5b331f4961d764373f3a4e2751954e75489fb17902aad583eedbb41dc165a3b
    02 // height = 2
    01 // nLeafs at this height VarInt
    // ----------------------
    01 // offset VarInt
    cd73c0c6bb645581816fa960fd2f1636062fcbf23cb57981074ab8d708a76e3b // 32 byte hash
    // ----------------------
    // implied end of leaves at this height
    // height of next leaves is therefore 1
    02 // nLeafs at this height VarInt
    // ----------------------
    00 // offset VarInt
    3470d882cf556a4b943639eba15dc795dffdbebdc98b9a98e3637fda96e3811e // 32 byte hash
    // ----------------------
    01 // offset VarInt
    c58e40f22b9e9fcd05a09689a9b19e6e62dbfd3335c5253d09a7a7cd755d9a3c // 32 byte hash
    // ----------------------
    // implied end of leaves at this height
    // height of next leaves is therefore 0
    04 // nLeafs at this height VarInt
    // ----------------------
    00 // offset VarInt
    8c00bb9360e93fb822c84b2e579fa4ce75c8378ae87f67730a49552f73c56ee8 // 32 byte hash (this is the txid at index 0)
    // ----------------------
    01 // offset VarInt
    da256f78ae0ad74bbf539662cdb9122aa02ba9a9d883f1d52468d96290515adb // 32 byte hash
    // ----------------------
    02 // offset VarInt
    b4c8d919190a090e77b73ffcd52b85babaaeeb62da000473102aca7f070facef // 32 byte hash
    // ----------------------
    03 // offset VarInt
    e5b331f4961d764373f3a4e2751954e75489fb17902aad583eedbb41dc165a3b // 32 byte hash (this is the txid at index 3)
    // ----------------------
    // implied end of data because new height would be -1
    const { Br } = require('openspv')
    const reader = new Br()
    reader.buf = Buffer.from('020101cd73c0c6bb645581816fa960fd2f1636062fcbf23cb57981074ab8d708a76e3b02003470d882cf556a4b943639eba15dc795dffdbebdc98b9a98e3637fda96e3811e01c58e40f22b9e9fcd05a09689a9b19e6e62dbfd3335c5253d09a7a7cd755d9a3c04008c00bb9360e93fb822c84b2e579fa4ce75c8378ae87f67730a49552f73c56ee801da256f78ae0ad74bbf539662cdb9122aa02ba9a9d883f1d52468d96290515adb02b4c8d919190a090e77b73ffcd52b85babaaeeb62da000473102aca7f070facef03e5b331f4961d764373f3a4e2751954e75489fb17902aad583eedbb41dc165a3b', 'hex')
    
    let maxHeight = parseInt(reader.read(1).toString('hex'), 16)
    let compoundPath = Array(maxHeight + 1).fill(0).map(() => ({}))
    let height = maxHeight
    let x = 0
    let nLeavesAtThisHeight = reader.readVarIntNum()
    let startOfNextHeight = nLeavesAtThisHeight
    while (height >= 0) {
      offset = reader.readVarIntNum()
      hash = reader.read(32).reverse().toString('hex')
      compoundPath[height][hash] = offset
      x++
      if (x == startOfNextHeight) {
        height--
        if (height < 0) break
        nLeavesAtThisHeight = reader.readVarIntNum()
        startOfNextHeight = nLeavesAtThisHeight + x
      }
    }
    
    console.log({ compoundPath })
    [ // index within the outer array corresponds to the height
    	{ // within each height there must be one or more hashes with their corresponding offsets { [hash]: offset }
    		"e86ec5732f55490a73677fe88a37c875cea49f572e4bc822b83fe96093bb008c": 0, // txid at index 0
    		"db5a519062d96824d5f183d8a9a92ba02a12b9cd629653bf4bd70aae786f25da": 1,
    		"efac0f077fca2a10730400da62ebaebaba852bd5fc3fb7770e090a1919d9c8b4": 2,
    		"3b5a16dc41bbed3e58ad2a9017fb8954e7541975e2a4f37343761d96f431b3e5": 3 // txid at index 3
    	},
        {
    		"1e81e396da7f63e3989a8bc9bdbefddf95c75da1eb3936944b6a55cf82d87034": 0,
    		"3c9a5d75cda7a7093d25c53533fddb626e9eb1a98996a005cd9f9e2bf2408ec5": 1
    	},
    	{
    		"3b6ea708d7b84a078179b53cf2cb2f0636162ffd60a96f81815564bbc6c073cd": 1
    	}
    ]
    
    // let's say we want to derive the path for txid 3b5a16dc41bbed3e58ad2a9017fb8954e7541975e2a4f37343761d96f431b3e5 
    // first we determine from the 0th array in the compound merkle path that the block index associated is 3.
    
    const example = {
      index: 3,
      path: []
    } 
    
    compoundPath.map((leaves, height) => {
      const indexOffset = example.index >> height ^ 1
      for (const hash in leaves) {
        if (leaves[hash] === indexOffset) {
          example.path.push(hash)
          return true
        }
      }
      return Error(`We do not have a hash for this index at height: ${height}`)
    })
    {
      index: 3,
      path: [
        '3b6ea708d7b84a078179b53cf2cb2f0636162ffd60a96f81815564bbc6c073cd',
        '1e81e396da7f63e3989a8bc9bdbefddf95c75da1eb3936944b6a55cf82d87034',
        'efac0f077fca2a10730400da62ebaebaba852bd5fc3fb7770e090a1919d9c8b4'
      ]
    }
    // pseudocode
    function merkleProof(txid, index, path) {
      try {
        const root = deriveRootFromPath(txid, index, path)
        const blockHeader = await lookupHeaderByRoot(root)
        if (blockHeader.state === 'LONGEST_CHAIN') return true
        else return false
      } catch (error) {
        console.log({ error })
        return false
      }
    }
    {
      "message": {
        "recipient": "028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1",
        "messageBox": "payment_inbox",
        "body": "hello"
      }
    }
    {
      "status": "success"
    }
    {
      "messageBox": "payment_inbox"
    }
    {
      "status": "success",
      "messages": [
        {
          "messageId": 3301,
          "body": "hello",
          "sender": "028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1"
        }
      ]
    }
    {
      "messageIds": [
        3301
      ]
    }
    {
      "status": "success"
    }
    {
      "version": "1.0",
      "messageType": "initialRequest",
      "identityKey": "...",
      "initialNonce": "...",
      "signature": "...",
      ...
    }
    {
      "version": "1.0",
      "messageType": "initialResponse",
      "identityKey": "...",
      "nonce": "...",
      "yourNonce": "...",
      "signature": "...",
      ...
    }
    Host URL: http://localhost
    Standard Port: 3301
    Versioning Standard: v1, v2, etc
    const httpResult = await makeHttpRequest(
          'http://localhost:3301/v1/<routeName>',
          {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json'
            },
            body: JSON.stringify({
              <requestBody>
            })
          }
        )
  • On receiving the server’s HTTP response, decodes those same fields from the response headers, building a BRC-103 message that includes the returned status code, headers, and body as a “payload.”

  • Verifiable Certificate: A certificate derived from a master certificate, revealing keys for only the fields a particular verifier may see.
  • Peer: A party participating in communication, using the protocol to exchange messages.

  • Session: The state tracking an authenticated channel between two peers.

  • Nonce: A random value used once within a cryptographic exchange to ensure freshness and avoid replay attacks.

  • Signature: A digital signature produced by the user’s or certifier’s private key.

  • Transport: The underlying communication medium that relays messages between peers.

  • RevocationOutpoint

    32-byte TXID + varint output idx

    On-chain reference to track revocation (if spent, revoked).

    Fields

    Varint count + repeated pairs

    Pairs of: <fieldNameLength, fieldName, fieldValueLength, fieldValue>

    Signature

    Varint length + bytes

    Certifier’s signature over all fields (excluding itself).

    After all fields are encrypted, the certifier signs the assembled certificate, comprising all encrypted fields.

  • The certifier can then encrypt the key K_f for the subject’s own identity: EncryptedKey_f -> E_subject(K_f), the subject can store in the master keyring.

  • Disclosure to a Verifier

    • When selectively disclosing field f, the subject decrypts EncryptedKey_f, obtains K_f, and re-encrypts K_f with the verifier’s identity key, producing K_f_for_verifier.

    • The subject includes K_f_for_verifier in the verifier’s keyring for that verifiable certificate.

  • IdentityKey: Sender’s public key.
  • Nonce Fields: For challenge–response patterns (e.g. yourNonce, initialNonce).

  • Signature: A digital signature by the sender’s private key over the relevant content.

  • Optional Data:

    • Certificates: A list of verifiable certificates.

    • RequestedCertificates: A set specifying certifiers and certificate types with fields.

    • Payload: Arbitrary data included in general messages.

  • messageType = "initialRequest"
  • identityKey = A_publicKey

  • initialNonce = A_Nonce

  • Optionally, a requestedCertificates set if A wants B’s certificates.

  • initialResponse

    • Receiver (B) verifies the request, creates its own random nonce (B_Nonce).

    • B sends initialResponse containing:

      • messageType = "initialResponse"

      • identityKey = B_publicKey

      • initialNonce = B_Nonce (its own newly created nonce)

      • yourNonce = A_Nonce (echoing A’s nonce)

      • Optionally, any certificates B wants to share right away.

      • A signature verifying B truly created this message.

    • When A receives this initialResponse, it verifies B’s authenticity via the signature over (A_Nonce + B_Nonce), marking the session as authenticated.

  • The signature covers the payload plus nonces.

  • Certificate Revocation:

    • The revocationOutpoint can be polled or monitored in the ledger to confirm it has not been spent. A spent outpoint implies the certificate is revoked Non-zero outpoints must be checked.

  • Selective Disclosure:

    • Properly encrypt fields with randomly derived keys.

    • Re-encrypt those keys only for intended verifiers.

  • Privilege Escalation:

    • Carefully manage session state to ensure a partially authenticated session does not gain privileges.

  • Transport Security:

    • Although each message is authenticated, transport-level encryption (e.g. TLS) can still be beneficial, especially to hide message lengths or frequencies.

    • This protocol does not encrypt any data by itself.

  • Storage:

    • A wallet may store certificates in a local database.

    • A session manager maps sessionNonce and peerIdentityKey to a single in-memory record.

    Type

    32-byte (base64) string

    Certificate category identifier (e.g., unique type associated with “social handles”).

    SerialNumber

    32-byte (base64) string

    Uniquely identifies this certificate instance.

    Subject

    33-byte compressed pubkey (hex)

    The wallet’s (subject’s) public key.

    Certifier

    33-byte compressed pubkey (hex)

    The certifier's public identity key.

    BRC-100

    POST

    encrypt

    BRC-56 defined

    Binary or String

    Binary

    BRC-2 Decryption

    POST

    decrypt

    BRC-56 defined

    Binary or String

    Binary

    BRC-3 Signature Creation

    POST

    createSignature

    No Params

    JSON

    Binary

    BRC-3 Signature Verification

    POST

    verifySignature

    BRC-56 defined

    Binary or String

    JSON

    BRC-53 Certificate Creation

    POST

    createCertificate

    No Params

    JSON

    JSON

    BRC-53 Certificate Verification

    POST

    proveCertificate

    No Params

    JSON

    JSON

    BRC-56 HMAC Creation

    POST

    createHmac

    BRC-56 defined

    Binary or String

    Binary

    BRC-56 HMAC Verification

    POST

    verifyHmac

    BRC-56 defined

    Binary or String

    Boolean

    BRC-56 Public Key Derivation

    GET

    getPublicKey

    BRC-56 defined

    None

    JSON

    BRC-56 Certificate List

    POST

    findCertificates

    No Params

    JSON

    JSON

    BRC-56 Version Request

    GET

    getVersion

    No Params

    None

    String

    BRC-56 Network Request

    POST

    getNetwork

    No Params

    None

    String

    BRC-56 Authentication Request

    GET

    isAuthenticated

    No Params

    None

    JSON

    BRC-56 Async Auth Request

    POST

    waitForAuthentication

    No Params

    JSON

    JSON

    BRC-1
    BRC-2

    message.body

    string

    The content of the message

    messages[].body

    string

    The content of the message

    messages[].sender

    string

    The sender's public key

    VarInt number of transactions which follow

    1-9 bytes

    Raw Transaction

    RawTx bytes as in standard format

    many bytes

    Has BUMP

    01 if so, followed by the BUMP index; 00 if not, followed by nothing.

    1 byte

    BUMP index

    VarInt index number - indicating the BUMP to which the prior tx belongs if there is one.

    1-9 bytes

  • If there is a Merkle path after the tx then we lookup the BUMP using the BUMP index number.

    1. Lookup the txid within level 0 leaves of the BUMP to get the index of the txid within a block.

    2. Calculate the Merkle root with the index, txid, and BUMP data.

    3. Add the merkle root to an array which will be used in a request to our local header service once all transactions have been parsed.

    4. Mark the tx as valid or not as soon as the header service responds.

  • Otherwise we run local validation on the transaction, stopping at the soonest failure.

    1. Check the txid exists in memory, and is marked as valid.

    2. Check that all scripts evaluate to TRUE.

    3. Check that the sum of satoshis in > satoshis out + fee

    4. Mark the tx as valid.

  • We make a request to the local header service as soon as we have all merkle roots calculated.

    1. This involves sending a list of Merkle roots to the Pulse service which will validate that the merkle roots provided are all part of headers within the longest chain.

    2. If any of the roots are not part of the longest chain, the response is negative and the whole validation has failed.

  • We await the final transaction being marked as valid since it depends on all other processes.

  • Version no

    Version number starts at 4022206465, encoded Uint32LE => 0100BEEF

    4 bytes

    nBUMPs

    VarInt number of BSV Unified Merkle Paths which follow

    1-9 bytes

    BUMP data

    All of the BUMPs required to prove inclusion of inputs in longest chain of blocks BRC-74

    many bytes x nBUMPs

    article
    BRC-30
    Tx Ancestors
    Lite Client Toolbox
    BRC-8
    DPP
    BRC-30
    BRC-12
    BRC-74
    Khan's algorithm
    bsv
    go-bt

    nTransactions

    Derivation Suffix: An additional, output/script-level field included by the client with the payment transaction that is used by the payee's wallet for verification. Also defined in BRC-29.

  • x-bsv-payment header: A custom header carrying JSON data, including the transaction references and derivation prefixes/suffixes.

  • internalizeAction(): A function defined by the payee’s wallet or server that finalizes the transaction acceptance logic (e.g., verifying the correct output script, ensuring the derivation prefix is valid, confirming the transaction is not a duplicate, etc.).

  • The server calculates how many satoshis this request requires (if any). This can be a static fee, dynamic, or zero.
  • 402 Payment Required (if fee > 0 and no valid payment provided)

    • If the client has not included a valid x-bsv-payment header, the server responds with HTTP status 402 and sets:

      • x-bsv-payment-satoshis-required: Number of satoshis required.

      • x-bsv-payment-derivation-prefix: A random nonce () for the transaction.

  • Client Submits Payment

    • The client’s wallet or user agent sees the 402 response.

    • It constructs a BSV transaction paying the requested amount to the server’s derivation.

    • The client re-sends the request with a header x-bsv-payment containing JSON:

  • Server Verifies Payment

    • The server checks the prefix (derivationPrefix) and suffix (derivationSuffix), ensures it matches what was advertised, and that the transaction properly pays the required amount.

    • If successful, the server considers the request to be funded.

  • Server Continues

    • Assuming the payment is valid, the server proceeds with the requested operation and returns a normal success response (e.g., 200).

  • x-bsv-payment-satoshis-required
    • Integer number of satoshis needed for this request.

    • Sent from server → client in 402 Payment Required.

  • x-bsv-payment-derivation-prefix

    • Payment-level nonce for deriving the payment output script.

    • Sent from server → client in 402 Payment Required.

  • x-bsv-payment

    • JSON structure containing the actual transaction data.

    • Sent from client → server in a subsequent request or retry after 402.

  • x-bsv-payment-satoshis-required: <price in satoshis>

  • x-bsv-payment-derivation-prefix: <nonce> (often base64 or hex)

  • Body: Optional JSON describing the error or instructions for convenience:

  • Checking if the amount is at least the required satoshisRequired.

  • Preventing double-spend or replay.

  • E.g., price = 200 satoshis.
  • If x-bsv-payment Provided

    • Parse and verify. If valid, continue. If invalid, return 400 Bad Request.

  • If Not Paid

    • Return 402 + x-bsv-payment-version + x-bsv-payment-derivation-prefix + x-bsv-payment-satoshis-required.

  • If Paid

    • Proceed to business logic.

  • Create transaction paying the server’s derivation.

  • Store it in x-bsv-payment JSON.

  • Re-Send

    • Re-send the request with x-bsv-payment header.

    • If accepted, receives normal 200 OK.

    • If server fraudulently absconds with client funds:

      • Clients should request more robust identity certificates using in the future.

      • Do not use the service again.

      • Make reports to the issuers of the server's certificates to have them revoked.

      • Do not trust certifiers who are willing to issue certificates to fraudulent entities.

  • Because all requests are already mutually authenticated via BRC-103, a MITM cannot hijack the payment flow. Tampering with the transaction or the prefix invalidates the request and leads to cryptographic failure.

  • Underpayment

    • The server should reject transactions that pay less than required. Or, if partial payments are allowed, the server must define how to handle partial coverage. Servers should set clear refund policies, and policies for services not used or partially paid. Generally, partial payment is prohibited.

  • Double Spends

    • The server’s wallet.internalizeAction() logic must handle double-spend scenarios, ensuring the transaction is fully-signed, final and valid on the network.

  • Data Confidentiality

    • BRC-105 does not itself encrypt data. Transport-level encryption (e.g., TLS) is recommended to protect transaction details and requests from eavesdroppers.

  • BRC-103
    BRC-104
    BRC-29
    BRC-100
    BRC-29
    BRC-103
    BRC-104
    BRC-29
    402 Payment Required
    Motivation

    BRC-56 defines a suite of abstract messages used by applications and wallets to facilitate various Bitcoin and MetaNet operations that enable micropayments, protect user privacy and ensure secure authentication without the need for each application to maintain a separate user account. While BRC-5 defines a method of using a BRC-56 wallet over HTTP on the local machine, some mobile devices are unable to support running HTTP servers due to platform-specific limitations. Additionally, it is sometimes desirable for a MetaNet environment to run fully in the browser, enabling users to access their identities on devices or platforms where a desktop-based BRC-5 client cannot be installed. This specification provides a ubiquitous communications substrate enabling the use of BRC-56 functionality across a wide range of devices and deployment contexts, including fully in-browser experiences.

    Specification

    We specify that the parent page runs the wallet, responding to messages from child pages. This has several advantages:

    • The wallet can always pop-up any necessary permission popups or user-interactive authorization screens without interference from client pages

    • When the user visits the parent page, they log in once, then they can access any applications after login

    • Multiple applications, all running in the same parent page, can access and utilize the BRC-56 wallet at once

    • Reducing the number of wallets running in parallel reduces the chances of UTXO synchronization or corruption issues

    • It is possible to run the parent wallet page locally, connecting to remote services only when required by specific applications

    • If a specific application was the parent and the wallet was a child, failure of the parent page to respond could constitute failure of a user to access their identity or assets, which might otherwise be available through another application

    Application Message Sending and Processing

    We start with the message relay interface defined by XDM. JavaScript code for sending messages from the application to the wallet is as follows:

    We stipulate that:

    1. All messages (requests, responses and errors) have a type property equal to CWI (this value, which stands for Computing with Integrity, is historical)

    2. A random message ID is generated by the application

    3. The application listens for new, incoming response messages. As part of the listener, the application:

      • Drops any events without the correct type in the event data

      • Drops any events where isTrusted is not true

      • Drops any events where the event data contains the isInvocation flag, denoting any outgoing messages that were echoed back

      • Drops any events where the event data contains an id field other than the one generated by step 2

      • Handles any error messages if the event's data contains a status field equal to error, relying on the code and description fields to construct an appropriate error

      • Otherwise, if no errors are detected, the application is now free to make use of the result field from the event's data payload, which will be the response from the wallet as specified by the relevant BRC standard for the specific message being sent

    4. With the listener in place and ready to process the response when it arrives, the application now constructs and sends the message to the wallet through the parent window:

      • Like all messages, the outgoing message contains a type field equal to CWI

      • An isInvocation flag is set to true

    This application-side interface facilitates exchanging and receiving messages with the BRC-56 wallet over XDM. We now proceed to how the wallet handles its side of the interaction.

    Wallet Message Receipt, Processing and Response

    The wallet listens for incoming messages and replies to the originator with appropriate responses after obtaining permission from the user (if applicable) and processing the request. Some JavaScript code that implements this functionality is provided:

    We stipulate, before any client applications are loaded which might send any messages to the wallet, that the wallet running on the parent page must bind a message event handler that:

    1. Upon receipt of a message with an event data field type not equal to CWI will drop the message

    2. Upon receipt of an untrusted message, or one without a call will drop the message

    3. Upon receipt of a message with an unknown or unsupported call will proceed to step 6

    4. Based on the call and params will perform the necessary steps as required by the relevant BRC specifications for the specific operation

    5. Compose a response message and send it back to the originator, the response message comprising an event payload with the following fields:

      • A type value of CWI

      • The id that was specified by the application when the message was created

    6. In case of any errors with the operation, the wallet will instead send back a response message comprising an event payload with the following fields:

      • A type value of CWI

      • A status value of error

    Values for call Associated with Various Message Types

    For each of the message pairs (request and response) incorporated into BRC-56, we specify the existence of a corresponding XDM message pair with a specific call value:

    Message Pair

    call Value

    Specific Implementation Notes

    Transaction Creation

    createAction

    Encryption

    encrypt

    Decryption

    decrypt

    Signature Creation

    Implementations

    Implementers of applications and wallets will need to create and process XDM messages in the manner described, according to the various fields and properties as required by BRC-56, and in a manner consistent with the reference implementation, which is the Babbage SDK's XDM substrate functionality.

    Implementation questions should be directed to the author.

    One (crude) example of a deployed architecture in which a parent page uses XDM to communicate with child application pages, facilitating the operation of multiple client applications which communicate with the parent wallet, has been implemented by the Babbage team at BabbageOS.com.

    BRC-56
    Motivation

    The current state of BIP270, BIP271, BIP272, BIP273, BIP274, BIP275, and BIP282 lacks a unified standard owned by a dedicated committee, leading to multiple versions on GitHub that do not accurately represent field implementations. This situation makes it challenging for new players to implement invoice-based payments correctly from the outset. Furthermore, industry representatives have expressed the need for extensions to the existing standards, such as accommodating meta-assets or accepting discount coupons, which lower the amount of BSV required to satisfy the invoiced amount.

    The DPP addresses these challenges by re-evaluating and baselining the existing standards to align with common field implementations, while maintaining backward compatibility. The protocol seeks input from industry players on extension needs and aims to find the smallest denominator for such needs, allowing for future custom extensions without compromising backward compatibility.

    Concepts

    The Direct Payment Protocol (DPP) is a standard for facilitating direct payments between a customer and a merchant by specifying the necessary messages, objects, and components required for secure and efficient transactions. This section outlines the high-level concepts involved in the DPP standard.

    Messages

    The DPP protocol consists of three main messages: PaymentTerms, Payment, and PaymentACK. These messages are communicated between the customer and the payment host's server, serving to initiate, execute, and acknowledge payment transactions.

    JSON Objects

    The DPP protocol relies on JSON objects to represent and exchange data throughout the payment process. These objects are used to define payment details, payment host and customer information, and payment acknowledgment information.

    PaymentTerms

    PaymentTerms is the first message in the DPP protocol, sent by the payment host's server in response to a customer's payment initiation. It contains details about the required payment, such as the available payment modes, beneficiary information, and policies.

    Modes

    PaymentModes define the various ways a customer can make a payment. The PaymentTerms message lists the supported modes, and the customer must choose one of these modes to proceed with the payment. Each mode has its own specific requirements and format for the Payment and PaymentACK messages.

    Beneficiary

    The Beneficiary object contains information about the merchant, such as their name, email, address, and payment reference. This data can be used by the payment host to identify and associate PaymentTerms with the merchant.

    Policies

    Policies define any additional requirements set by the merchant for processing the Payment. These can include required originator fields or other constraints that the customer must adhere to when submitting the Payment message.

    Payment

    The Payment message is sent by the customer after they have authorized the payment. It specifies the chosen payment mode and provides the necessary data required for that mode, such as transaction details, originator information, and any mode-specific objects.

    Originator

    The Originator object contains information about the payer, which can be used for identification, refunds, and other purposes. This data can include the payer's name, paymail, return address, return script, and other optional data.

    PaymentACK

    The PaymentACK message is the final message in the DPP protocol, sent from the payment host's server to the customer's wallet in response to a Payment message. It acknowledges receipt of the payment and provides any mode-specific data or additional information, such as a secure peer channel for direct communication or a redirect URL.

    Protocol

    Now that we have covered the basic concepts, we specify the data structures necessary to achieve compliance with the DPP protocol.

    1. Three Primary Messages

    The DPP consists of three primary messages: PaymentTerms, Payment, and PaymentACK. Each message is a JSON object with specific fields and requirements.

    1.1 PaymentTerms

    The PaymentTerms message provides the customer with the necessary information to make a payment to the payment host. It includes details about the required payment, expiration data, and additional metadata:

    PaymentTerms Field
    Description

    network (string, required)

    Identifies the blockchain network. In production, this should always be "bitcoin-sv".

    version (string, required)

    Specifies the DPP version.

    outputs (array of outputs, optional, deprecated)

    Deprecated, for backward compatibility only.

    creationTimestamp (number, required)

    Unix timestamp (seconds since 1-Jan-1970 UTC) when the PaymentTerms was created.

    expirationTimestamp (number, optional)

    Unix timestamp (UTC) after which the PaymentTerms should be considered invalid.

    1.2 Payment

    The Payment message is sent after the customer has authorized the payment. It specifies the chosen payment mode and provides the required data for that mode.

    Payment Field
    Description

    modeId (string, required)

    The ID of the chosen mode from the PaymentTerms message.

    mode (object, required)

    The Payment object for the specific mode used.

    originator (object, optional)

    Payer data needed for identification and refund purposes.

    transaction (hex-formatted string, optional, deprecated)

    A fully-signed and valid Bitcoin transaction. Deprecated.

    memo (string, optional)

    A plain-text note from the customer to the payment host.

    1.3 PaymentACK

    The PaymentACK message is the final message in the DPP, sent from the payment host's server to the Bitcoin wallet in response to a Payment message.

    PaymentACK Field
    Description

    modeId (string, required)

    The ID of the chosen mode from the PaymentTerms message.

    mode (object, required)

    The Payment object for the specific mode used.

    peerChannel (object, optional)

    Provides data needed to communicate via the created channel in a secure manner.

    redirectUrl (string, optional)

    An optional URL to redirect the customer after the payment is completed.

    2. Components

    Several components are used within the messages described above. This section provides a detailed description of each component.

    2.1 Modes

    PaymentModes define the various ways a customer can make a payment. The PaymentTerms message lists the supported modes, and the customer must choose one of these modes to proceed with the payment. Each mode has its own specific requirements and format for the Payment and PaymentACK messages. The main part of the PaymentTerms object is the Modes component. For now, we propose one flexible payment mode called HybridPaymentMode, which can be used to pay with BSV, tokens, or a combination of funding sources. In the future, if HybridPaymentMode cannot fulfill some requirements, other PaymentModes can be specified.

    Mode Field
    Description

    modeId (string, required)

    Unique identifier for the payment mode.

    description (string, required)

    A short description of the payment mode.

    requirements (object, required)

    An object containing the required fields and data for the chosen payment mode.

    2.2 Beneficiary

    The Beneficiary object contains information about the merchant, such as their name, email, address, and payment reference. This data can be used by the payment host to identify and associate PaymentTerms with the merchant.

    Beneficiary Field
    Description

    name (string, required)

    Name of the merchant.

    email (string, required)

    Official merchant email.

    address (string, required)

    Merchant's address.

    paymentReference (string, required)

    ID of the payment/invoice.

    avatar (string, optional)

    URL to an avatar.

    2.3 Policies

    Policies define any additional requirements set by the merchant for processing the Payment. These can include required originator fields or other constraints that the customer must adhere to when submitting the Payment message.

    Policies Field
    Description

    requiredOriginatorFields (array of strings, optional)

    List of the fields which are required by the merchant to process the payment (regardless of whether DPP defines them as optional ones).

    2.4 Originator

    The Originator object contains information about the payer, which can be used for identification, refunds, and other purposes. This data can include the payer's name, paymail, return address, return script, and other optional data.

    Originator Field
    Description

    name (string, required)

    Name of the payer.

    paymail (string, optional)

    Payer's paymail (where, e.g., refunds will be sent, identity can be used somehow, etc.).

    return_address (string, optional)

    Payer's return bitcoin address on which the merchant can refund the payment back if there is such a case (if paymail cannot be used, another way paymail is a better option).

    return_script (string, optional)

    Similar to the above but a script instead of a raw address (it is more flexible, e.g., the payer might want to have a refund in a stable coin).

    avatar (string, optional)

    URL to an avatar.

    2.5 PeerChannel

    The PeerChannel object describes and defines the format of the peerChannel field in the PaymentACK message. It is used to provide data that specifies a created channel for secure direct communication between the payer and the merchant.

    PeerChannel Field
    Description

    host (string, required)

    The hostname and port of the server handling the secure direct communication channel.

    token (string, required)

    A unique token used for authentication and authorization within the secure communication channel.

    channel_id (string, required)

    A unique identifier for the specific communication channel established between the payer and the merchant.

    Extensibility

    We use JSON as JSON is naturally extensible. Any property of the objects not specified in this standard is a candidate to convey information for extensions. Other standards can be created to denote specific payment modes. One such standard is BRC-54, which defines the Hybrid Payment Mode. This protocol defines an abstract messaging layer with JSON objects, but other standards such as BRC-55 can stipulate concrete transport mechanisms and such as HTTPS.

    Implementations

    The Direct Payment Protocol (over HTTPS) is implemented in this example from Jad Wahab.

    PeerServ Host Interconnect Protocol

    Ty Everett ([email protected])

    Abstract

    This document outlines the PeerServ Host Interconnect Protocol (PHIP), a peer discovery mechanism specifically designed for the PeerServ message relay system. Analogous to the scalability and resiliency enabled by CHIP (Confederacy Host Interconnect Protocol) for overlay networks, PHIP allows PeerServ instances to discover and connect with other active instances where a particular user receives messages, thus enabling robust and efficient message delivery across these instances. It also defines a mechanism for instances to prove the authenticity of the original message sender to one another using key linkage information.

    Identity-Linked Token Protocol

    Jake Jones ([email protected])

    Abstract

    This proposal extends the Enhanced Mandala Token Protocol (BRC-107) with identity certificate integration based on BRC-52/53. It enables tokens to enforce real-world compliance requirements, KYC/AML regulations, and identity-based access controls while preserving privacy through selective field revelation. The protocol supports regulated security tokens, accredited investor requirements, geographic restrictions, and identity-based recovery mechanisms, all validated through SPV-friendly cryptographic proofs.

    // khan's algorithm
    function khanTopologicalSort(graph) {
        const inDegree = {}
        const queue = []
        const result = []
        for (let node in graph) {
            inDegree[node] = 0
        }
        for (let node in graph) {
            for (let neighbor in graph[node]) {
                inDegree[neighbor]++
            }
        }
        for (let node in inDegree) {
            if (inDegree[node] === 0) {
                queue.push(node)
            }
        }
        while (queue.length) {
            let node = queue.shift()
            result.push(node)
            for (let neighbor in graph[node]) {
                inDegree[neighbor]--
                if (inDegree[neighbor] === 0) {
                    queue.push(neighbor)
                }
            }
        }
        return result.reverse()
    }
    
    const txs = [
        {
            txid: '2222222222222222222222222222222222222222222222222222222222222222',
            inputs: ['1111111111111111111111111111111111111111111111111111111111111111'],
        },
        {
            txid: '1111111111111111111111111111111111111111111111111111111111111111',
            inputs: ['0000000000000000000000000000000000000000000000000000000000000000'],
        },
        {
            txid: '0000000000000000000000000000000000000000000000000000000000000000',
            inputs: [],
        },
        {
            txid: '4444444444444444444444444444444444444444444444444444444444444444',
            inputs: [
                '3333333333333333333333333333333333333333333333333333333333333333',
                '2222222222222222222222222222222222222222222222222222222222222222',
            ],
        },
        {
            txid: '3333333333333333333333333333333333333333333333333333333333333333',
            inputs: [
                '2222222222222222222222222222222222222222222222222222222222222222',
                '1111111111111111111111111111111111111111111111111111111111111111',
            ],
        },
    ]
    
    const graph = {}
    for (let tx of txs) {
        graph[tx.txid] = {}
        for (let input of tx.inputs) {
            graph[tx.txid][input] = true
        }
    }
    console.log({ graph })
    console.log({ correctOrder: khanTopologicalSort(graph) })
    0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000
    0100beef // version
    01 // VarInt nBUMPs
    fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331 // see BRC-74 for details of BUMP format
    02 // VarInt nTransactions = 2
    // rawtx parent follows
    0100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac00000000
    01 // above tx has merkle path
    00 // VarInt the index of the path for this tx in the above list
    // rawtx current payment follows
    0100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac00000000
    00 // above tx doesn't have merkle path, but instead has local parent
    {
      "derivationPrefix": "AAAAA...",
      "derivationSuffix": "...",
      "transaction": "SGVsbG8s" // a BSV transaction in AtomicBEEF format encoded as base64
    }
    {
      "status": "error",
      "code": "ERR_PAYMENT_REQUIRED",
      "satoshisRequired": 200,
      "description": "A BSV payment is required..."
    }
    {
      "derivationPrefix": "<prefix from server>",
      "derivationSuffix": "<optional suffix>",
      "transaction": "SGVsbG8s"
    }
    new Promise((resolve, reject) => {
      const id = 'abcdabcd' // get a random message ID
      window.addEventListener('message', async e => {
        if (e.data.type !== 'CWI' || !e.isTrusted || e.data.id !== id || e.data.isInvocation) return
        if (e.data.status === 'error') {
          const err = new Error(e.data.description)
          err.code = e.data.code
          reject(err)
        } else {
          resolve(e.data.result)
        }
      })
      window.parent.postMessage({
        type: 'CWI',
        isInvocation: true,
        id,
        call: 'getVersion',
        params: {}
      }, '*')
    })
    window.addEventListener('message', async e => {
      if (e.data.type !== 'CWI' || !e.isTrusted || typeof e.data.call !== 'string') return
    
      // This is where the wallet will do its processing, based on `call` and `params`.
    
      // ... in a rudamentary implementation ...
    
      if (e.data.call === 'createAction') { // BRC-1
        try {
          let result = await doBRC1Thing({
            ...e.data.params,
            originator: e.origin // You might let BRC1Thing know which app is sending the request, for permission purposes
          })
          e.source.postMessage({
            type: 'CWI', result, id: e.data.id
          }, e.origin)
        } catch (error) {
          e.source.postMessage({
            type: 'CWI',
            id: e.data.id,
            status: 'error',
            code: error.code || 'ERR_UNKNOWN',
            description: error.message
          }, e.origin)
        }
      } else if (e.data.call === 'encrypt') { // BRC-2 encrypt
        try {
          let result = await doBRC2Thing({
            ...e.data.params,
            originator: e.origin // You might let BRC2Thing know which app is sending the request, for permission purposes
          })
          e.source.postMessage({
            type: 'CWI', result, id: e.data.id
          }, e.origin)
        } catch (error) {
          e.source.postMessage({
            type: 'CWI',
            id: e.data.id,
            status: 'error',
            code: error.code || 'ERR_UNKNOWN',
            description: error.message
          }, e.origin)
        }
      } // ... implement all functions ...
    
    })

    memo (string, optional)

    A note to be displayed to the customer, explaining the purpose of the PaymentTerms. Maximum length is 50 characters.

    paymentUrl (string, required)

    Secure HTTPS location where a Payment message will be sent to obtain a PaymentACK.

    beneficiary (object, optional)

    Contains data about the merchant.

    modes (key-value map, required)

    A dictionary of possible payment modes specified by ID, each mode describing detailed instructions about payment requirements.

    policies (object, optional)

    Specifies special merchant requirements according to the Payment object.

    extendedData (object, optional)

    Additional optional data as a freestyle object.

    extendedData (object, optional)

    Additional optional data as a freestyle object.

    Contact your local police department.

  • File an IC3 complaint.

  • BRC-29
    BRC-103
    BRC-12
    , allowing listeners to easily drop outgoing messages rather than trying to process them as responses
  • The id that was generated in step 2 is included. The same id must be used by wallets when sending back the response

  • The call determines which message is being sent. Specific call values are defined below

  • The params field comprises the specific parameters as specified in BRCs that define specific message types

  • A result value that is the result of the operation being performed, as specified by the particular operation

  • The id that was specified by the application when the message was created

  • A relevant code for the error, as specified by the particular operation in question

  • A human-readable description for the error

  • createSignature

    BRC-3 Signature Verification

    verifySignature

    BRC-53 Certificate Creation

    createCertificate

    BRC-53 Certificate Verification

    proveCertificate

    BRC-56 HMAC Creation

    createHmac

    BRC-56 HMAC Verification

    verifyHmac

    BRC-56 Public Key Derivation

    getPublicKey

    BRC-56 Certificate List

    ninja.findCertificates

    This call name prefix is historical and retained for compatibility

    BRC-56 Version Request

    getVersion

    BRC-56 Network Request

    getNetwork

    BRC-56 Authentication Request

    isAuthenticated

    BRC-56 Async Auth Request

    waitForAuthentication

    BRC-1
    BRC-2
    BRC-2
    BRC-3
    Watch Explainer
    Motivation

    Current token systems on BSV lack native integration with identity verification, making regulatory compliance difficult and limiting adoption for security tokens and regulated assets. While BRC-52/53 provides a robust identity certificate system, there's no standard for linking these certificates to token ownership and transfers.

    This proposal addresses:

    • Regulatory compliance for security tokens requiring KYC/AML

    • Accredited investor verification for restricted offerings

    • Geographic restrictions for regulatory jurisdictions

    • Identity-based recovery for lost keys

    • Privacy-preserving compliance through selective revelation

    • Fraud prevention through identity linkage

    Specification

    Identity-Bound Token Types

    We define three levels of identity requirements for tokens:

    1. Open Tokens: No identity requirements (backward compatible with BRC-92/BRC-107)

    2. Verified Tokens: Require valid BRC-52 certificate

    3. Restricted Tokens: Require specific certificate fields or types

    Enhanced Genesis Output

    The genesis transaction establishes identity requirements:

    Where:

    • issuerCertificateHash: SHA-256 hash of issuer's BRC-52 certificate

    • complianceRules: Encoded rules for token transfers

    • identityCommitment: H(assetId || issuerCertificate || complianceRules || maxSupply)

    Compliance Rules Structure

    Identity-Linked Token Output

    Where:

    • recipientCertificateHash: SHA-256 hash of recipient's BRC-52 certificate

    • identityCommitment: H(assetId || amount || certificateHash || prevTxid)

    Identity-Aware Transfer Protocol

    When transferring identity-linked tokens, the sender provides:

    Verification Protocol

    Recipients and overlays MUST verify:

    1. Standard Token Checks (from BRC-106)

    • Commitment verification

    • Conservation check

    • Merkle proof validation

    2. Identity Checks

    Selective Field Revelation

    Certificate holders reveal only required fields:

    1. Determine Required Fields: Based on token's compliance rules

    2. Encrypt for Recipient: Using BRC-52/53 key derivation

    3. Include in Transfer: Add encrypted keys to certificate keyring

    4. Recipient Decrypts: Using their identity key

    Example revealing only country for geographic restriction:

    Identity-Based Recovery

    Tokens can include recovery conditions:

    Where:

    • recoveryCommitment: H(certificateType || recoveryFields || recoveryPubkey)

    • recoveryDelay: Time lock before recovery (e.g., 30 days)

    Certificate Levels and Permissions

    Use Cases

    1. Security Token Offering (STO)

    2. Geographic Restrictions

    3. Age-Restricted Assets

    4. Institutional Trading

    Privacy Considerations

    Zero-Knowledge Proofs

    For sensitive compliance checks, support ZK proofs:

    • Prove age > 18 without revealing exact age

    • Prove accredited status without revealing net worth

    • Prove country membership without revealing specific country

    Encrypted Field Storage

    All certificate fields remain encrypted until revelation:

    • Only revealed fields are decrypted

    • Revelation is counterparty-specific

    • No permanent plaintext exposure

    Pseudonymous Compliance

    Users can maintain pseudonymity while proving compliance:

    • Certificate links to pubkey, not real name

    • Only certifier knows real identity

    • Selective revelation preserves privacy

    Security Considerations

    Certificate Validation

    • Always verify certificate signatures

    • Check revocation status via UTXO

    • Validate certifier is trusted

    • Ensure certificate hasn't expired

    Replay Protection

    • Include prevTxid in commitments

    • Timestamp compliance attestations

    • Use nonces for uniqueness

    Key Compromise

    • Certificate revocation via UTXO spending

    • Recovery mechanisms for token access

    • Time-locked recovery periods

    Migration and Compatibility

    Backward Compatibility

    • Open tokens work without identity

    • Existing BRC-92/106 tokens unaffected

    • Optional identity for gradual adoption

    Migration Path

    1. Phase 1: Deploy identity-aware wallets

    2. Phase 2: Certifiers issue BRC-52 certificates

    3. Phase 3: Token issuers adopt compliance rules

    4. Phase 4: Overlays enforce identity requirements

    5. Phase 5: Full ecosystem adoption

    Implementation Examples

    Creating Identity-Linked Token

    Transferring with Compliance

    Test Vectors

    Identity Commitment

    Compliance Check

    References

    • BRC-52: Identity Certificates

    • BRC-53: Certificate Creation and Revelation

    • BRC-92: Mandala Token Protocol

    • BRC-107: Enhanced Mandala Token Protocol

    • BRC-43: Security Levels, Protocol IDs, Key IDs and Counterparties

    • BRC-2: Data Encryption and Decryption

    • BRC-3: Digital Signature Creation and Verification

    Implementations

    Reference implementations:

    • TypeScript: Coming Soon

    • Go: Coming Soon

    • Python: Coming Soon

    21 <assetId>
    <issuerCertificateHash>
    <complianceRules>
    <identityCommitment>
    OP_2DROP OP_2DROP OP_2DROP OP_DROP ...
    {
      "version": 1,
      "requireIdentity": true,
      "allowedCertificateTypes": [
        "8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE="
      ],
      "requiredFields": ["country", "accreditedStatus"],
      "restrictions": {
        "allowedCountries": ["US", "CA", "GB"],
        "minCertificateLevel": "enhanced_kyc",
        "maxAmountPerIdentity": 10000,
        "cooldownPeriod": 86400
      }
    }
    21 <assetId> <amount>
    <recipientCertificateHash>
    <identityCommitment>
    OP_2DROP OP_2DROP OP_2DROP OP_DROP P2PKH
    {
      "transaction": "hex_encoded_transaction",
      "tokenProofs": {
        "inputs": [...],
        "outputs": [...],
        "conservationProof": {...}
      },
      "identityProofs": {
        "sender": {
          "certificate": {
            "type": "8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=",
            "subject": "0376d67c86b45be3c36c328c2aa5c5dd79c546d2...",
            "serialNumber": "kUahacBHmYL2nkzemkatFg==",
            "certifier": "035ce8cc44dbcf4c991d666d381d67263aed9123...",
            "revocationOutpoint": "48645047cd66f7b48b24efb080ec7e27...1",
            "signature": "3045022100c0686907...",
            "keyring": {
              "country": "encrypted_for_recipient",
              "accreditedStatus": "encrypted_for_recipient"
            }
          },
          "certificateProof": {
            "merkleProof": "...",
            "blockHeight": 850000
          }
        },
        "recipient": {
          "certificateHash": "sha256_hash_of_recipient_certificate",
          "certificateType": "8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE="
        }
      },
      "complianceAttestation": {
        "rulesVersion": 1,
        "checksPassed": [
          "country_allowed",
          "accredited_investor",
          "amount_within_limit"
        ],
        "timestamp": 1234567890,
        "attestorSignature": "..."
      }
    }
    function verifyIdentityCompliance(transfer) {
      // Verify sender's certificate
      if (!verifyCertificate(transfer.identityProofs.sender.certificate)) {
        return false;
      }
    
      // Check certificate not revoked
      if (isSpent(transfer.identityProofs.sender.certificate.revocationOutpoint)) {
        return false;
      }
    
      // Verify certificate matches output
      senderCertHash = H(transfer.identityProofs.sender.certificate);
      if (senderCertHash != transfer.transaction.inputs[0].certificateHash) {
        return false;
      }
    
      // Decrypt and verify required fields
      fields = decryptFields(transfer.identityProofs.sender.certificate.keyring);
      if (!meetsComplianceRules(fields, token.complianceRules)) {
        return false;
      }
    
      // Verify recipient certificate type
      if (!token.complianceRules.allowedCertificateTypes.includes(
        transfer.identityProofs.recipient.certificateType)) {
        return false;
      }
    
      return true;
    }
    {
      "certificate": {
        "fields": {
          "firstName": "encrypted_not_revealed",
          "lastName": "encrypted_not_revealed",
          "country": "encrypted_value",
          "city": "encrypted_not_revealed"
        },
        "keyring": {
          "country": "encrypted_revelation_key_for_recipient"
        }
      }
    }
    21 <assetId> <amount>
    <primaryCertificateHash>
    <recoveryCommitment>
    OP_IF
      <recoveryDelay> OP_CHECKSEQUENCEVERIFY OP_DROP
      <recoveryCertificateHash> OP_EQUAL
    OP_ELSE
      <primaryCertificateHash> OP_EQUAL
    OP_ENDIF
    {
      "certificateLevels": {
        "basic_kyc": {
          "maxTransferAmount": 1000,
          "dailyLimit": 5000,
          "allowedOperations": ["transfer", "receive"]
        },
        "enhanced_kyc": {
          "maxTransferAmount": 10000,
          "dailyLimit": 50000,
          "allowedOperations": ["transfer", "receive", "stake"]
        },
        "institutional": {
          "maxTransferAmount": null,
          "dailyLimit": null,
          "allowedOperations": ["transfer", "receive", "stake", "mint", "burn"]
        }
      }
    }
    // Genesis specifies accredited investor requirement
    complianceRules = {
      requiredFields: ["accreditedStatus", "country"],
      allowedCountries: ["US"],
      restrictions: {
        mustBeAccredited: true,
        minInvestment: 10000
      }
    }
    // Token only transferable within specific regions
    complianceRules = {
      requiredFields: ["country"],
      allowedCountries: ["EU", "UK", "CH"],
      restrictions: {
        blockRestrictedCountries: ["US", "CN", "RU"]
      }
    }
    // Gaming tokens requiring age verification
    complianceRules = {
      requiredFields: ["ageRange"],
      restrictions: {
        minimumAge: 18,
        requireAgeAttestation: true
      }
    }
    // Different limits based on certificate type
    if (certificate.type == "retail") {
      maxDailyVolume = 10000;
    } else if (certificate.type == "qualified") {
      maxDailyVolume = 100000;
    } else if (certificate.type == "institutional") {
      maxDailyVolume = unlimited;
    }
    async function createIdentityToken(params) {
      // Get issuer's certificate
      const issuerCert = await wallet.getCertificate();
    
      // Define compliance rules
      const rules = {
        requireIdentity: true,
        allowedCertificateTypes: [params.certificateTypeId],
        requiredFields: params.requiredFields,
        restrictions: params.restrictions
      };
    
      // Create genesis with identity binding
      const genesis = {
        assetId: generateAssetId(),
        issuerCertificateHash: hash(issuerCert),
        complianceRules: rules,
        identityCommitment: hash(
          assetId + issuerCert + rules + params.maxSupply
        )
      };
    
      return createGenesisTransaction(genesis);
    }
    async function transferWithCompliance(amount, recipient) {
      // Get certificates
      const senderCert = await wallet.getCertificate();
      const recipientCert = await requestCertificate(recipient);
    
      // Check compliance
      const compliance = await checkCompliance(
        senderCert,
        recipientCert,
        token.complianceRules
      );
    
      if (!compliance.passed) {
        throw new Error(`Compliance failed: ${compliance.reason}`);
      }
    
      // Reveal required fields
      const keyring = await revealFields(
        senderCert,
        token.complianceRules.requiredFields,
        recipient
      );
    
      // Create transfer
      return {
        transaction: createTokenTransfer(amount, recipient),
        identityProofs: {
          sender: {
            certificate: senderCert,
            keyring: keyring
          },
          recipient: {
            certificateHash: hash(recipientCert)
          }
        },
        complianceAttestation: compliance.attestation
      };
    }
    Input:
      assetId: "abc...def:0"
      certificateHash: "123...789"
      amount: 100
      prevTxid: "def...456"
    
    Output:
      commitment = SHA256(assetId || amount || certificateHash || prevTxid)
                 = "xyz...123"
    Certificate Fields:
      country: "US"
      accreditedStatus: "true"
    
    Compliance Rules:
      allowedCountries: ["US", "CA"]
      mustBeAccredited: true
    
    Result: PASS ✓
    Motivation

    BRC-33 establishes a reliable message relay architecture, providing a solution for situations where users need to exchange messages but are unable to do so directly over the network. While a centralized server is simpler to deploy, a federated approach that enables instances to cooperate and assist each other in delivering messages removes the need for everyone on the network to rely on a single server. By proposing an interconnect protocol for PeerServ hosts, this document aims to address this requirement and enhance the scalability and reliability of the PeerServ message relay system.

    Specification

    PHIP Token Protocol

    The PHIP token is a BRC-48 output on the Bitcoin SV network which hosts an advertisement created by the PeerServ server operator. The protocol comprises the following ordered fields:

    Field
    Description

    Field 1

    The term 'PHIP', representing a PHIP advertisement.

    Field 2

    The identity key of the instance operator who submitted the advertisement.

    Field 3

    The domain name of the HTTPS server hosting the PeerServ instance.

    Field 4

    The identity key of the user who the instance operator believes will receive messages via the PeerServ instance.

    Field 5

    A signature from the recipient authorizing this host to make this advertisement. The recipient signature is specified below.

    Recipient Signature

    The purpose of the recipient signature is to prevent malicious PeerServ hosts from creating advertisements that route messages destined for certain recipients to their servers without authorization. The recipient's PeerServ host will need to obtain this signature from the recipient prior to creating any advertisements to receive messages on their behalf.

    The message template for the recipient signature is as follows:

    Where:

    • <host key> is the BRC-31 identity key of the PeerServ host the recipient is authorizing

    • <host domain> is the domain the recipient knows the host to reside at, and

    • <box regex> is either the regular expression, or if no regular expression is provided, the string ALL

    For example: 028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1 peerserv.babbage.systems ALL

    The signature is to be computed by the recipient according to the BRC-3 process. The BRC-43 security level is 1, the protocol ID is PHIP authorization and the key ID is 1. The counterparty is anyone, meaning that anyone can verify the recipient's signature.

    Token Creation Process

    We specify the creation of a new BRC-22 overlay network (with accompanying BRC-24 lookup service) that will host and track PHIP tokens from various PeerServ instance operators across the network. When it wishes to advertise that messages can be routed to a particular user through their server, the PeerServ instance operator creates a new PHIP token and submits it to the overlay. Upon receiving a new submission, the overlay operators must confirm that the BRC-48 locking key of the PeerServ instance operator is connected to their claimed BRC-31 identity key by ensuring that the BRC-42 child key used for signing can be linked back to the claimed identity key.

    The token creation process followed by a PeerServ instance operator comprises several steps:

    1. Obtaining the recipient's signature to authorize the message routing advertisement.

    2. Deriving the BRC-48 Locking Key: The PeerServ instance operator should use BRC-42 key derivation, with the operator's BRC-31 identity key as the sender private key, while the 'anyone' public key (1 times G) should be the counterparty. The invoice number for BRC-43 is calculated at security level 2, with protocol ID PHIP and key ID 1. Then, the signing private key can be derived from the identity key using this invoice number.

    3. Computing the Signature: The derived private key from the earlier step is used to calculate the signature covering the fields of the PHIP token.

    4. Broadcast the Transaction: A transaction output is embedded with the PHIP token, and this transaction is then submitted to the PHIP overlay network.

    Validation and Verification of Tokens

    Before admitting a PHIP token into the overlay, PHIP overlay operators should verify that the claimed identity key from the PeerServ instance operator corresponds to the BRC-48 signing key. Any invalid tokens must not be admitted into the overlay. The validation and verification process is specified in the steps below:

    • Verify the PHIP identifier. The first field of the PHIP token should be equal to PHIP. If the PHIP identifier fails to verify, the token has to be rejected as invalid.

    • Validate the BRC-48 locking key. The overlay operator should apply the BRC-42 key derivation method, with the advertiser's BRC-31 identity key as the sender public key and the 'anyone' private key (1) as the recipient. The BRC-43 methodology should then be used to calculate the invoice number at security level 2, protocol ID PHIP and key ID 1. The public key derived through the advertiser's identity key using this invoice number must match the locking key; if not, the token is rejected as invalid.

    • Validate the signature. The signature produced in the process, using the public key derived, should be verified over the fields of the PHIP token. Only valid signatures which satisfy the necessary conditions should be considered authentic.

    • Verify the recipient signature. Use the recipient's claimed identity public key to derive the appropriate signing key for the PHIP authorization protocol, with security level 1 and key ID 1 for the anyone counterparty. Check the signature against the specified message based on the provided fields.

    • Blacklist checks. If the overlay network operator maintains a blacklist of known-malicious PeerServ instance operators, they can choose not to admit the token.

    • Allow the token into the PHIP overlay. The token is deemed valid if all conditions are successfully met, and can be admitted into the PHIP overlay network.

    PHIP Lookup Service

    As alluded to earlier, we specify the creation of a new BRC-24 PHIP lookup service which allows network users to find and query various PHIP advertisement UTXOs, thereby facilitating the navigation and interaction with other operators' PeerServ instances. As specified later, PeerServ instance operators looking to forward new messages to the correct place so that the recipient can access them can make use of this lookup service to find which PeerServ instance is in use by the PeerServ message recipient.

    Provider Name

    We specify PHIP as the BRC-24 Lookup Service Provider Name.

    Query Processing

    The lookup service accepts a JSON object as its query. The object is specified to contain a recipient key, which the lookup service will use to find records for PeerServ hosts who claim to deliver to the specified recipient.

    Query Example

    The network user performs a lookup service query for the 'user' key, which is the BRC-31 identity key of the message recipient they want to reach. The lookup service will search and return all corresponding UTXOs linked to that key. The network user can then utilize the HTTPS URL(s) for the host record(s) returned, in order to effectuate message delivery.

    Routing Authorization Endpoint

    Before a PeerServ instance operator advertises that it is able to receive incoming messages on behalf of final recipients, it will need a way to collect authorizations from said recipients. These authorizations are sent to a new BRC-31-protected endpoint (in addition to those specified by BRC-33) which collects and verifies recipient authorization signatures. We specify this HTTPS, JSON, POST endpoint as follows: POST /authorizeRouting

    Parameters

    Name
    Description

    message

    The message that has been signed by the recipient (required for the avoidance of doubt, makes validation and error handling easier)

    signature

    The recipient authorization signature, as specified

    Processing Steps

    The PeerServ instance that receives this request will validate the signature, storing and using it if it later decides to advertise this recipient's availability for the receipt of incoming messages across the network.

    Return Value

    If the server received and validated the authorization from the recipient, a success response is returned.

    Errors

    If there was an error, appropriate HTTP status codes should be used. An example of a reasonable error response is provided.

    Message Delivery Endpoint

    When a PeerServ instance operator advertises that it is able to receive incoming messages from other hosts, it must be prepared to accept requests to a new BRC-31-protected endpoint (in addition to those specified by BRC-33) to propagate incoming messages. We specify this HTTPS, JSON, POST endpoint as follows: POST /propagateMessage

    Parameters

    Name
    Description

    originalSender

    The identity key of the original message sender

    keyLinkage

    The (Method 2) key linkage information that links the original sender with the Authrite message signature

    signedMessage

    The message comprising the original Authrite request made by the original sender, which will contain all relevant information, including the message recipient, message box, and message body

    senderSignature

    The signature that the original sender provided for the message when it was delivered to the sender's local, original PeerServ host

    Processing Steps

    The PeerServ instance that receives this request will perform the following steps:

    1. Compute the child public key for the original message sender by adding (by point addition) the keyLinkage value to the originalSender public key.

    2. Check the senderSignature against the computed public key for validity.

    3. Examine the signedMessage to determine the appropriate message box and recipient.

    4. If the server is willing to add this message to the specified message box for the specified recipient, the message is added.

    Return Value

    If the message was successfully stored in the recipient's appropriate PeerServ message box, a success response is returned.

    Errors

    If there was an error, appropriate HTTP status codes should be used. An example of a reasonable error response is provided.

    Message Delivery to Recipient PeerServ Instance

    When a BRC-33 message sender submits a new message destined for a recipient to his local PeerServ instance, the PeerServ instance will perform the following steps to effectuate message delivery across the network:

    1. Save the BRC-31 Authrite message signature, message payload, message signing child public key, BRC-43 protocol ID and key ID used for BRC-31 signature verification on the incoming message that was provided by the sender. This will later be used for BRC-69 key linkage revelation.

    2. Use the PHIP lookup service to look up UTXOs associated with the PeerServ instances in use by the recipient.

    3. If Regular Expression fields were provided for any of the tokens, test the message box where the message is to be delivered against these values, discarding any tokens that fail the Regular Expression check, but keeping any tokens that did not provide one.

    4. Apply the steps defined by the Validation and Verification of Tokens section of this document, verifying for themself that the tokens provided by the lookup service are legitimate, and dropping any that fail this verification.

    5. Make use of the Message Delivery Endpoint to deliver the message to each of the PeerServ instance operators with valid PHIP tokens, providing the stipulated parameters.

    Monetization

    It is possible to make use of BRC-41 within the Message Delivery Endpoint to monetize the routing and delivery of PeerServ messages, which would allow operators to collect fees for relaying and synchronizing messages. Subject to routing agreements between hosts, people who make use of this endpoint should be prepared to handle a 402 Payment Required error, as specified by BRC-41. Network operators may also choose to route messages for free, but this is not sustainable at large scale.

    Implementations

    There are no known implementations of this standard at present. This specification will be updated as and when an appropriate implementation is developed.

    BRC-23
    BRC-69

    Genealogical Identity Protocol

    Todd Price ([email protected])

    Abstract

    The Genealogical Identity Protocol (GIP) represents an innovative leap in identity verification within the Bitcoin ecosystem. Merging genealogical data in GEDCOM files with advanced cryptographic techniques, the GIP creates an immutable and secure identity system. This aligns seamlessly with Dan Roble's Innovation Bank proposal and integrates with global identity protocols, thereby enhancing interoperability.

    The GIP uses GEDCOM files' rich historical and familial data as a unique identity marker, fortified by an adaptive versioning system for continuous updates and refinement. This system verifies the longest unbroken chain of ancestors, adding robust security layers to identity verification.

    Furthermore, the GIP handles hash-based dependencies via a novel signing scheme, encapsulating the diversity of modern family structures. It mitigates complex familial relationships while maintaining high-security standards. By offering a dynamic and secure solution to digital identities, the GIP enhances the Bitcoin ecosystem and forecasts future breakthroughs in blockchain-based identity management.

    <host key> <host domain> <box regex>
    {
      "user": "028d37b941208cd6b8a4c28288eda5f2f16c2b3ab0fcb6d13c18b47fe37b971fc1"
    }
    {
      "status": "success"
    }
    {
      "status": "error",
      "code": "ERR_SIGNATURE_INVALID",
      "description": "The recipient authorization signature could not be verified."
    }
    {
      "status": "success"
    }
    {
      "status": "error",
      "code": "ERR_SENDER_LINKAGE_VERIFICATION_FAILED",
      "description": "Unable to link the signature to the original message sender."
    }

    Motivation

    The motivation for developing the Genealogical Identity Protocol (GIP) stems from a need to overcome inherent identity verification challenges within the Bitcoin ecosystem and the broader digital world. The GIP is designed to cater to a global audience, seamlessly integrating with international standards for self-sovereign identity, thus ensuring its relevance and application on a global scale.

    One of the primary incentives for the GIP's development is the requirement for a decentralized and secure identity verification method, fitting with the ethos of Bitcoin. GIP leverages the rich genealogical data embedded in GEDCOM files, thus creating a unique identity marker. This approach eliminates dependence on centralized authorities or government-issued identity documents, thereby reducing security risks and enhancing verifiability.

    GIP's innovative approach to digital identity also allows for the creation of secondary data markets, enabling individuals to leverage their identities for personal gain. The GIP's detailed and secure identity system, combined with its sophisticated data privacy controls, creates the potential for individuals to monetize their anonymized data. This approach empowers users to control their data and benefit from its value, fundamentally shifting the dynamics of the digital economy.

    Furthermore, the GIP’s flexible nature makes it capable of handling the complexities and dynamics of modern familial relationships. Its ability to manage hash-based dependencies results in a more accurate and comprehensive representation of real-world identities. This intricacy of identity representation extends to include coats of arms, heraldry, and intersection with various reputation, expertise, and public office portfolios, thus offering a more holistic and adaptable identity management system.

    The GIP's end-to-end authentication capabilities form another key motivation for its implementation. By facilitating the derivation of shared secrets for key exchanges, deterministic hash chains, ECDH, and CGA++, GIP offers a more secure and efficient framework within the Bitcoin ecosystem.

    Finally, the GIP is motivated by the aspiration to contribute to a globally interoperable digital identity management system. Its design allows seamless integration with both self-sovereign and international identity protocols, fostering a more unified, secure, and user-centric digital identity ecosystem.

    In conclusion, the GIP is driven by the urgent need for improved identity verification methods in decentralized systems like Bitcoin, the aim to empower individuals to benefit from their digital identities, and the vision to contribute to a globally interoperable, secure, and user-centric digital identity framework.


    Specification

    GEDCOM Files

    The Genealogical Identity Protocol (GIP) takes a revolutionary step forward in identity management within the Bitcoin ecosystem by harnessing the untapped potential of Genealogical Data Communication (GEDCOM) files. The salient feature of these files is the vast genealogical information they contain about individuals and families. When used as identity markers, they create a layered, historically authenticated representation that is innately resistant to forgery and fraud.

    In the GIP system, GEDCOM files form the foundation of identity representation. Each GEDCOM file serves as a detailed, dynamic, and individualized identity dossier, accurately reflecting the unique familial lineage and heritage of the user. This distinctive identity marker enhances security within the Bitcoin ecosystem by providing a robust defense against identity theft and impersonation.

    However, the role of GEDCOM files within the GIP extends beyond being static identity markers. These files are dynamic entities that drive various interactions within the Bitcoin ecosystem, including transactions, authorizations, access controls, and other blockchain engagements. The user's GEDCOM-based identity is tied to these functionalities, ensuring a secure, transparent transactional environment characterized by verifiable authenticity.

    The GIP further enhances the utility of GEDCOM files through an adaptive versioning system, permitting continuous updates and refinements. This feature enables each new version of a GEDCOM file to undergo independent authentication, with associated levels of signatures. The continuous refinement and authentication process ensures the ongoing enrichment of an individual's genealogical data, fostering user engagement and community validation.

    This adaptive versioning system effectively addresses the inherent complexity of genealogical data, which often involves potential discrepancies or inaccuracies, particularly with respect to distant relatives. Each GEDCOM file version becomes a timestamped snapshot of a person's genealogical data at a particular point in time, with subsequent versions forming a chronological archive. This methodology provides a granular understanding of the data's evolution and adds an extra layer of authenticity.

    Further enhancing security, the GIP introduces a proofing mechanism against the longest unbroken chain of ancestors. This system uses the Longest Common Substring as a verification tool to maintain consistency and coherence across different versions of a GEDCOM file.

    The integration of GEDCOM files in the GIP represents a significant departure from traditional digital identity systems. The GIP presents a comprehensive, secure, and flexible identity management solution that not only ensures privacy and security but also offers flexibility, adaptability, and a reflection of real-world complexities. By empowering individuals with control over their identities and recognizing their personal history's complexity, GIP lays the foundation for a dynamic and multidimensional identity system.

    Hash-Based Dependencies

    The Genealogical Identity Protocol (GIP) employs hash-based dependencies to encapsulate the nuances and dynamism of modern familial relationships within its innovative genealogical model. These dependencies encode intricate family bonds into the Bitcoin blockchain, leading to a highly secure, accurate, and verifiable representation of complex familial structures.

    Families in the modern world often break away from traditional boundaries, encompassing non-traditional structures such as step-parenting, adoption, co-parenting, and more. The GIP, through the use of digital signatures, incorporates these diverse family structures, ensuring that every unique familial bond is authenticated and represented accurately within the system.

    However, the mathematical modeling of these dynamic relationships poses a significant challenge, primarily due to their inherent dynamism and potential circular dependencies. In response, the GIP models hash-based dependencies as dynamic edges, signifying that the unique identifier (hash) of a GEDCOM file is not static and can evolve over time as new information becomes available or when newer versions of the GEDCOM files are created.

    To illustrate, consider a situation where an individual and their parents have completed their GEDCOM files, but the grandparents' files remain incomplete. The incomplete grandparents' hash needs to be integrated into the GEDCOM files of both the individual and their parents. This interdependency forms a circular loop, where the completion of one hash depends on the finalization of another. The GIP's versioning system provides a solution to this complexity.

    The versioning system, in conjunction with the dynamic nature of hash-based dependencies, manages these intricacies effectively. Each version of a GEDCOM file presents a snapshot of an individual's genealogical data at a particular moment. As more information becomes available, or as updates occur, newer versions of the GEDCOM files can be created, which include the updated hash. This iterative process ensures the system remains flexible and responsive to changes and updates.

    The GIP employs a unique signing scheme to manage hash-based dependencies and facilitate the instantiation of GEDCOM files. Once an individual finalizes their GEDCOM file, they sign it and send it to their parents. The parents then integrate the child's hash into their GEDCOM file, sign it, and send it back. The child then generates a new version of their GEDCOM file, incorporating the parent's signed hash, and signs the new version. This process can be replicated across multiple generations, resulting in an authenticated, complete family tree.

    The integration of hash-based dependencies and the adaptive versioning system in the GIP addresses the challenges of digitally representing complex familial relationships. By accurately capturing these relationships and managing their inherent dynamism, the GIP extends the concept of digital identity beyond traditional paradigms, providing an identity model that truly reflects the complexities of human relationships in the digital era.

    Digital Signatures

    Digital signatures play a pivotal role within the Genealogical Identity Protocol (GIP), acting as the foundation for transaction authorization and asset ownership verification within the Bitcoin ecosystem. Their versatility extends across different contexts, allowing individuals to manage their degree of identity disclosure, ranging from full disclosure in high-stake environments like passport offices to pseudonymous interactions on low-risk platforms such as social media.

    This flexibility stems from the GIP's unique approach to constructing signing identities. Depending on the context, various collections of data fields can be used to create distinct signing identities, encompassing realms such as business interactions, social media engagements, and legal proceedings. This approach integrates seamlessly with key management software, allowing users to authenticate with services requesting specific identity elements from their portfolio and GEDCOM file.

    When a user needs to authenticate with a service that may request the signing of an engagement log, a fresh key can be generated. This key maps to the selective exposure of specific values from all the possible identity elements. The assignment of keys to identities hinges on the particular service's requirement threshold, allowing the system to cater to different levels of identity verification requirements, such as a "100 points of ID" system or a zero-knowledge proof verifying one's age.

    Digital signatures within the GIP offer a robust method for secure transaction authorization and identity verification. This system bridges the gap between digital and physical identities and enables secure interactions within the Bitcoin ecosystem. The integration fosters trust and confidence in transactions and engagements within this ecosystem.

    However, the practical application of digital signatures extends beyond transaction security. The GIP grants users control over the extent of their identity disclosure, accommodating the fluidity and complexity of modern identities. This user-centric approach ensures a high level of privacy, marking a significant departure from traditional identity verification methods, which often lack the adaptability to cater to the diverse needs of users in the digital era.

    In essence, the implementation of digital signatures within the GIP signifies a remarkable innovation in digital identity management. By offering a secure, flexible, and user-focused system for identity management, the GIP adapts to the demands and intricacies of the modern world. This system empowers individuals to exercise control over their digital identities, emphasizing privacy and individuality.

    Identity Verification

    An integral component of the Genealogical Identity Protocol (GIP) is its identity verification process. Relying on merkle proofs of subsets of data fields from a user's identity portfolio, corroborated by family tree data structures, the GIP forges a reliable and secure system for validating identities. The inherent interconnectedness and the unalterable nature of familial bonds create a robust infrastructure, enhancing the credibility of identity assertions.

    These proofs offer a flexible system that can be tailored to various components of the identity protocol, adjusting to specific use cases. For example, certain proofs may necessitate a genealogical intersection with the societal family tree, while others could require attestations from designated experts in specific business sectors, with a particular emphasis on their intersector network connections.

    This adaptive identity verification system contributes significantly to the robustness and integrity of the data. It safeguards privacy by managing the exposure of sensitive data through selective disclosure. Users can regulate who can access their data and under what conditions, fortifying privacy protection.

    The GIP also introduces the concept of self-sovereign data markets. It empowers users to leverage their anonymized data by selling it while proving its genetic provenance and demographic suitability without disclosing personally identifiable information. This mechanism could stimulate the emergence of secondary data markets, where individuals have the freedom and security to benefit from their anonymized personal data.

    Moreover, the GIP offers cryptographic assurances for identity verification. This includes the use of Public Key Infrastructure (PKI) to sign digital certificates, ensuring that the identity claims are made by the rightful owners and are not tampered with. The protocol also incorporates deterministic hash chains, which provide a way to construct a series of related hashes, where each hash depends on the previous one, adding an extra layer of security and traceability.

    In summary, the GIP's approach to identity verification provides a comprehensive, resilient, and adaptable solution. Through a combination of merkle proofs, family tree data structures, expert attestations, and advanced cryptographic techniques, it addresses the complexities inherent in digital identities. Furthermore, by facilitating selective access management and the creation of secondary data markets, the GIP stands as a progressive, user-centric solution in the realm of digital identities.

    Standards

    The Genealogical Identity Protocol (GIP) is designed to work in harmony with a broad range of identity protocols worldwide, inclusive of self-sovereign identity (SSI) frameworks and internationally recognized standards like the ISO/IEC 29115:2013 entity authentication assurance framework. This interoperability is made possible due to the GIP's state-of-the-art key management strategies, ensuring secure interfacing with various external protocols while safeguarding user privacy.

    Adherence to the principles of self-sovereign identity forms the backbone of GIP. Principles like user-centric control over personal data, transparency, interoperability, and persistent identities are central to its design. This foundational alignment enables GIP to integrate seamlessly with SSI frameworks that are being developed and adopted globally, empowering users to control, manage, and utilize their digital identities across a myriad of applications. These applications span from social media platforms to financial services, while concurrently preserving user privacy and data security.

    Similarly, the GIP is compliant with international identity standards such as ISO/IEC 29115:2013, which provides an entity authentication assurance framework. Such compliance assures that GIP identities are recognized, verified, and accepted in the global digital market, opening doors to a wide spectrum of uses and applications for GIP users around the world. This adaptability positions the GIP as a flexible and universal solution for digital identity management, capable of operating within a diverse range of regulatory environments and digital ecosystems.

    In essence, the GIP's global alignment and seamless integration with international identity standards, supplemented by its pioneering features and groundbreaking design, positions it as a versatile and forward-thinking solution for digital identity management. By offering a secure, adaptable, and user-centered approach to identity management, the GIP signifies a significant leap forward in the domain of digital identities. Its compatibility with a diverse range of international regulatory environments and digital ecosystems further amplifies its utility and potential, marking it as a valuable asset for individuals and organizations in today's digital world.

    Regulatory Compliance

    The Genealogical Identity Protocol (GIP) is constructed with regulatory compliance at its core, particularly focusing on key global standards such as the European General Data Protection Regulation (GDPR).

    GDPR compliance is particularly significant as it's one of the most comprehensive and stringent data protection frameworks worldwide. It outlines robust requirements for the handling of personal data of EU citizens, including principles like data minimization, purpose limitation, accuracy, and the rights to access, rectification, and erasure.

    In accordance with GDPR, the GIP's design ensures that only the minimum necessary data is collected and processed. All data handling operations align with the purpose limitation principle, i.e., data is used solely for the purpose for which it was collected, with no scope for unauthorized or unexpected usage. Data accuracy is maintained through the GIP's innovative use of blockchain technology, which enables secure, tamper-proof record-keeping.

    Moreover, the GIP empowers users with direct control over their data. They can access their data at any time, correct inaccuracies, or request deletion of their data, aligning with the GDPR's rights of access, rectification, and erasure. This is made possible by the self-sovereign nature of the GIP, which places data control directly in the hands of the users.

    The GIP's use of sophisticated cryptographic techniques for data protection further enhances its GDPR compliance. These techniques protect the confidentiality, integrity, and availability of data, meeting the GDPR's requirements for data security.

    In addition, the GIP is designed to be adaptable to other data protection regulations globally. Its principles of minimal data collection, purpose limitation, accuracy, security, and user control are common to many data protection frameworks, making it easier for the GIP to comply with varying regulatory requirements across different jurisdictions.

    In conclusion, the GIP's strong focus on regulatory compliance, especially with the GDPR, makes it a secure and trustworthy solution for digital identity management. By prioritizing user privacy and data protection, the GIP enables individuals to engage with digital services with confidence, safe in the knowledge that their personal data is being handled responsibly and securely.

    Knowledge Assets in a Decentralized World

    The GIP, in alignment with Dan Roble's Innovation Bank model, considers an individual's genealogical data stored in GEDCOM files as a form of 'Knowledge Asset' (K-Asset). In this context, a K-Asset is seen as the fundamental unit of account, a validated claim that defines an individual's unique identity and family lineage.

    Under the GIP, each GEDCOM file - a record of a user's family history - serves as a K-Asset, providing a vast repository of quantifiable and qualifiable data. This data not only holds the key to the individual's identity but also represents potential economic value that can be leveraged within the broader Bitcoin ecosystem.

    Just as a physical asset like gold or real estate can be quantified (by weight or square footage, for instance) and qualitatively assessed (based on purity or location), so too can these K-Assets be evaluated. The quantity, in this case, refers to the extensive data points contained within each GEDCOM file, while the quality refers to the accuracy and completeness of this data, verified through the protocol's robust identity verification mechanisms.

    The concept of K-Assets aligns with the growing global movement towards self-sovereign identity (SSI) protocols. These protocols aim to empower individuals by granting them ownership and control over their personal data. By framing genealogical data as a K-Asset, the GIP pioneers a new form of SSI, one that leverages the inherent value of an individual's family history.

    In the larger context of network value (NV) versus hierarchy value (HV), the GIP serves as a decentralized network platform that emphasizes NV. Drawing parallels to modern platforms such as Google, Facebook, and AirBnB, the GIP aims to harness the power of network effects, using the interconnectedness of genealogical data to bridge disparate communities and derive value from the intrinsic coordination of those combined communities.

    In this network-centric model, the value of the GIP ecosystem grows as more users join the network and contribute their unique genealogical data. This stands in contrast to traditional, hierarchy-based systems, which often struggle to adapt to the dynamic and diverse needs of users.

    By categorizing genealogical data as K-Assets, the GIP pushes the boundaries of what constitutes an asset in the digital era, blurring the line between tangible and intangible, physical and digital. This unique approach empowers individuals to take control of their identities, facilitates the creation of secondary data markets, and paves the way for new forms of economic interaction within the Bitcoin ecosystem.

    Proof of Ancestor

    The Genealogical Identity Protocol (GIP) features an innovative mechanism known as 'Proof of Ancestor', which utilizes the power of genealogical data and advanced cryptography to deliver irrefutable proofs of lineage.

    This unique system is founded upon the principle that each individual's unique lineage constitutes a secure backbone for their identity. By verifying their connection to specific ancestors, an individual bolsters the credibility and authenticity of their identity.

    The implementation of 'Proof of Ancestor' extends beyond identity validation; it also provides a robust system for managing, authenticating, and preserving historical data. Through the digitization and encoding of each person's lineage into the Bitcoin blockchain via GEDCOM files, an immutable ancestral footprint is established. This information is openly verifiable, offering a decentralized method for maintaining and accessing historical data while maintaining privacy through pseudonymity.

    Considering the complexity and depth of genealogical data, the GIP takes into account the management of discrepancies and potential conflicts inherent to this information. The 'Proof of Ancestor' mechanism allows for timestamped snapshots of an individual's genealogical data, serving as version-controlled GEDCOM files that encapsulate the historical progression of a person's lineage. This enables the verification of data consistency and coherence, ensuring its accuracy and authenticity over time.

    An additional layer of security is established through the implementation of the Longest Common Substring (LCS) method. By verifying the longest unbroken chain of ancestors across different versions of GEDCOM files, the LCS process ensures data consistency and integrity, providing a robust defense against potential data tampering or falsification.

    In conclusion, the 'Proof of Ancestor' mechanism within the GIP revolutionizes the concept of identity verification within the Bitcoin ecosystem. It not only enhances security and trust within the system, but it also pioneers a novel method of historical data preservation and access. The unique blend of genealogical data, advanced cryptographic techniques, and blockchain technology yields a secure, verifiable, and resilient approach to digital identity management.


    Implementation

    To implement the GIP within the Bitcoin ecosystem, a step-by-step approach must be taken. The implementation can be outlined in four broad stages - Setup, Data Collection, Identity Verification, and Transaction Authorization.

    To ensure the GIP's successful implementation, it is essential to conduct regular system audits and maintenance. This will help to identify and resolve any potential issues or vulnerabilities in the system, maintaining its effectiveness and security.

    By following this approach, the Genealogical Identity Protocol can be successfully implemented within the Bitcoin ecosystem, providing a secure, reliable, and innovative solution for identity management. Its successful implementation will serve as a significant milestone in the development of the Bitcoin ecosystem, offering an unprecedented level of security and verifiability for digital identities.

    Software Development

    The proposed software implementation to operationalize the Genealogical Identity Protocol (GIP) indeed requires careful planning and development. The outlined functionalities and user-experience are critical for adoption and efficient use of the system.

    GEDCOM File Creation and Management

    The first significant component is the software for creating and managing GEDCOM files. This software should enable users to input their data efficiently and accurately. It should guide users through the process, providing clear instructions and explanations to ensure the accuracy and completeness of the data. In addition, it should have features for checking and validating the data, including automated checks for common errors and inconsistencies.

    User Interface

    A user-friendly interface is essential for broad adoption and efficient use of the software. It should be designed with a strong focus on usability and user experience, ensuring that even users who are not familiar with genealogical data or blockchain technologies can use the software effectively. The interface should be clean, intuitive, and responsive, with clear navigation and workflow.

    Attestation and Versioning

    The software should support an attestation mechanism, allowing users to pass their GEDCOM file to others for verification and attestation. Additionally, an inbuilt versioning system is crucial for managing updates and changes to the GEDCOM file. Users should be able to create new versions of their GEDCOM files, collect digital signature attestations on them, and easily traverse past versions.

    Extended Data Fields

    To accommodate hash-based dependencies, the software needs to extend the data fields of the GEDCOM file. It should allow for the input of these dependencies in the connecting values between parent, child, and sibling nodes. This requires careful planning and design to ensure that the software can handle these additional data complexities effectively.

    Key Management System

    Alongside the GEDCOM file management software, a robust key management system needs to be developed. This system will manage the digital signatures used for transaction authorization and asset ownership verification. It must be secure, efficient, and able to handle high transaction volumes.

    Testing and Deployment

    Once developed, the software should be thoroughly tested to ensure its functionality, performance, and reliability. It should be deployed in a phased manner within the Bitcoin ecosystem, with each phase thoroughly tested before moving to the next. This allows for any issues to be identified and addressed promptly.

    Implementing this software solution is a considerable undertaking that will require a highly skilled and experienced development team. However, with careful planning and execution, it can significantly enhance the security, efficiency, and user experience of the GIP, driving its adoption and success.

    Data Security & Privacy Protocols

    Implementing data security and privacy protocols in the Genealogical Identity Protocol (GIP) is essential given the sensitive nature of the genealogical data stored in GEDCOM files. These protocols should be designed to protect the data from unauthorized access and ensure its confidentiality and integrity. Here are some key considerations:

    • Data Encryption: All genealogical data should be encrypted both at rest and in transit. Strong encryption algorithms should be employed to ensure that even if the data is intercepted or accessed without authorization, it cannot be read or used.

    • Access Controls: Proper access controls should be in place to ensure that only authorized individuals can access and modify the GEDCOM files. This can involve the use of multi-factor authentication, biometric verification, or other advanced security measures. Access controls should also be granular, allowing different levels of access and permissions based on roles and needs.

    • Data Minimization and Anonymization: Whenever possible, the system should use data minimization and anonymization techniques to limit the amount of personal data stored and processed. This can involve only collecting and storing the minimum necessary data, and anonymizing data when it is used for processing or analytics.

    • Secure Key Management: The key management system used for managing the digital signatures should be highly secure, and should follow best practices for key generation, storage, and use. This can involve the use of secure hardware for key storage, regular key rotation, and protocols for key revocation and renewal.

    • Auditing and Monitoring: The system should have robust auditing and monitoring capabilities to track all actions performed on the data. This can help detect any unauthorized or suspicious activities and respond quickly to any potential security incidents.

    • Privacy-by-Design: The system should follow the principles of privacy-by-design, which involves considering privacy and data protection issues at the design phase of the system, and building in appropriate safeguards from the start.

    With these protocols in place, GIP can ensure robust security and privacy protection for the sensitive genealogical data it handles, building trust with its users and ensuring compliance with data protection laws and standards.

    Gathering and Inputting Genealogical Data

    Gathering and inputting genealogical data is a vital step in the deployment of the Genealogical Identity Protocol (GIP). Here's how it can be effectively done:

    • Self-Reporting: Users within the Bitcoin ecosystem will self-report their genealogical data. This method puts users in control of their data, ensuring they are the primary source of their own genealogical information.

    • User Interface: The interface provided for data input should be intuitive and user-friendly, with fields clearly labeled and guidance provided for each input. This can be facilitated via an easy-to-use software application designed for creating and managing GEDCOM files. The software should guide the user through the data entry process, helping them understand what information is required, why it's needed, and how it will be used.

    • Data Validation: To ensure the accuracy of the genealogical data provided, there should be mechanisms in place to validate the data. This could involve automated checks for consistency and completeness, prompts for users to review and confirm their data, and support for verifying data through cross-referencing with other sources or users.

    • User Support: It is crucial to provide ample support to users throughout the data gathering and input process. This could involve tutorials, FAQ sections, and readily available customer service to guide users through the process.

    • Iterative Updates: Given the complexity and evolving nature of genealogical data, the system should support iterative updates. This feature would allow users to update their GEDCOM files as new information becomes available or as changes occur in their genealogical data.

    • Privacy and Consent: Before gathering and inputting genealogical data, the system should clearly inform users about the privacy measures in place to protect their data and obtain their informed consent. Users should have a clear understanding of how their data will be used, who will have access to it, and how they can control or update their information.

    By adopting this structured and user-centric approach to data gathering, the GIP can ensure accurate and efficient collection of genealogical data, facilitating the creation of a secure and unique identity management system within the Bitcoin ecosystem.

    Data Accuracy

    Accuracy of genealogical data is a cornerstone in the successful implementation of the Genealogical Identity Protocol (GIP). Inaccuracies could indeed jeopardize the system's integrity and effectiveness. To maintain this accuracy, several measures could be undertaken:

    • User Education: Users should be educated about the importance of accurate data entry. They need to understand that the GIP relies on the correctness of this information for proper functioning. Guidelines and educational materials could be provided to users explaining the significance of accurate data, potential impacts of inaccuracies, and methods for ensuring the correctness of their entries.

    • Cross-Verification: The system could cross-verify the information provided by users against other reliable sources such as external genealogical databases or government records. While this might pose privacy challenges, it could be handled carefully with the consent of the users and by ensuring the confidentiality of the data checked.

    • Cryptographic Attestations: Another way to ensure data accuracy is by involving family members and relatives in the process. Once a user submits their genealogical data, relatives could provide cryptographic attestations confirming the correctness of the information. This not only ensures the accuracy of the data but also adds an additional layer of security to the system.

    • Continuous Updates and Correction: The GIP should be designed to allow for easy updates and corrections. As genealogical data is dynamic and might change or evolve over time, users should be able to make changes to their GEDCOM files as needed. They should be able to rectify any errors or update their files to reflect new information.

    • Auditing and Reporting Mechanisms: To maintain data accuracy, periodic audits could be performed. Users could also be encouraged to report any discrepancies they notice. This vigilance will help in maintaining the integrity of the system and ensuring its continuous accuracy.

    By incorporating these measures, the GIP can ensure the accuracy and integrity of the genealogical data collected. This will not only make the system more reliable but also enhance its acceptance and credibility among users.

    Identity Verification

    The fifth step in implementing the Genealogical Identity Protocol (GIP) is identity verification, a crucial component that ensures the authenticity of individuals within the Bitcoin ecosystem.

    • Utilizing GEDCOM Files for Identity Verification: Each GEDCOM file is unique to an individual and is the primary tool for identity verification within the GIP. These files serve as an individual's digital fingerprint within the system, representing their unique genealogical identity. When an individual makes a claim of identity, the system cross-references this claim against the data contained in the individual's GEDCOM file. This process provides a highly secure and reliable form of identity verification.

    • Cryptographic Methods in Identity Verification: The use of cryptographic methods such as digital signatures and hash-based dependencies significantly enhance the security and robustness of the identity verification process. Digital signatures authenticate the identity claims made by individuals, ensuring that the claim is indeed made by the individual it purports to be. Hash-based dependencies, on the other hand, ensure the integrity of the data within the GEDCOM files. By verifying that the genealogical data has not been tampered with, they provide an additional layer of security to the system.

    • Proof of Ancestor Mechanisms: These mechanisms offer an additional level of identity verification within the GIP. By cross-referencing an individual's genealogical data with other familial connections within the ecosystem, they verify the individual's lineage claims. This provides an extra layer of authentication, further bolstering the credibility and reliability of the system.

    • Ensuring a Trustworthy System: The identity verification process is integral to establishing a trustworthy GIP. By accurately verifying the identities of individuals within the Bitcoin ecosystem, it ensures the security and reliability of the system. The use of advanced cryptographic methods further mitigates the risk of fraudulent activity, fostering an environment of trust and confidence among users.

    The identity verification process is a crucial component of the GIP implementation. It employs sophisticated cryptographic techniques to verify the authenticity of identity claims and to protect the integrity of the genealogical data. In doing so, it establishes a secure and trustworthy identity management system within the Bitcoin ecosystem

    Transaction Authorization

    The final stage in the GIP implementation process, transaction authorization, ensures that every transaction made within the Bitcoin ecosystem is secure, authenticated, and involves identities that have been verified using the GEDCOM files. This is the stage where all the previous steps come together to provide a seamless and trustworthy transaction experience for all participants in the ecosystem.

    • Peer-to-Peer Transaction Model: A core aspect of transaction authorization in the GIP involves a move away from the traditional server-based model towards a peer-to-peer transaction model. This enables users to authenticate transactions directly with their network peers. This eliminates the need for a central server and provides a highly scalable network architecture that enables efficient transaction validation at the edge of the network.

    • Contact Books of Network Peers: In this system, users create 'contact books' or lists of network peers whom they can trust. These contact books are built based on validated GEDCOM files and verified identities, providing a solid foundation of trust within the network. Transactions can then be authorized directly between peers, leveraging the security and verification features provided by the GIP.

    • End-to-End Authentication: The GIP employs end-to-end authentication to secure the transactions that are passed from one peer to another. This advanced security feature ensures that only the intended receiver can accept and validate the transaction, thereby significantly reducing the chances of fraud or unauthorized access.

    • Double-Spend Check: Despite the decentralization of transaction authorization, a mechanism for preventing double-spending is necessary to maintain the integrity of the Bitcoin ecosystem. In this scenario, the 'small world miner network' comes into play. This network of miners, who are closer in terms of network hops, can efficiently verify whether the same Bitcoin has been spent twice, thereby maintaining the overall security of the system.

    In conclusion, the transaction authorization phase is critical for implementing the GIP. By using a decentralized model and advanced security features, it ensures that transactions are secure, reliable, and involve only verified identities. This fosters an environment of trust and confidence, laying the groundwork for a secure and efficient system of identity management and transactions within the Bitcoin ecosystem.


    ##References Robles, D.R., Layton, B.E. "The Innovation Bank: Blockchain Technology and the Decentralization of the Engineering Professions." Available at: https://bico.media/7c7161e2ff483e6df2fdc4a4d5d0396811cd1defb74c96d0ecf44797ad0bde0b

    Field 6

    Optional. If provided, comprises a Regular Expression that is used to test if the message box is supported. If the regular expression passes, the PeerServ instance supports the message box. This is only an optional "fail fast" mechanism, and instance operators must be prepared to reject messages that are destined for users or message boxes they are unwilling to support.

    BRC-48
    BRC-48
    BRC-48
    BRC-48
    BRC-31
    BRC-31
    BRC-31
    BRC-31
    BRC-69

    Unified Abstract Wallet-to-Application Messaging Layer

    • Ty Everett ([email protected])

    • Brayden Langley ([email protected])

    Abstract

    The importance of a standard interface by which Bitcoin applications can communicate with wallets and underlying infrastructure cannot be overstated. We propose an identity interface facilitating the creation of Bitcoin transactions, the use of user-held keys for encryption and digital signatures, and the employment of identity certificates to authenticate users with their counterparties. We set a baseline standard and create a versioning system that facilitates continued expansion and extensibility over time.

    Motivation

    Computing has long been subject to shortfalls in the areas of information centralization and architectural cross-compatibility. Users on the internet struggle with complex and insecure authentication systems which leave them vulnerable and leak their data. Websites rely on advertising to monetize their offerings, but ads warp the incentives of platforms and creators in ways that ultimately harm everyone involved. By defining a standard interface by which users can identify themselves, protect their data and engage in e-commerce with Bitcoin, this standard offers a solution to problems that have long plagued the existing model.

    Specification

    We specify a baseline standard for an abstract messaging layer which facilitates an identity interface between an application and an underlying MetaNet Client. As part of this messaging layer, we incorporate various message types defined by other BRC standards:

    • : We incorporate by reference the message types relating to Bitcoin transaction creation as specified by . This facilitates micropayment-based interactions as part of applications, enabling new monetization models that are not subject to the same problematic incentives as internet-based advertising.

    • : We incorporate by reference the message types relating to encryption as specified by . This facilitates user privacy and provides a secure foundation for user-to-user communication, enabling applications which protect privacy to emerge and gain traction.

    • :

    With these core components in place, we are left only with the need to specify a few other messages that are necessary to facilitate versioning, user network checking and user-to-wallet authentication status discovery. We now proceed to the specification of those auxiliary messages.

    HMACs

    The introduction of HMACs are the most significant addition aside from the core message types. HMACs facilitate authenticating messages sent between users, and are generally useful for a wide range of applications.

    We stipulate the following process for HMAC creation:

    • The message sender begins by computing the invoice number based on the security level, protocol ID, and key ID

    • The message sender uses key derivation with the computed invoice number to derive a child public key for the recipient

    • The message sender uses key derivation with the computed invoice number to derive their own child private key

    We stipulate the following process for HMAC verification:

    • The recipient somehow comes to know the HMAC, the message, the counterparty, the security level, protocol ID, and key ID. The mechanism for conveying this information to the recipient is beyond the scope of this specification.

    • The recipient begins by computing the invoice number based on the security level, protocol ID, and key ID

    • The recipient uses key derivation with the computed invoice number, their own private key and the public key of the sender, to compute the sender's child public key

    HMAC Creation Request

    The HMAC Creation Request is a message sent by the application to the client. It contains a header with the following information:

    Field
    Description

    The message payload comprises the data to HMAC.

    HMAC Creation Response

    The response message comprises a payload containing the computed HMAC value.

    HMAC Verification Request

    The HMAC Verification Request is a message sent by the application to the client. It contains a header with the following information:

    Field
    Description

    The message payload comprises the data to verify against the HMAC provided in the header.

    HMAC Verification Response

    The response message comprises a payload containing a boolean that indicates whether the HMAC was successfully verified.

    HMAC Error

    If the client is unable to fulfill the HMAC Creation or Verification Requests for any reason except failed verification, we specify that it should respond with a JSON-formatted HMAC Error. The fields for the object are specified as follows:

    Field
    Description

    One example of an HMAC Error is given below:

    Public Key and Certificate Retrieval

    Facilitating access to public keys and certificates are a crucial part of the wallet messaging layer as they provide the necessary components for identity verification. is used for defining the protocolID and keyID formats, and defines the format of certificates requested.

    Public Key Request

    To request a public key, we define the following standard request fields:

    Field
    Description

    When the wallet receives this request from the application, after obtaining requisite permission from the user, we stipulate the following process for key derivation:

    1. If identityKey is true, the wallet returns its root public identity key to the application without proceeding to the other steps.

    2. The wallet checks the invoice number based on the security level, protocol ID, and key ID

    3. If forSelf is false, the wallet uses key derivation with the computed invoice number to derive a child public key for the counterparty, returning the public key.

    Public Key Response

    The response message comprises a 33-byte, DER-encoded public key X coordinate value.

    Public Key Error

    If the client is unable to fulfill the Public Key Request for any reason, we specify that it should respond with a JSON-formatted Public Key Error. The fields for the object are specified as follows:

    Field
    Description

    One example of a Public Key Error is given below:

    Certificate List Request

    To request a list of identity certificates belonging to the user, we define these standard request fields:

    Field
    Description

    When the wallet receives this message from the application, the wallet will ascertain based on user preferences and the information provided which certificates will be returned. The wallet is by no means required to return all responsive certificates, if for example the user does not want to reveal a particular affiliation in a particular context. The wallet composes a list, which may be empty, of responsive certificates.

    Certificate List Response

    The response from the wallet to the application comprises an array of identity certificates, which may be empty.

    Certificate List Error

    If the client is unable to fulfill the Certificate List Request for any reason except an empty list, we specify that it should respond with a JSON-formatted HMAC Error. The fields for the object are specified as follows:

    Field
    Description

    One example of a Certificate List Error is given below:

    Network, Versioning and Authentication

    Another important aspect of the wallet messaging layer is allowing applications the ability to check which Bitcoin network is in use, and whether or not a user has been authenticated.

    Bitcoin Network Request

    To determine which Bitcoin network a user's MetaNet Client is currently using, applications can make requests to a standardized endpoint to ensure compatibility.

    We define that the request message has no content (beyond the fact of it being a Bitcoin Network Request) and simply returns a string of either "test" or "main" indicating the current network in use.

    Client Version Request

    We define the standard client version request to contain no parameters (beyond the fact of it being a Client Version Request) and to simply return the version of the MetaNet Client in use as a string.

    For historical reasons, to denote compatibility with these specifications, we stipulate that the version should be in the range 0.3.x. For example, 0.3.80.

    Authentication Status Request

    The authentication status request requires no parameters and returns a boolean indicating whether the current user is "authenticated" or not.

    The purpose of this functionality is to facilitate software where the user can "log in" once in their client, and never need a separate login for MetaNet applications. When not authenticated, the application should assume that none of the other functionality, aside from client version checks, will work. It provides a way for applications, when they load, to ensure that the communication system with the client is operational, as a sort of "ping" request that also ensures the user is set up with a wallet.

    Asynchronous Authentication Request

    The asynchronous authentication request requires no parameters and waits until the user is authenticated before returning a response of true.

    Implementations

    Implementations of this specification will need to decide on a concrete transport layer (referred to as a "substrate") to facilitate communication between the wallet and applications. Application developers will then need to write their applications in a way that facilitates communication over the substrate, and wallets will need to properly handle incoming requests from applications.

    Some examples of communication substrates include:

    • , for operating a wallet over HTTP on a local machine, enabling applications on that machine to interact with the running wallet.

    • , for cross-document messaging between a parent page which runs a wallet and a set of child pages which run various applications.

    • , for exposing an identity interface via the window object in web browsers.

    The BRC-56 functions and messages, across these three substrates, have been implemented by the Babbage team in the .

    Identity Certificates

    • Brayden Langley ([email protected])

    • Ty Everett ([email protected])

    Abstract

    We incorporate by reference the message types relating to digital signatures as specified by
    . This facilitates generalized message sender attestation and endorsement, solving problems such as fake AI-generated content by allowing relevant parties or the entire world to check whether something has been endorsed by its purported originator.
  • BRC-4: We incorporate by reference the extension to BRC-1 as defined by BRC-4, providing for the consumption and utilization of arbitrary UTXO-based Bitcoin tokens as part of transactions. This facilitates the creation and transfer between users of tokenized assets without restrictions beyond those set by their respective output locking scripts.

  • BRC-46: We incorporate by reference the extension to BRC-1 as defined by BRC-46, providing for the tracking and management of Bitcoin UTXOs in baskets. This facilitates the storage and retrieval of single-party tokens and digital assets in the user's wallet while removing the need to rely on a single trusted application for asset management.

  • BRC-50: We incorporate by reference the message types relating to incoming transaction submission as specified by BRC-50, ensuring users have a way to receive funds into their wallets from within applications. This gives them a way to receive payment for the value they create as part of their interactions within applications.

  • BRC-53: We incorporate by reference the message types relating to digital identity certificate creation and revelation, as specified by BRC-53. This provides a way for users to maintain and selectively reveal their identities with specific counterparties in the digital world, facilitating an increased level of trust and accountability.

  • The message sender computes the ECDH shared secret between the two derived child keys
  • The resulting elliptic curve point's X and Y values are hashed with SHA256 to create a SHA-256 HMAC key

  • The resulting 256-bit value is used to compute the SHA-256 HMAC for the message

  • The HMAC value is returned by the client to the application over the abstract BRC-1 communications substrate.

  • The recipient uses the same process to compute his own child private key

  • The recipient computes a shared secret between the two child keys, using the hash of the X and Y values as a SHA-256 HMAC key

  • The recipient then uses the HMAC key to compute the HMAC of the message, checking that the computed value matches the provided value

  • Otherwise, if forSelf is true, the wallet uses BRC-42 key derivation with the computed invoice number to derive their own child private key. The wallet then multiplies the private key by the generator point, G, to arrive at their own child public key, as would be derived by a counterparty. The computed public key is returned.

  • protocolID

    The BRC-43 security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The BRC-43 key ID

    counterparty

    The BRC-43 counterparty, or self

    protocolID

    The BRC-43 security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The BRC-43 key ID

    counterparty

    The BRC-43 counterparty, or self

    hmac

    This is the HMAC value that is to be verified, for the provided message

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_PERMISSION_DENIED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    protocolID

    The BRC-43 security level and protocol ID represented as an array. For example, [0, "hello world"] represents a level-0 protocol with open permissions, while [2, "document signing"] represents a level 2 protocol.

    keyID

    The BRC-43 key ID

    counterparty

    The BRC-43 counterparty, self, or anyone

    forSelf

    Whether the derived child public key corresponds to a private key held by the current user. (optional, default false)

    identityKey

    If true, the identity key will be returned, and no key derivation will be performed (optional, default false). Overrides protocolID, keyID, counterparty, and forSelf.

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_PERMISSION_DENIED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    certifiers

    An array of the public keys for certifiers to filter certificates by: only certificates issued by these certifiers will be returned.

    types

    The certificate types to filter certificates by, given as an object whose keys are types and whose values are, for historical reasons, arrays of fields to request from certificates of the given type. Note that unless all fields are returned, no one can validate the certificate signature. We therefore specify that if true is provided in place of an array of fields, that all fields should always be returned.

    status

    This should always be a string comprising "error".

    code

    A machine-readable error code. Extensions to this standard can define specific error codes and standardize additional fields. Codes are strings, for example "ERR_PERMISSION_DENIED".

    description

    All errors must have a human-readable description field that describes the error. This allows the application to represent the error for the user.

    BRC-1
    BRC-1
    BRC-2
    BRC-2
    BRC-3
    BRC-43
    BRC-42
    BRC-42
    BRC-43
    BRC-42
    BRC-43
    BRC-43
    BRC-52
    BRC-43
    BRC-42
    BRC-52
    BRC-52
    BRC-5
    BRC-6
    BRC-7
    Babbage SDK
    BRC-3
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "The user has denied permission for computing an HMAC over this data."
    }
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "The user has denied permission for revealing their identity public key."
    }
    {
      "status": "error",
      "code": "ERR_PERMISSION_DENIED",
      "description": "The user has denied permission for obtaining a list of certificates."
    }
    Identity on the internet has come to rely almost exclusively on trusted third parties acting as gatekeepers for user authentication. Digital signatures provide part of the solution, but there is still a need to link the public key with the true identity of the signer, while still tolerating key compromises. We define an open-ended, ubiquitous and privacy-centric version of digital identity certificates that facilitate selective revelation and UTXO-based revocation. BRC-3 digital signatures ensure the authenticity of certified fields, while BRC-2 encryption facilitates an approval-based access control scheme. In this standard, we define the data structures, key derivation protocols, signing and verification procedures for identity certificates. We also discuss how responsible certificate issuers can handle key compromises.

    Motivation

    The motivation behind this standard is to address the limitations of digital signatures for verifying the true identity of internet users, a verification process which currently relies heavily on passwords and trusted third parties.

    The goal is to create an open-ended, privacy-centric, and ubiquitous solution for digital identity certificates that facilitates selective revelation and UTXO-based revocation. This standard aims to provide a decentralized and reliable method for identity verification without compromising user privacy, and could be useful in various scenarios, including e-commerce, financial transactions, and secure communication.

    By providing a secure method for linking a user's public key to their true identity, the standard would enable secure and private online transactions and collaborations, while also protecting against fraudulent activities and identity theft. By recognizing that key compromises do occur and supporting certificate revocation, we allow users to recover from breaches without tying their entire digital identity to a single key.

    Specification

    We start by specifying the data structures needed to represent various components of identity certificates, then proceed to key derivation schemes, signing and verification procedures, the secure verifier field revelation protocol, and finally UTXO-based revocation and responsible key compromise handling procedures.

    Data Structures

    PublicKey

    The PublicKey structure is a compressed, DER-encoded secp256k1 public key (only the X coordinate), formatted as a 33-byte hexadecimal string.

    Example:

    02e087b19a205ae13f512341d1cfc0c712d66cacad24a809fce7edb3529e78b5da

    Nonce

    The Nonce structure is a 256-bit number, converted to a base64 string.

    Example:

    L9t1aQLkWkmMw1Poi1ofIjHV6GO+BNN63v8Na8/gW4Y=

    Signature

    The Signature structure is a DER-encoded ECDSA signature converted into a hexadecimal string.

    Example

    3045022100c0686907d8914abfa7f356c560c7d17045dde5c10135b1cbf9bf6e4cc52e09820220366eec15372bc34db10f997e21755f603a2023c96578e9d71fca2570f23055d6

    RevocationOutpoint

    The Outpoint structure is a Bitcoin SV TXID (a hexadecimal string) and output index (a decimal integer), separated by a decimal point (“.”). When a certificate outpoint has been spent, the certificate has been revoked.

    Example

    48645047cd66f7b48b24efb080ec7e27f3f448c21109939b80afd11e40898c92.1

    CertificateTypeID

    The CertificateTypeID structure is a 256-bit number that represents the distinct type or class of certificate issued by the certifier, converted to a base64 string. All certificate types with the same unique Type ID can be expected to have the same fields, and fields can be expected to have the same meanings.

    Example

    8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=

    CertificateValidationKey

    The CertificateValidationKey structure is a 256-bit key converted to a base64 string. The key is used by verifiers to check the signature on the certificate.

    Example

    G4pBfpBEZ7n5iEHrtG5MFOnIO0U1D758naHJilcK/RU=/7lzk4XTKI=+BNN63v8Na8/gW4Y=

    CertificateSerialNumber

    The CertificateSerialNumber structure is a 128-bit number that represents the unique identifier of the certificate, converted to a base64 string. No two certificates should have the same serial number, especially certificates from the same certifier or of the same type.

    Example

    kUahacBHmYL2nkzemkatFg==

    CertificateFieldValue

    The CertificateFieldValue structure is a piece of certified information that is encrypted with one of the CertificateFieldRevelationKeys. The 256-bit initialization vector used is prepended to the beginning of the data, and the AES-256-GCM algorithm is used. The structure is represented as a base64 string.

    Example

    IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp

    CertificateFieldRevelationKey

    The CertificateFieldRevelationKey structure is a 256-bit AES-GCM encryption key used to decrypt and reveal one of the CertificateFieldValues. It is represented as a base64 string.

    Example

    ZG3C7x11lIeqd5Fi9BDzeTXMEAIlh+uDOB53d03EV5s=

    CertificateFields

    The CertificateFields structure is an object whose keys are certificate field names, and whose values are CertificateFieldValue structures.

    Example

    CertificateFieldRevelationKeyring

    The CertificateFieldRevelationKeyring structure is an object whose keys are certificate field names and whose values are encrypted versions of the corresponding CertificateFieldRevelationKeys that decrypt them.

    When a sender is communicating with a counterparty over a communications channel, the sender encrypts the field revelation keys by following the BRC-2 Encryption process (each CertificateFieldRevelationKey is encrypted with AES-256-GCM, and the 256-bit initialization vector is prepended to the ciphertext).

    For each field revelation key that is included, the sender and recipient of the information use the following BRC-43 protocol and key IDs:

    Attribute

    Value

    Security Level

    2

    Protocol ID

    authrite certificate field encryption xxxxx

    Key ID

    yyyyy zzzzz

    Counterparty

    The sender uses the recipient's identity key, the recipient uses the sender's identity key.

    Where:

    • xxxxx is the certificate type ID

    • yyyyy is the certificate Serial Number

    • zzzzz is the field name which the CertificateFieldRevelationKey decrypts

    NOTE: The bearer of a certificate is not obligated to reveal the keys to all certificate fields at all times to all parties. Therefore, a Certificate structure that contains an incomplete CertificateFieldRevelationKeyring (lacking keys for certain fields) can still be considered valid. It is up to the verifier how much information they need to examine.

    Example

    Certificate

    The Certificate structure is an object with the following JSON fields:

    Field
    Description

    type

    A CertificateTypeID structure indicating the type of certificate.

    subject

    A PublicKey structure denoting the key belonging to the party being certified.

    validationKey

    A CertificateValidationKey structure representing the validation key of the certificate.

    serialNumber

    A CertificateSerialNumber structure representing the unique serial number of the certificate.

    fields

    A CertificateFields structure containing all of the encrypted fields that were certified by the certifier.

    Example

    Signing and Verification

    The signature for a certificate is over all the fields, the subject, the certifier, the type, the serial number, the revocation outpoint, and the validation key. Each field is organized deterministically, in alphabetical order, in a JSON object. We stipulate the use of the (default) Stable Stringify Algorithm to avoid ambiguous ordering.

    When the certificate is signed, we specify that the certifier utilizes the BRC-3 signing process with their certifier private key and the following BRC-43 attributes:

    Attribute

    Value

    Security Level

    2

    Protocol ID

    authrite certificate signature xxxxx

    Key ID

    yyyyy

    Counterparty

    The public key of the validation key included in the certificate.

    Where:

    • xxxxx is the certificate type ID

    • yyyyy is the certificate Serial Number

    NOTE: The validation key is part of the certificate, so anyone with this key can check the certificate signature.

    For signature verification, we specify that the verifier checks the BRC-3 signature by using the certificate's validation key as the BRC-42 identity private key and the certifier's identity public key as the counterparty.

    Revelation Key Generation

    The subject (the person being certified) may use this key derivation scheme to derive the field revelation keys used to encrypt the various fields of their certificate, based on their own identity private key.

    Attribute

    Value

    Security Level

    2

    Protocol ID

    authrite certificate field xxxxx

    Key ID

    yyyyy zzzzz

    Counterparty

    self

    Where:

    • xxxxx is the certificate type ID

    • yyyyy is the certificate Serial Number

    • zzzzz is the field name from the certificate

    Secure Verifier Field Revelation Protocol

    In order to preserve data integrity, we need a way to keep certificate fields encrypted such that only particular fields can be revealed as needed. We stipulate the use of a keyring structure for selective field revelation to verifiers. As the keyring is not included in the certificate's signature (only the encrypted field values themselves), verifiers can still check the authenticity of the certificate without access to all keyring keys.

    When a prover reveals the fields to a verifier, they will follow these steps:

    1. Retrieve the relevant symmetric field encryption keys

    2. Encrypt the keys for the verifier following the BRC-2 process for counterparty encryption.

    3. Construct the keyring with the field revelation keys and their associated field names according to the structure defined above.

    For step 2, we stipulate the use of the following BRC-43 attributes when deriving the encryption keys:

    Attribute

    Value

    Security Level

    2

    Protocol ID

    authrite certificate field encryption

    Key ID

    xxxxx yyyyy

    Counterparty

    self

    Where:

    • xxxxx is the certificate Serial Number

    • yyyyy is the field name from the certificate

    It is strictly forbidden for a verifier to store or reveal the field revelation keys or the field values themselves to anyone else without the consent of the certificate holder. Doing so would be a violation of the terms of agreement and would result in the revocation of the certificate for that verifier.

    UTXO-based Certificate Revocation

    One of the problems with identity certificates of the past is that certificate authorities would have to maintain a list of any certificates that were revoked due to key compromises, violation of the terms of agreements, or other reasons. Then anyone that wanted to check if a certificate was still valid would have to check against this list, assuming it wasn't compromised, to make sure it hadn't been revoked.

    A simple solution to this problem is to make use of an associated Bitcoin transaction and output created at the time the certificate is issued. As described above, this revocation outpoint structure points to a UTXO that, if ever spent, indicates that the certificate is revoked.

    This allows verifiers to easily check if a certificate has been revoked, without having to rely on a trusted centralized revocation list.

    Handling Key Compromises Responsibly

    If the private key corresponding to a certificate issuer's public key ever becomes compromised, it is important that the issuer generate a new key pair, revoke existing certificates, and issue new certificates to the relevant certificate holders.

    If one of the certificate holders has a key compromised, there needs to be a standard way to request a new certificate.

    Certifiers should establish a process for coordinating with certificate holders to manage the reissuance of certificates.

    Future BRCs can define protocols by which this process can occur.

    Implementations

    An example implementation of Identity Certificates can be seen in Authrite, and the MYAC tutorial can be followed for creating your own Authrite Certifier.

    BSV Unified Merkle Path (BUMP) Format

    Darren Kellenschwiler ([email protected]), Deggen Tone Engel ([email protected]), TonesNotes Ty Everett ([email protected]) Damian Orzepowski ([email protected]) Arkadiusz Osowski ([email protected])

    Abstract

    We propose the BSV Unified Merkle Path format in both binary and JSON encoding optimized for generation by transaction processors, and also happens to be convenient for proof validating clients.

    At a high level the format encodes a number of txids which all exist within one particular block, along with each of their merkle paths and the blockHeight.

    The blockHeight is encoded first, followed by level 0 of the Merkle tree, which includes the txids of interest, and their corresponding siblings. Thereafter we encode each level of the tree thereafter, but only include branches of the tree which are required to calculate the Merkle root the txids which are of interest to us. For example if we only have one txid of interest, we will include it and its sibling, followed by one leaf per level of the tree.

    {
      “first_name”: “IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp”,
      “last_name”: “3o0jTew8WMW54svE8Btx9Aks1FlQCHOxGKLZpc7SR0ESSIomToAYFtCq6U7NUuf3ktwLgnv5XdCrCTo+mOTHl/H+oyjcxB7xfdwav+bBx6vG5y9voDI/Z2MQGxE/Pmeg”,
      “address_line_1”: “WGqZGJo7VHeQ5tx7uqeyA5q08tRVxJLUoprjAiJ8FmzOoe4gt0+6PGDgvrhkbzauSxGY9yRyOeP+irHclCIrzjwjbfkK19thoyUhr8u1283FobikPs2xKrhUvcYhDOV7”,
      “address_line_2”: “IjI5UXJnMbcSEqIVkH8B5a9cY8EtWO7RvJH9gAWuIq0Y3koINgfqNjmockAgXnGxLvdQXvWdlCIm+foedIdHhqs9Xi60wR7hLSs9emjo6nq1Mx01wYFRW1le//Sup80x”,
      “city”: “Ed4Nr8UL3h7AqX3PlExwLQ0Mi/QLBH9wCIpdeMb442HDbQlodF1eUuJQRXt+0ajzmXEqaGNSD59xEXmsFouLDLa6sOOzXr2psCKMXkU1+IFHGv8TgJx/vDTCxMvL7t2T”,
      “state”: “6oiC8AMFFrLRGhpbWUO1HkA05/QPmfaUg1be4cP2vbcadIv4quaBgfwmNWE6xItpQNAfEwrx1ub9b4cNIKnN+6JAsiDiqs42mbjsgTuZL90fSEL9yPTwRuvW1ccvJ43z”,
      “zipcode”: “Y+iqr8cSMEMMq8WqpIudzni1DIiQT5BsK29ld8lFCZddrrjep0qQyKoaP9+46ikIu9VOQIoOJayhiW7KifUSYt+D/WODyPei4Ru7tqfgR47Vo4u0EFI3KLBXyC3DgiN+”
    }
    {
      “first_name”: “G2GmxIWNPkO2SUP0XpQvQqX31yz58aLHk9e7JxO+q/MT3k9ZjTe3t8aN2Qwg2+AtBulXZpKhuvxOgxicfd8GqCjFkGtyUrbSdmCFjPUJm7z/P/LWkJHByeBzh3/yOWa7”,
      “last_name”: “YZAHgs+P8Tgci3+5uuAuHr0k3CXPEcB3trpqtEUygV+uwoTgDWk01XTT1eOW6n7qjcDt4g7tlzuWtkawDkvRbCcVe3oBsEI5X8+A10s8TAsyNQV5O1R8mkGoL8/Hec4K”
    }
    {
      “type”: ”8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=”,
      “subject”: ”0376d67c86b45be3c36c328c2aa5c5dd79c546d22859e39439bd5d934058345abc”,
      “validationKey”: ”G4pBfpBEZ7n5iEHrtG5MFOnIO0U1D758naHJilcK/RU=/7lzk4XTKI=+BNN63v8Na8/gW4Y=”,
      “serialNumber”: ”kUahacBHmYL2nkzemkatFg==”,
      “fields”: {
        “first_name”: “IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp”,
        “last_name”: “3o0jTew8WMW54svE8Btx9Aks1FlQCHOxGKLZpc7SR0ESSIomToAYFtCq6U7NUuf3ktwLgnv5XdCrCTo+mOTHl/H+oyjcxB7xfdwav+bBx6vG5y9voDI/Z2MQGxE/Pmeg”,
        “address_line_1”: “WGqZGJo7VHeQ5tx7uqeyA5q08tRVxJLUoprjAiJ8FmzOoe4gt0+6PGDgvrhkbzauSxGY9yRyOeP+irHclCIrzjwjbfkK19thoyUhr8u1283FobikPs2xKrhUvcYhDOV7”,
        “address_line_2”: “IjI5UXJnMbcSEqIVkH8B5a9cY8EtWO7RvJH9gAWuIq0Y3koINgfqNjmockAgXnGxLvdQXvWdlCIm+foedIdHhqs9Xi60wR7hLSs9emjo6nq1Mx01wYFRW1le//Sup80x”,
        “city”: “Ed4Nr8UL3h7AqX3PlExwLQ0Mi/QLBH9wCIpdeMb442HDbQlodF1eUuJQRXt+0ajzmXEqaGNSD59xEXmsFouLDLa6sOOzXr2psCKMXkU1+IFHGv8TgJx/vDTCxMvL7t2T”,
        “state”: “6oiC8AMFFrLRGhpbWUO1HkA05/QPmfaUg1be4cP2vbcadIv4quaBgfwmNWE6xItpQNAfEwrx1ub9b4cNIKnN+6JAsiDiqs42mbjsgTuZL90fSEL9yPTwRuvW1ccvJ43z”,
        “zipcode”: “Y+iqr8cSMEMMq8WqpIudzni1DIiQT5BsK29ld8lFCZddrrjep0qQyKoaP9+46ikIu9VOQIoOJayhiW7KifUSYt+D/WODyPei4Ru7tqfgR47Vo4u0EFI3KLBXyC3DgiN+”
      },
      “certifier”: ”035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
      “revocationOutpoint”: “48645047cd66f7b48b24efb080ec7e27f3f448c21109939b80afd11e40898c92.1”,
      “signature”: “3045022100c0686907d8914abfa7f356c560c7d17045dde5c10135b1cbf9bf6e4cc52e09820220366eec15372bc34db10f997e21755f603a2023c96578e9d71fca2570f23055d6”,
      “keyring”: {
        “first_name”: “G2GmxIWNPkO2SUP0XpQvQqX31yz58aLHk9e7JxO+q/MT3k9ZjTe3t8aN2Qwg2+AtBulXZpKhuvxOgxicfd8GqCjFkGtyUrbSdmCFjPUJm7z/P/LWkJHByeBzh3/yOWa7”,
        “last_name”: “YZAHgs+P8Tgci3+5uuAuHr0k3CXPEcB3trpqtEUygV+uwoTgDWk01XTT1eOW6n7qjcDt4g7tlzuWtkawDkvRbCcVe3oBsEI5X8+A10s8TAsyNQV5O1R8mkGoL8/Hec4K”
      }
    }

    certifier

    A PublicKey structure denoting the well-known public key of the entity issuing the certificate.

    revocationOutpoint

    A RevocationOutpoint structure pointing to a Bitcoin SV UTXO. If the UTXO has been spent by the certifier, the certificate should be considered revoked. If all zeroes, this functionality is disabled for the certificate. Disabling UTXO-based revocation should be in accordance with the rules defining this certificate type.

    signature

    A Signature structure denoting the signature made by the certifying entity over the certified fields of the subject.

    keyring

    A CertificateRevelationKeyring structure containing keys for some or all of the fields of the certificate. If no fields are being revealed, this is optional.

    BRC-43
    BRC-43
    BRC-43
    BRC-43

    Copyright

    This BRC is licensed under the Open BSV license.

    Visualization

    BUMP Showcase can help form an understanding of how BUMP works to encode all necessary data.

    Motivation

    Several formats have made their own improvements to the original format which was returned by a Bitcoin node via json-rpc method getmerkleproof.

    Improvements include:

    • BRC-10 a TSC creation which was subsequently returned by the node's json-rpc method getmerkleproof2

    • BRC-11 removing the need for specifying targets, replacing with height to improve validation speed.

    • BRC-58 removal of all extraneous data to minimize data size.

    • introduction of a compound path encoding which allows representation of multiple paths within the same block.

    The purpose of defining this new specification is to capture the incremental improvements under one spec which encapsulates the pros of each, and removes the cons. This new spec should allow:

    • Inclusion of height makes lookup extremely fast while only adding maximum 9 bytes to the data size.

    • Multiple paths can be expressed in the same data model.

    • One format for everything, so that there is no need to convert from single to compound path.

    • Size optimization allowing us to skip encoding of far right leaves when duplication of working hash would suffice.

    Binary Encoding

    Global

    The top level encoding specifies a block height and a tree height.

    Field
    Description
    Size

    block height

    VarInt block height in which the transactions are encapsulated

    1-9 bytes

    tree height

    The height of the Merkle Tree in this block, max 64

    1 byte

    Level

    Thereafter the number of leaves at the top height is specified, and the leaves for this height follow.

    Field
    Description
    Size

    nLeaves

    VarInt number of leaves at this height

    1-9 bytes

    leaves

    Each leaf encoded in the format below.

    sum of leaf sizes

    Leaf

    Once all leaves at this height have been specified, an implied increment of the height in the tree occurs and we specify the number of leaves in the next level up, and so on until we have specified the leaves at level (treeHeight - 1) at which point we stop. We do not need to encode the root hash as it is always calculable.

    Field
    Description
    Size

    offset

    VarInt offset from left hand side within tree

    1-9 bytes

    flags

    Flags can be 00, or 01, or 02 - detailed meaning in table below

    1 byte

    hash

    A hash representing a txid, sibling hash, or a branch

    0 or 32 bytes

    Flags

    The first flag is to indicate whether or not to duplicate the working hash or use the following data. The second flag indicates whether the hash is a relevant txid or just a sibling hash.

    bits
    byte
    meaning

    0000 0000

    00

    data follows, not a client txid

    0000 0001

    01

    nothing follows, duplicate working hash

    0000 0010

    02

    data follows, and is a client txid

    Hex String

    Bytewise Breakdown

    JSON Encoding

    In the JSON encoding - we start with a height of a block in which transactions from BUMP are mined. A path Array index corresponds to the height within the Merkle tree, so we start with level 0 which includes all of the txid's of interest to a client in this block and the txid's of additional transactions required to begin the merkle root computation. Within each array element we contain an array of one or more leaves which are specified as a leaf.

    Within the leaf itself we have am offset - the only required parameter, along with optional hash, txid and duplicate. The hash is a hex string encoding reversed bytes of the hash at this position in the Merkle tree, the duplicate true is a boolean and represents a "no data" for this position, this is to encode for the right hand side of the merkle tree. The expected behavior is for a parser to duplicate the working hash in this case, therefore no further data is required. A txid boolean is included if true - to indicate whether the hash in question is considered a relevant txid to the receiving party, rather than just a sibling hash needed to calculate the root.

    JSON Example

    Calculating the Merkle Root from a BUMP

    Let's start by dumping this format as hex into a Buffer in JavaScript and parsing it into an object with a Buffer Reader. Then we can calculate the merkle root from any of the included txids.

    Merging

    A note on compounding multiple BUMPs together. The first check should always be the blockHeight - ensure it matches. The second check is the root. Each BUMP calculates its root, and if they don't match - you cannot combine them. If they match then the process is a simple inclusion of all leaves, dropping duplicates.

    Implementations

    TypeScript - ts-sdk Golang - go-sdk Python - py-sdk

    Authrite Mutual Authentication

    Ty Everett ([email protected])

    Abstract

    This specification defines Authrite, a system for the mutual authentication of two parties over a communications channel. It facilitates the exchange of identity certificates between users, allowing them to certify each other's identities and share identity information selectively. Authrite leverages the Identity Keys of MetaNet Users and relies on Permissions and Certificate management functions to allow Users to control how identity information is shared. This specification defines the nonce exchanges, certificate and field exchange negotiation protocol, and message signing scheme for two-party Authrite communications channels.

    fe8a6a0c000c04fde80b0011774f01d26412f0d16ea3f0447be0b5ebec67b0782e321a7a01cbdf7f734e30fde90b02004e53753e3fe4667073063a17987292cfdea278824e9888e52180581d7188d8fdea0b025e441996fc53f0191d649e68a200e752fb5f39e0d5617083408fa179ddc5c998fdeb0b0102fdf405000671394f72237d08a4277f4435e5b6edf7adc272f25effef27cdfe805ce71a81fdf50500262bccabec6c4af3ed00cc7a7414edea9c5efa92fb8623dd6160a001450a528201fdfb020101fd7c010093b3efca9b77ddec914f8effac691ecb54e2c81d0ab81cbc4c4b93befe418e8501bf01015e005881826eb6973c54003a02118fe270f03d46d02681c8bc71cd44c613e86302f8012e00e07a2bb8bb75e5accff266022e1e5e6e7b4d6d943a04faadcf2ab4a22f796ff30116008120cafa17309c0bb0e0ffce835286b3a2dcae48e4497ae2d2b7ced4f051507d010a00502e59ac92f46543c23006bff855d96f5e648043f0fb87a7a5949e6a9bebae430104001ccd9f8f64f4d0489b30cc815351cf425e0e78ad79a589350e4341ac165dbe45010301010000af8764ce7e1cc132ab5ed2229a005c87201c9a5ee15c0f91dd53eff31ab30cd4
    fe8a6a0c00 // blockHeight (813706), VarInt
    0c // treeHeight (12), byte
    // Level 0, client TXIDs and sibling TXIDs (TXIDs required only to compute internal tree hash).
    04 // nLeaves, VarInt
    fde80b // offset, VarInt
    00 // flags
    11774f01d26412f0d16ea3f0447be0b5ebec67b0782e321a7a01cbdf7f734e30 // hash
    fde90b // offset VarInt
    02 // flags = CLIENT_TXID
    004e53753e3fe4667073063a17987292cfdea278824e9888e52180581d7188d8 // hash
    fdea0b // offset VarInt
    02 // flags = CLIENT_TXID
    5e441996fc53f0191d649e68a200e752fb5f39e0d5617083408fa179ddc5c998 // hash
    fdeb0b // offset VarInt
    01 // flags = DUPLICATE_WORKING_HASH
    // Level 1, internal merkle tree hashes
    02 // nLeaves, VarInt
    fdf405 // offset, VarInt
    00 // flags
    0671394f72237d08a4277f4435e5b6edf7adc272f25effef27cdfe805ce71a81 // hash
    fdf505 // offset VarInt
    00 // flags
    262bccabec6c4af3ed00cc7a7414edea9c5efa92fb8623dd6160a001450a5282 // hash
    // Level 2, internal merkle tree hashes
    01 // nLeaves VarInt at level 2
    fdfb02 // offset VarInt
    01 // flags = DUPLICATE_WORKING_HASH
    // Level 3, internal merkle tree hashes
    01 // nLeaves VarInt at level 3
    fd7c01 // offset VarInt (three hundred and eighty)
    00 // flags
    93b3efca9b77ddec914f8effac691ecb54e2c81d0ab81cbc4c4b93befe418e85 // hash
    // Level 4, internal merkle tree hashes
    01 // nLeaves VarInt at level 4
    bf // offset VarInt
    01 // flags = DUPLICATE_WORKING_HASH
    // Level 5, internal merkle tree hashes
    01 // nLeaves VarInt at level 5
    5e // offset VarInt
    00 // flags
    5881826eb6973c54003a02118fe270f03d46d02681c8bc71cd44c613e86302f8 // hash
    // Level 6, internal merkle tree hashes
    01 // nLeaves VarInt at level 6
    2e // offset VarInt
    00 // flags
    e07a2bb8bb75e5accff266022e1e5e6e7b4d6d943a04faadcf2ab4a22f796ff3 // hash
    // Level 7, internal merkle tree hashes
    01 // nLeaves VarInt at level 7
    16 // offset VarInt
    00 // flags
    8120cafa17309c0bb0e0ffce835286b3a2dcae48e4497ae2d2b7ced4f051507d // hash
    // Level 8, internal merkle tree hashes
    01 // nLeaves VarInt at level 8
    0a // offset VarInt
    00 // flags
    502e59ac92f46543c23006bff855d96f5e648043f0fb87a7a5949e6a9bebae43 // hash
    // Level 9, internal merkle tree hashes
    01 // nLeaves VarInt at level 9
    04 // offset VarInt
    00 // flags
    1ccd9f8f64f4d0489b30cc815351cf425e0e78ad79a589350e4341ac165dbe45 // hash
    // Level 10, internal merkle tree hashes
    01 // nLeaves VarInt at level 10
    03 // offset VarInt
    01 // flags = DUPLICATE_WORKING_HASH
    // Level 11, internal merkle tree hashes
    01 // nLeaves VarInt at level 11
    00 // offset VarInt
    00 // flags
    af8764ce7e1cc132ab5ed2229a005c87201c9a5ee15c0f91dd53eff31ab30cd4 // hash
    {
      "blockHeight": 813706,
      "path": [
        [
          {
            "offset": 3048,
            "hash": "304e737fdfcb017a1a322e78b067ecebb5e07b44f0a36ed1f01264d2014f7711"
          },
          {
            "offset": 3049,
            "txid": true,
            "hash": "d888711d588021e588984e8278a2decf927298173a06737066e43f3e75534e00"
          },
          {
            "offset": 3050,
            "txid": true,
            "hash": "98c9c5dd79a18f40837061d5e0395ffb52e700a2689e641d19f053fc9619445e"
          },
          {
            "offset": 3051,
            "duplicate": true
          }
        ],
        [
          {
            "offset": 1524,
            "hash": "811ae75c80fecd27efff5ef272c2adf7edb6e535447f27a4087d23724f397106"
          },
          {
            "offset": 1525,
            "hash": "82520a4501a06061dd2386fb92fa5e9ceaed14747acc00edf34a6cecabcc2b26"
          }
        ],
        [
          {
            "offset": 763,
            "duplicate": true
          }
        ],
        [
          {
            "offset": 380,
            "hash": "858e41febe934b4cbc1cb80a1dc8e254cb1e69acff8e4f91ecdd779bcaefb393"
          }
        ],
        [
          {
            "offset": 191,
            "duplicate": true
          }
        ],
        [
          {
            "offset": 94,
            "hash": "f80263e813c644cd71bcc88126d0463df070e28f11023a00543c97b66e828158"
          }
        ],
        [
          {
            "offset": 46,
            "hash": "f36f792fa2b42acfadfa043a946d4d7b6e5e1e2e0266f2cface575bbb82b7ae0"
          }
        ],
        [
          {
            "offset": 22,
            "hash": "7d5051f0d4ceb7d2e27a49e448aedca2b3865283ceffe0b00b9c3017faca2081"
          }
        ],
        [
          {
            "offset": 10,
            "hash": "43aeeb9b6a9e94a5a787fbf04380645e6fd955f8bf0630c24365f492ac592e50"
          }
        ],
        [
          {
            "offset": 4,
            "hash": "45be5d16ac41430e3589a579ad780e5e42cf515381cc309b48d0f4648f9fcd1c"
          }
        ],
        [
          {
            "offset": 3,
            "duplicate": true
          }
        ],
        [
          {
            "offset": 0,
            "hash": "d40cb31af3ef53dd910f5ce15e9a1c20875c009a22d25eab32c11c7ece6487af"
          }
        ]
      ]
    }
    const { createHash } = require('crypto')
    const { Br, Bw } = require('bsv')
    
    // Displaying hashes as hex strings in reverse byte order is a matter of convention with respect to txids. 
    // The functions below handle the conversions such that when we "hash()" something, we are running sha256 - 
    // digesting the reverse bytes of a hex string, and returning the reverse bytes encoded as a hex string.
    const hexRevToBuf = (str) => Buffer.from(str, 'hex').reverse()
    const bufRevToHex = (buf) => Buffer.from(buf.toString('hex'), 'hex').reverse().toString('hex')
    const hash = (str) => bufRevToHex(createHash('sha256').update(createHash('sha256').update(hexRevToBuf(str)).digest()).digest())
    
    function bumpHexToJSON(str) {
      const reader = new Br()
      reader.buf = Buffer.from(str, 'hex')
      let blockHeight = reader.readVarIntNum()
      let treeHeight = parseInt(reader.read(1).toString('hex'), 16)
      let path = Array(treeHeight).fill(0).map(() => ([]))
      let flags, offset, nLeavesAtThisHeight
      for (let level = 0; level < treeHeight; level++) {
        nLeavesAtThisHeight = reader.readVarIntNum()
        while (nLeavesAtThisHeight) {
          offset = reader.readVarIntNum()
          flags = parseInt(reader.read(1).toString('hex'), 16)
          const leaf = { offset }
          if (flags & 1) {
            leaf.duplicate = true
          } else {
            if (flags & 2) leaf.txid = true
            leaf.hash = reader.read(32).reverse().toString('hex')
          }
          path[level].push(leaf)
          nLeavesAtThisHeight--
        }
        path[level].sort((a, b) => a.offset - b.offset)
      }
      return { blockHeight, path }
    }
    
    function bumpJSONtoHex({ blockHeight, path }) {
      const bw = new Bw()
      bw.writeVarIntNum(blockHeight)
      let treeHeight = path.length
      bw.writeUInt8(treeHeight)
      for (let level = 0; level < treeHeight; level++) {
        let nLeaves = Object.keys(path[level]).length
        bw.writeVarIntNum(nLeaves)
        for (const leaf of path[level]) {
          bw.writeVarIntNum(leaf.offset)
          let flags = 0
          if (!!leaf?.duplicate) flags |= 1
          if (!!leaf?.txid) flags |= 2
          bw.writeUInt8(flags)
          if ((flags & 1) === 0)
            bw.write(hexRevToBuf(leaf.hash))
        }
      }
      return bw.toBuffer().toString('hex')
    }
    
    function calculateMerkleRootFromBUMP(bump, txid) {
      // Find the index of the txid at the lowest level of the Merkle tree
      const index = bump.path[0].find(l => l.hash === txid).offset
      if (!index) throw Error(`The BUMP does not contain the txid: ${txid}`)
      // Calculate the root using the index as a way to determine which direction to concatenate.
      let workingHash = txid
      bump.path.map((leaves, height) => {
        const offset = index >> height ^ 1
        const leaf = leaves.find(l => l.offset === offset)
        if (!leaf) throw new Error(`We do not have a hash for this index at height: ${height}`)
        if (leaf.duplicate) {
          workingHash = hash(workingHash + workingHash)
        } else if (offset % 2) {
          workingHash = hash(leaf.hash + workingHash)
        } else {
          workingHash = hash(workingHash + leaf.hash)
        }
      })
      return workingHash
    }
    
    
    const bump = bumpHexToJSON('fe8a6a0c000c04fde80b0011774f01d26412f0d16ea3f0447be0b5ebec67b0782e321a7a01cbdf7f734e30fde90b02004e53753e3fe4667073063a17987292cfdea278824e9888e52180581d7188d8fdea0b025e441996fc53f0191d649e68a200e752fb5f39e0d5617083408fa179ddc5c998fdeb0b0102fdf405000671394f72237d08a4277f4435e5b6edf7adc272f25effef27cdfe805ce71a81fdf50500262bccabec6c4af3ed00cc7a7414edea9c5efa92fb8623dd6160a001450a528201fdfb020101fd7c010093b3efca9b77ddec914f8effac691ecb54e2c81d0ab81cbc4c4b93befe418e8501bf01015e005881826eb6973c54003a02118fe270f03d46d02681c8bc71cd44c613e86302f8012e00e07a2bb8bb75e5accff266022e1e5e6e7b4d6d943a04faadcf2ab4a22f796ff30116008120cafa17309c0bb0e0ffce835286b3a2dcae48e4497ae2d2b7ced4f051507d010a00502e59ac92f46543c23006bff855d96f5e648043f0fb87a7a5949e6a9bebae430104001ccd9f8f64f4d0489b30cc815351cf425e0e78ad79a589350e4341ac165dbe45010301010000af8764ce7e1cc132ab5ed2229a005c87201c9a5ee15c0f91dd53eff31ab30cd4')
    
    calculateMerkleRootFromBUMP(bump, '304e737fdfcb017a1a322e78b067ecebb5e07b44f0a36ed1f01264d2014f7711') // '57aab6e6fb1b697174ffb64e062c4728f2ffd33ddcfa02a43b64d8cd29b483b4'
    calculateMerkleRootFromBUMP(bump, 'd888711d588021e588984e8278a2decf927298173a06737066e43f3e75534e00') // '57aab6e6fb1b697174ffb64e062c4728f2ffd33ddcfa02a43b64d8cd29b483b4'
    calculateMerkleRootFromBUMP(bump, '98c9c5dd79a18f40837061d5e0395ffb52e700a2689e641d19f053fc9619445e') // '57aab6e6fb1b697174ffb64e062c4728f2ffd33ddcfa02a43b64d8cd29b483b4'
    bumpJSONtoHex(bump)
    function combinePaths(one, two) {
      if (one.blockHeight !== two.blockHeight) 
        throw Error('You cannot combine paths which do not have the same blockHeight.')
      const txid1 = one.path[0].find(leaf => !!leaf?.hash).hash
      const root1 = calculateMerkleRootFromBUMP(one, txid1)
      const txid2 = two.path[0].find(leaf => !!leaf?.hash).hash
      const root2 = calculateMerkleRootFromBUMP(two, txid2)
      if (root1 !== root2) 
        throw Error('You cannot combine paths which do not have the same root.')
      const combinedPath = []
      for (let h = 0; h < one.path.length; h++) {
        combinedPath.push([])
        for (let l = 0; l < one.path[h].length; l++) {
          combinedPath[h].push(one.path[h][l])
        }
        for (let l = 0; l < two.path[h].length; l++) {
          if (!combinedPath[h].find(leaf => leaf.offset === two.path[h][l].offset)) {
            combinedPath[h].push(two.path[h][l])
          } else {
            // Ensure that any elements which appear in both are not downgraded to a non txid.
            if (!!two.path[h][l]?.txid) 
              combinedPath[h].find(leaf => leaf.offset === two.path[h][l]).txid = true
          }
        }
      }
      return { blockHeight: one.blockHeight, path: combinedPath }
    }
    BRC-61
    Motivation

    Identity on the internet relies heavily on trusted third parties to authenticate users. However, this centralization creates potential security and privacy risks, as third parties may collect and misuse user data. BRC-52 addresses this problem by introducing a privacy-centric version of digital identity certificates that facilitate selective revelation and UTXO-based revocation. This standard builds upon BRC-52 by providing a secure and efficient mechanism for exchanging identity information between users over an authenticated communications channel. By leveraging the Identity Keys of MetaNet Users, Authrite provides a decentralized approach to mutual authentication that reduces reliance on third parties and thereby enhances user privacy.

    Specification

    Authrite facilitates the exchange of identity information between two parties over a communications channel, allowing them to mutually authenticate each other. The following sections describe the requisite data structures, nonce exchanges, negotiation protocol, and message signing scheme for Authrite.

    High-level Overview

    When Alice initiates communication with Bob, she requests Bob's identity public key, and optionally, a list of certificate type IDs and certifiers she trusts. Bob responds with his identity public key, any certificates that Alice requested, and a list of certificate type IDs and certifiers he needs from Alice. To verify Bob's information, Alice validates his signature, checks that the certified key from all certificates matches his identity public key, and decrypts certificate fields with provided keys. If Alice has met Bob's certification requirements, she may send any messages of her choosing to Bob, including certificates he indicated he could trust. Bob verifies Alice's information and may respond with messages and certificates of his own. If at any point either party wants to re-scope the certificate inclusion in messages, they can initiate a new request for the other's identity public key.

    Data Structures

    We incorporate by reference all the data structures that were defined by BRC-52. Nonces, as well as some other necessary higher-level data structures are specified as follows:

    Nonce

    The Nonce structure is a 256-bit number, converted to a base64 string.

    Example

    RequestedCertificateCertifierList

    The RequestedCertificateCertifierList structure is an array of PublicKey structures, each denoting a certifier which the sending party will trust.

    Example

    RequestedCertificateTypeIDAndFieldList

    The RequestedCertificateTypeIDAndFieldList structure is an object whose keys are CertificateTypeID structures and whose values are each an array of field names from certificates of that type which the sending party requests to examine.

    Example

    RequestedCertificateSet

    The RequestedCertificateSet structure is an object with the following JSON fields:

    • certifiers — A RequestedCertificateCertifierList structure denoting the certifiers trusted by the sending party.

    • types — A RequestedCertificateTypeIDAndFieldList structure denoting the types of certificates trusted by the sending party, and which fields from each type the sending party would like to examine.

    Example

    CertificateList

    The CertificateList structure is an array comprising a list of Certificate structures, given in response to a RequestedCertificateSet structure.

    Example

    Negotiation Protocol

    Alice’s Initial Request

    When Alice starts an interaction with Bob, she sends a message with the following JSON fields:

    • authrite — The version of this specification to use (currently 0.1).

    • messageType — For Alice’s initial message, this should be initialRequest

    • identityKey — A PublicKey structure comprising the Identity Public Key belonging to Alice.

    • nonce — A Nonce structure which was randomly generated by Alice.

    • requestedCertificates — A RequestedCertificateSet structure indicating which certificates Bob should include in future messages, if he has them. If Alice does not require certificates from Bob, this is optional.

    NOTE that Alice cannot create a signature for this initial request, because she does not yet know Bob’s identity public key.

    Example

    Bob’s Initial Response

    When Bob receives the Initial Request message from Alice, he responds by sending a message with the following JSON fields:

    • authrite — The version of this specification to use (currently 0.1).

    • messageType — For Bob’s initial response this should be initialResponse

    • identityKey — A PublicKey structure comprising the Identity Public Key belonging to Bob.

    • nonce — A Nonce structure which was randomly generated by Bob.

    • certificates — A CertificateList structure created in response to Alice’s RequestedCertificateSet: Bob includes every certificate he has matching the CertificateTypeIDs Alice specified, as long as it was issued by one of Alice’s trusted certifiers. If Alice did not ask for any certificates, or if Bob does not have (or wish to provide) any of the certificates which Alice specified, this is optional.

    • requestedCertificates — A RequestedCertificateSet structure indicating which certificates Alice should include in her future messages, if she has them. If Bob does not require certificates from Alice, this is optional.

    • signature — A Signature structure created in accordance with the Message Signing section.

    Example

    Bob's Initial Message Signing

    Bob creates a BRC-3 digital signature for Alice with the following BRC-43 protocol and key IDs:

    Attribute

    Value

    Security Level

    2

    Protocol ID

    authrite message signature

    Key ID

    xxxxx yyyyy

    Counterparty

    Alice's public key.

    Where:

    • xxxxx is the nonce provided by Alice, and

    • yyyyy is the nonce provided by Bob.

    The data to be signed by Bob with this key is the nonce provided by Alice, concatenated with the nonce Bob is sending back.

    Bob's Initial Message Verification

    When Alice receives the initialResponse message type from Bob, she will verify the BRC-3 signature with the corresponding values, with Bob as counterparty.

    After checking that the signature is valid, Alice then checks that the subject of all the provided certificates is equal to Bob’s identity public key. She then moves on to checking the validity of the certificates themselves, as per BRC-52.

    General Messages

    After the initialRequest and initialResponse message types have been exchanged, either party can exchange general messages that include arbitrary signed payloads. These payloads constitute the authenticated communications channel defined by Authrite. The messages should generally have fields that convey the following information:

    • authrite — The version of this specification to use (currently 0.1).

    • identityKey — A PublicKey structure comprising the Identity Public Key belonging to the sender.

    • nonce — A Nonce structure which was randomly generated by the sender.

    • yourNonce — The Nonce structure which the recipient had originally provided as part of the initial request or initial response.

    • certificates — A CertificateList structure created in response to the counterparty’s RequestedCertificateSet: The sender includes every certificate they have matching the CertificateTypeIDs the counterparty specified, as long as it was issued by one of the counterparty’s trusted certifiers. If the counterparty did not ask for any certificates, or if the sender does not have any of the certificates which the counterparty had specified, this is optional.

    • payload — This is the data to be sent to the counterparty. It could be a JSON object, an image, or any other generalized data of any kind. Examples of different Authrite messages implemented in different contexts are given below.

    • signature — A Signature structure created in accordance with the Message Signing section.

    General Message Signing

    The sender creates a BRC-3 digital signature for the recipient with the following BRC-43 protocol and key IDs:

    Attribute

    Value

    Security Level

    2

    Protocol ID

    authrite message signature

    Key ID

    xxxxx yyyyy

    Counterparty

    The recipient's public key.

    Where:

    • xxxxx is the original nonce (from the initial request or initial response) provided by the counterparty, and

    • yyyyy is the nonce provided by the sender, which is specified as part of this message.

    The data to be signed by the sender with this key is the message payload.

    General Message Verification

    When the recipient receives the message from the sender, they will verify the BRC-3 signature with the corresponding values, with the sender as counterparty.

    After checking that the signature is valid, the recipient then checks that the subject of all the provided certificates is equal to the sender's identity public key. They then move on to checking the validity of the certificates themselves, as per BRC-52.

    The recipient should also ensure that the yourNonce value was originally generated by them if they rely on it during verification.

    JSON Message Example

    When JSON is used, a message payload can simply be added to an Authrite JSON object:

    HTTP Message Example

    When Authrite messages are sent over HTTP, X-Authrite-* headers can be added in addition to the normal headers. The signature is created over the data in the HTTP request or response body. If there is not a body to sign, the URL can be signed:

    Certificate Inclusion Re-scoping Procedures

    Certificate Inclusion Re-scoping is when one or both parties change the certificates and/or certificate fields that they are requesting the other party provide. This mechanism can also be used to add or remove certifiers from the list of trusted entities, causing old certificates to be removed or new ones to be added.

    For Alice to trigger this process, she simply sends a new initial request to Bob. This new request contains her updated RequestedCertificateSet, and Bob should reflect the update for any future communications.

    For Bob to trigger the process, he must return an error and ask Alice to send a new initial request. Bob replies with a JSON object like the following:

    Implementations

    The Authrite protocol has been implemented in JavaScript through the following two NPM packages:

    • Authrite-JS implements the client-side functionality

    • Authrite-Express implements the server-side functionality, for use on Express servers

    BRC-52
    BRC-42
    BRC-43
    BRC-53
    L9t1aQLkWkmMw1Poi1ofIjHV6GO+BNN63v8Na8/gW4Y=
    [
      “0295ddf37f406a1dcdf23a0418d5cdc824b4d092e165add14697ce1b8d31e4f3e8”,
      “035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
      “020940955c81c7052583b4bab9c87c81cca92ab7e84d360812a7cdf327d4143ca9”
    ]
    {
      “eHFASF5sUWTHV40NNKigyFFC57pSEnobe/7lzk4XTKI=+BNN63v8Na8/gW4Y=”: [
        “first_name”,
        “last_name”
      ],
      “4nst50RUw4WD1VberI0pJzGMAwX81ozrzvL9fMe7ZhE=”: [
        “firstName”,
        “middleInitial”,
        “lastName”
      ],
      “M4Al7B4C8rY4ajTODGCLl2i0OQlScgOagNg9xEtbud0=”: [
        “full_legal_name”
      ]
    }
    {
      “certifiers”: [
        “0295ddf37f406a1dcdf23a0418d5cdc824b4d092e165add14697ce1b8d31e4f3e8”,	
        “035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
        “020940955c81c7052583b4bab9c87c81cca92ab7e84d360812a7cdf327d4143ca9”
      ],
      “types”: {
        “eHFASF5sUWTHV40NNKigyFFC57pSEnobe/7lzk4XTKI=+BNN63v8Na8/gW4Y=”: [
          “first_name”,
          “last_name”
        ],
        “4nst50RUw4WD1VberI0pJzGMAwX81ozrzvL9fMe7ZhE=”: [
          “firstName”,
          “middleInitial”,
          “lastName”
        ],
        “M4Al7B4C8rY4ajTODGCLl2i0OQlScgOagNg9xEtbud0=”: [
          “full_legal_name”
        ]
      }
    }
    [{
      “type”: ”8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=”,
      “subject”: ”0376d67c86b45be3c36c328c2aa5c5dd79c546d22859e39439bd5d934058345abc”,
      “validationKey”: ”G4pBfpBEZ7n5iEHrtG5MFOnIO0U1D758naHJilcK/RU=/7lzk4XTKI=+BNN63v8Na8/gW4Y=”,
      “serialNumber”: ”kUahacBHmYL2nkzemkatFg==”,
      “fields”: {
        “first_name”: “IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp”,
        “last_name”: “3o0jTew8WMW54svE8Btx9Aks1FlQCHOxGKLZpc7SR0ESSIomToAYFtCq6U7NUuf3ktwLgnv5XdCrCTo+mOTHl/H+oyjcxB7xfdwav+bBx6vG5y9voDI/Z2MQGxE/Pmeg”,
        “address_line_1”: “WGqZGJo7VHeQ5tx7uqeyA5q08tRVxJLUoprjAiJ8FmzOoe4gt0+6PGDgvrhkbzauSxGY9yRyOeP+irHclCIrzjwjbfkK19thoyUhr8u1283FobikPs2xKrhUvcYhDOV7”,
        “address_line_2”: “IjI5UXJnMbcSEqIVkH8B5a9cY8EtWO7RvJH9gAWuIq0Y3koINgfqNjmockAgXnGxLvdQXvWdlCIm+foedIdHhqs9Xi60wR7hLSs9emjo6nq1Mx01wYFRW1le//Sup80x”,
        “city”: “Ed4Nr8UL3h7AqX3PlExwLQ0Mi/QLBH9wCIpdeMb442HDbQlodF1eUuJQRXt+0ajzmXEqaGNSD59xEXmsFouLDLa6sOOzXr2psCKMXkU1+IFHGv8TgJx/vDTCxMvL7t2T”,
        “state”: “6oiC8AMFFrLRGhpbWUO1HkA05/QPmfaUg1be4cP2vbcadIv4quaBgfwmNWE6xItpQNAfEwrx1ub9b4cNIKnN+6JAsiDiqs42mbjsgTuZL90fSEL9yPTwRuvW1ccvJ43z”,
        “zipcode”: “Y+iqr8cSMEMMq8WqpIudzni1DIiQT5BsK29ld8lFCZddrrjep0qQyKoaP9+46ikIu9VOQIoOJayhiW7KifUSYt+D/WODyPei4Ru7tqfgR47Vo4u0EFI3KLBXyC3DgiN+”
      },
      “certifier”: ”035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
      “revocationOutpoint”: “48645047cd66f7b48b24efb080ec7e27f3f448c21109939b80afd11e40898c92.1”,
      “signature”: “3045022100c0686907d8914abfa7f356c560c7d17045dde5c10135b1cbf9bf6e4cc52e09820220366eec15372bc34db10f997e21755f603a2023c96578e9d71fca2570f23055d6”,
      “keyring”: {
        “first_name”: “kulDaJWJmzDH/5/qYuEIaDyHrS/PbLCSXPGClC4gLc0=”,
        “last_name”: “26ymqbJl9gMxb00do+kOg950/aE5H+m/PyCgwEXBD/8=”
      }
    }]
    {
      “authrite”: “0.1”,
      “messageType”: “initialRequest”,
      “identityKey”: “02a08a4bbba07eadf350f2821a7ab6deaecda3a1c91d487576c80333e9f7a2a635”,
      “nonce”: “0LzpPd0hSjqzVWeW6yOwrms/GD/obTz7Skc/mMxsgg8=”,
      “requestedCertificates”: {
        “certifiers”: [
          “0295ddf37f406a1dcdf23a0418d5cdc824b4d092e165add14697ce1b8d31e4f3e8”,
          “035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
          “020940955c81c7052583b4bab9c87c81cca92ab7e84d360812a7cdf327d4143ca9”
        ],
        “types”: {
          “eHFASF5sUWTHV40NNKigyFFC57pSEnobe/7lzk4XTKI=+BNN63v8Na8/gW4Y=”: [
            “first_name”,
            “last_name”
          ],
          “4nst50RUw4WD1VberI0pJzGMAwX81ozrzvL9fMe7ZhE=”: [
            “firstName”,
            “middleInitial”,
            “lastName”
          ],
          “M4Al7B4C8rY4ajTODGCLl2i0OQlScgOagNg9xEtbud0=”: [
            “full_legal_name”
          ]
        }
      }
    }
    {
      “authrite”: “0.1”,
      “messageType”: “initialResponse”,
      “identityKey”: “0375454679f3b020c2a255d1cedde607339102704b8cebf11c63e1d7fe6a329327”,
      “nonce”: “Ej0uwfGivItPlY0TWbm554qLIidwmliSRe6xPXK0FH0=”,
      “certificates”: [{
        “type”: ”8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=”,
        “subject”: ”0376d67c86b45be3c36c328c2aa5c5dd79c546d22859e39439bd5d934058345abc”,
        “validationKey”: ”G4pBfpBEZ7n5iEHrtG5MFOnIO0U1D758naHJilcK/RU=/7lzk4XTKI=+BNN63v8Na8/gW4Y=”,
        “serialNumber”: ”kUahacBHmYL2nkzemkatFg==”,
        “fields”: {
          “first_name”: “IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp”,
          “last_name”: “3o0jTew8WMW54svE8Btx9Aks1FlQCHOxGKLZpc7SR0ESSIomToAYFtCq6U7NUuf3ktwLgnv5XdCrCTo+mOTHl/H+oyjcxB7xfdwav+bBx6vG5y9voDI/Z2MQGxE/Pmeg”,
          “address_line_1”: “WGqZGJo7VHeQ5tx7uqeyA5q08tRVxJLUoprjAiJ8FmzOoe4gt0+6PGDgvrhkbzauSxGY9yRyOeP+irHclCIrzjwjbfkK19thoyUhr8u1283FobikPs2xKrhUvcYhDOV7”,
          “address_line_2”: “IjI5UXJnMbcSEqIVkH8B5a9cY8EtWO7RvJH9gAWuIq0Y3koINgfqNjmockAgXnGxLvdQXvWdlCIm+foedIdHhqs9Xi60wR7hLSs9emjo6nq1Mx01wYFRW1le//Sup80x”,
          “city”: “Ed4Nr8UL3h7AqX3PlExwLQ0Mi/QLBH9wCIpdeMb442HDbQlodF1eUuJQRXt+0ajzmXEqaGNSD59xEXmsFouLDLa6sOOzXr2psCKMXkU1+IFHGv8TgJx/vDTCxMvL7t2T”,
          “state”: “6oiC8AMFFrLRGhpbWUO1HkA05/QPmfaUg1be4cP2vbcadIv4quaBgfwmNWE6xItpQNAfEwrx1ub9b4cNIKnN+6JAsiDiqs42mbjsgTuZL90fSEL9yPTwRuvW1ccvJ43z”,
          “zipcode”: “Y+iqr8cSMEMMq8WqpIudzni1DIiQT5BsK29ld8lFCZddrrjep0qQyKoaP9+46ikIu9VOQIoOJayhiW7KifUSYt+D/WODyPei4Ru7tqfgR47Vo4u0EFI3KLBXyC3DgiN+”
        },
        “certifier”: ”035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
        “revocationOutpoint”: “48645047cd66f7b48b24efb080ec7e27f3f448c21109939b80afd11e40898c92.1”,
        “signature”: “3045022100c0686907d8914abfa7f356c560c7d17045dde5c10135b1cbf9bf6e4cc52e09820220366eec15372bc34db10f997e21755f603a2023c96578e9d71fca2570f23055d6”,
        “keyring”: {
          “first_name”: “G2GmxIWNPkO2SUP0XpQvQqX31yz58aLHk9e7JxO+q/MT3k9ZjTe3t8aN2Qwg2+AtBulXZpKhuvxOgxicfd8GqCjFkGtyUrbSdmCFjPUJm7z/P/LWkJHByeBzh3/yOWa7”,
          “last_name”: “YZAHgs+P8Tgci3+5uuAuHr0k3CXPEcB3trpqtEUygV+uwoTgDWk01XTT1eOW6n7qjcDt4g7tlzuWtkawDkvRbCcVe3oBsEI5X8+A10s8TAsyNQV5O1R8mkGoL8/Hec4K”
        }
      }],
      “requestedCertificates”: {
        “certifiers”: [
          “0295ddf37f406a1dcdf23a0418d5cdc824b4d092e165add14697ce1b8d31e4f3e8”,
          “035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
          “020940955c81c7052583b4bab9c87c81cca92ab7e84d360812a7cdf327d4143ca9”
        ],
        “types”: {
          “eHFASF5sUWTHV40NNKigyFFC57pSEnobe/7lzk4XTKI=+BNN63v8Na8/gW4Y=”: [
            “first_name”,
            “last_name”
          ],
          “4nst50RUw4WD1VberI0pJzGMAwX81ozrzvL9fMe7ZhE=”: [
            “firstName”,
            “middleInitial”,
            “lastName”
          ],
          “M4Al7B4C8rY4ajTODGCLl2i0OQlScgOagNg9xEtbud0=”: [
            “full_legal_name”
          ]
        }
      },
      “signature”: “3045022100fc0946c97393ffd48b34a333a82a69343bed3d43b52932da62cb0e75cc07ca1602200822693d7fd2cb3cd54ebeb610bd1646eaea34cfb99109f393a3bf59ccc50231”
    }
    {
      “authrite”: “0.1”,
      “identityKey”: “0375454679f3b020c2a255d1cedde607339102704b8cebf11c63e1d7fe6a329327”,
      “nonce”: “Ej0uwfGivItPlY0TWbm554qLIidwmliSRe6xPXK0FH0=”,
      “yourNonce”: “VBEk9m0CFlgG/cCpRf0QWKErMGI1wNuHIoCpWSY8+50=”,
      “certificates”: [{
        “type”: ”8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=”,
        “subject”: ”0376d67c86b45be3c36c328c2aa5c5dd79c546d22859e39439bd5d934058345abc”,
        “validationKey”: ”G4pBfpBEZ7n5iEHrtG5MFOnIO0U1D758naHJilcK/RU=/7lzk4XTKI=+BNN63v8Na8/gW4Y=”,
        “serialNumber”: ”kUahacBHmYL2nkzemkatFg==”,
        “fields”: {
          “first_name”: “IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp”,
          “last_name”: “3o0jTew8WMW54svE8Btx9Aks1FlQCHOxGKLZpc7SR0ESSIomToAYFtCq6U7NUuf3ktwLgnv5XdCrCTo+mOTHl/H+oyjcxB7xfdwav+bBx6vG5y9voDI/Z2MQGxE/Pmeg”,
          “address_line_1”: “WGqZGJo7VHeQ5tx7uqeyA5q08tRVxJLUoprjAiJ8FmzOoe4gt0+6PGDgvrhkbzauSxGY9yRyOeP+irHclCIrzjwjbfkK19thoyUhr8u1283FobikPs2xKrhUvcYhDOV7”,
          “address_line_2”: “IjI5UXJnMbcSEqIVkH8B5a9cY8EtWO7RvJH9gAWuIq0Y3koINgfqNjmockAgXnGxLvdQXvWdlCIm+foedIdHhqs9Xi60wR7hLSs9emjo6nq1Mx01wYFRW1le//Sup80x”,
          “city”: “Ed4Nr8UL3h7AqX3PlExwLQ0Mi/QLBH9wCIpdeMb442HDbQlodF1eUuJQRXt+0ajzmXEqaGNSD59xEXmsFouLDLa6sOOzXr2psCKMXkU1+IFHGv8TgJx/vDTCxMvL7t2T”,
          “state”: “6oiC8AMFFrLRGhpbWUO1HkA05/QPmfaUg1be4cP2vbcadIv4quaBgfwmNWE6xItpQNAfEwrx1ub9b4cNIKnN+6JAsiDiqs42mbjsgTuZL90fSEL9yPTwRuvW1ccvJ43z”,
          “zipcode”: “Y+iqr8cSMEMMq8WqpIudzni1DIiQT5BsK29ld8lFCZddrrjep0qQyKoaP9+46ikIu9VOQIoOJayhiW7KifUSYt+D/WODyPei4Ru7tqfgR47Vo4u0EFI3KLBXyC3DgiN+”
        },
        “certifier”: ”035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
        “revocationOutpoint”: “48645047cd66f7b48b24efb080ec7e27f3f448c21109939b80afd11e40898c92.1”,
        “signature”: “3045022100c0686907d8914abfa7f356c560c7d17045dde5c10135b1cbf9bf6e4cc52e09820220366eec15372bc34db10f997e21755f603a2023c96578e9d71fca2570f23055d6”,
        “keyring”: {
          “first_name”: “G2GmxIWNPkO2SUP0XpQvQqX31yz58aLHk9e7JxO+q/MT3k9ZjTe3t8aN2Qwg2+AtBulXZpKhuvxOgxicfd8GqCjFkGtyUrbSdmCFjPUJm7z/P/LWkJHByeBzh3/yOWa7”,
          “last_name”: “YZAHgs+P8Tgci3+5uuAuHr0k3CXPEcB3trpqtEUygV+uwoTgDWk01XTT1eOW6n7qjcDt4g7tlzuWtkawDkvRbCcVe3oBsEI5X8+A10s8TAsyNQV5O1R8mkGoL8/Hec4K”
        }
      }],
      “payload”: {
        “hello”: “Authrite!”
      },
      “signature”: “3045022100fc0946c97393ffd48b34a333a82a69343bed3d43b52932da62cb0e75cc07ca1602200822693d7fd2cb3cd54ebeb610bd1646eaea34cfb99109f393a3bf59ccc50231”
    }
    Content-Type: video/mp4
    Content-Length: 140546213245
    X-Authrite: 0.1
    X-Authrite-Identity-Key: 0375454679f3b020c2a255d1cedde607339102704b8cebf11c63e1d7fe6a329327
    X-Authrite-Nonce: Ej0uwfGivItPlY0TWbm554qLIidwmliSRe6xPXK0FH0=
    X-Authrite-YourNonce: VBEk9m0CFlgG/cCpRf0QWKErMGI1wNuHIoCpWSY8+50=
    X-Authrite-Certificates: [{
        “type”: ”8l5phhdm2Hi80s6QqFOLS0NwUzDzJhlUTWv2BezmstE=”,
        “subject”: ”0376d67c86b45be3c36c328c2aa5c5dd79c546d22859e39439bd5d934058345abc”,
        “validationKey”: ”G4pBfpBEZ7n5iEHrtG5MFOnIO0U1D758naHJilcK/RU=/7lzk4XTKI=+BNN63v8Na8/gW4Y=”,
        “serialNumber”: ”kUahacBHmYL2nkzemkatFg==”,
        “fields”: {
          “first_name”: “IlgngMNcUM0d4GyzkSGqXaIBw6/n8bB6BG0pprO6oGhxUcivP6wDfuMWjWrG64KQJYUMN3QjHoX40r3SvAyWQaAA9ldVuPLgZwi9q2TCECKHCyEuiATCM9PdB/Ba2rxp”,
          “last_name”: “3o0jTew8WMW54svE8Btx9Aks1FlQCHOxGKLZpc7SR0ESSIomToAYFtCq6U7NUuf3ktwLgnv5XdCrCTo+mOTHl/H+oyjcxB7xfdwav+bBx6vG5y9voDI/Z2MQGxE/Pmeg”,
          “address_line_1”: “WGqZGJo7VHeQ5tx7uqeyA5q08tRVxJLUoprjAiJ8FmzOoe4gt0+6PGDgvrhkbzauSxGY9yRyOeP+irHclCIrzjwjbfkK19thoyUhr8u1283FobikPs2xKrhUvcYhDOV7”,
          “address_line_2”: “IjI5UXJnMbcSEqIVkH8B5a9cY8EtWO7RvJH9gAWuIq0Y3koINgfqNjmockAgXnGxLvdQXvWdlCIm+foedIdHhqs9Xi60wR7hLSs9emjo6nq1Mx01wYFRW1le//Sup80x”,
          “city”: “Ed4Nr8UL3h7AqX3PlExwLQ0Mi/QLBH9wCIpdeMb442HDbQlodF1eUuJQRXt+0ajzmXEqaGNSD59xEXmsFouLDLa6sOOzXr2psCKMXkU1+IFHGv8TgJx/vDTCxMvL7t2T”,
          “state”: “6oiC8AMFFrLRGhpbWUO1HkA05/QPmfaUg1be4cP2vbcadIv4quaBgfwmNWE6xItpQNAfEwrx1ub9b4cNIKnN+6JAsiDiqs42mbjsgTuZL90fSEL9yPTwRuvW1ccvJ43z”,
          “zipcode”: “Y+iqr8cSMEMMq8WqpIudzni1DIiQT5BsK29ld8lFCZddrrjep0qQyKoaP9+46ikIu9VOQIoOJayhiW7KifUSYt+D/WODyPei4Ru7tqfgR47Vo4u0EFI3KLBXyC3DgiN+”
        },
        “certifier”: ”035ce8cc44dbcf4c991d666d381d67263aed9123f9b15cca215b54f1314152d23c”,
        “revocationOutpoint”: “48645047cd66f7b48b24efb080ec7e27f3f448c21109939b80afd11e40898c92.1”,
        “signature”: “3045022100c0686907d8914abfa7f356c560c7d17045dde5c10135b1cbf9bf6e4cc52e09820220366eec15372bc34db10f997e21755f603a2023c96578e9d71fca2570f23055d6”,
        “keyring”: {
          “first_name”: “kulDaJWJmzDH/5/qYuEIaDyHrS/PbLCSXPGClC4gLc0=”,
          “last_name”: “26ymqbJl9gMxb00do+kOg950/aE5H+m/PyCgwEXBD/8=”
        }
      }]
    X-Authrite-Signature: 3045022100fc0946c97393ffd48b34a333a82a69343bed3d43b52932da62cb0e75cc07ca1602200822693d7fd2cb3cd54ebeb610bd1646eaea34cfb99109f393a3bf59ccc50231
    {
      “authrite”: “0.1”,
      “messageType”: “rescopingTrigger”,
      “message”: “Send a new initialRequest message to re-scope required certificates, fields and/or trusted certifiers.”
    }
    BRC-43
    BRC-43

    Bitcoin Script ASM Format

    Freddie Honohan ([email protected])

    Abstract

    This proposal introduces a standardised method of dealing with the ASM representation of Bitcoin Script across the ecosystem language libraries (Py-SDK, TS-SDK, Go-SDK, Teranode etc).

    Motivation

    The purpose of this proposal is to provide a generalised standard in order for deterministic translation of Bitcoin Script to and from ASM for cross-language compatibility.

    Currently, different implementations may produce inconsistent ASM representations for the same script. For example, the boolean value false might be rendered as OP_0, OP_FALSE depending on the library used. This lack of standardisation creates interoperability issues when scripts are shared across different tools and platforms.

    Specification

    1. It is important that ASM format scripts operate correctly regardless of where they were produced or processed.

    2. The Hexadecimal and Binary representations are defined in BRC-14.

    3. Since ASM format is primarily used for human-readability, op-codes with multiple representations like the boolean pair [OP_0, OP_1] are to be represented as their english full-name counterpart e.g. [OP_FALSE, OP_TRUE] Example:

    1. Other discrepancies were found and documented and rules are set out below to deal with them.

    Implementation

    1. The logic dealing with Bitcoin Script ASM is to be standardised across libraries and languages as described hereunder.

    2. Op-Codes with several names must be parsed into the correct hex/binary byte despite the chosen ASM format name. Example Input Parsing:

    1. However op-codes with several names must be output into the most human-readable format (e.g. OP_0 will always output as OP_FALSE). Example Output Serialization:

    1. Full Op-Code to Hex Table With Statuses

    Index
    Word
    Hex
    Legacy
    Chronicles

    References

    • : Bitcoin Script Binary and Hex Formats - Ty Everett ([email protected])

    OP_PUSHDATA1

    0x4c

    ✅

    ✅

    77

    OP_PUSHDATA2

    0x4d

    ✅

    ✅

    78

    OP_PUSHDATA4

    0x4e

    ✅

    ✅

    79

    OP_1NEGATE

    0x4f

    ✅

    ✅

    80

    OP_RESERVED

    0x50

    Reserved

    Reserved

    81

    OP_TRUE

    0x51

    ✅

    ✅

    82

    OP_2

    0x52

    ✅

    ✅

    83

    OP_3

    0x53

    ✅

    ✅

    84

    OP_4

    0x54

    ✅

    ✅

    85

    OP_5

    0x55

    ✅

    ✅

    86

    OP_6

    0x56

    ✅

    ✅

    87

    OP_7

    0x57

    ✅

    ✅

    88

    OP_8

    0x58

    ✅

    ✅

    89

    OP_9

    0x59

    ✅

    ✅

    90

    OP_10

    0x5a

    ✅

    ✅

    91

    OP_11

    0x5b

    ✅

    ✅

    92

    OP_12

    0x5c

    ✅

    ✅

    93

    OP_13

    0x5d

    ✅

    ✅

    94

    OP_14

    0x5e

    ✅

    ✅

    95

    OP_15

    0x5f

    ✅

    ✅

    96

    OP_16

    0x60

    ✅

    ✅

    97

    OP_NOP

    0x61

    ✅

    ✅

    98

    OP_VER

    0x62

    ❌

    ✅

    99

    OP_IF

    0x63

    ✅

    ✅

    100

    OP_NOTIF

    0x64

    ✅

    ✅

    101

    OP_VERIF

    0x65

    ❌

    ✅

    102

    OP_VERNOTIF

    0x66

    ❌

    ✅

    103

    OP_ELSE

    0x67

    ✅

    ✅

    104

    OP_ENDIF

    0x68

    ✅

    ✅

    105

    OP_VERIFY

    0x69

    ✅

    ✅

    106

    OP_RETURN

    0x6a

    ✅

    ✅

    107

    OP_TOALTSTACK

    0x6b

    ✅

    ✅

    108

    OP_FROMALTSTACK

    0x6c

    ✅

    ✅

    109

    OP_2DROP

    0x6d

    ✅

    ✅

    110

    OP_2DUP

    0x6e

    ✅

    ✅

    111

    OP_3DUP

    0x6f

    ✅

    ✅

    112

    OP_2OVER

    0x70

    ✅

    ✅

    113

    OP_2ROT

    0x71

    ✅

    ✅

    114

    OP_2SWAP

    0x72

    ✅

    ✅

    115

    OP_IFDUP

    0x73

    ✅

    ✅

    116

    OP_DEPTH

    0x74

    ✅

    ✅

    117

    OP_DROP

    0x75

    ✅

    ✅

    118

    OP_DUP

    0x76

    ✅

    ✅

    119

    OP_NIP

    0x77

    ✅

    ✅

    120

    OP_OVER

    0x78

    ✅

    ✅

    121

    OP_PICK

    0x79

    ✅

    ✅

    122

    OP_ROLL

    0x7a

    ✅

    ✅

    123

    OP_ROT

    0x7b

    ✅

    ✅

    124

    OP_SWAP

    0x7c

    ✅

    ✅

    125

    OP_TUCK

    0x7d

    ✅

    ✅

    126

    OP_CAT

    0x7e

    ✅

    ✅

    127

    OP_SPLIT

    0x7f

    ✅

    ✅

    128

    OP_NUM2BIN

    0x80

    ✅

    ✅

    129

    OP_BIN2NUM

    0x81

    ✅

    ✅

    130

    OP_SIZE

    0x82

    ✅

    ✅

    131

    OP_INVERT

    0x83

    ✅

    ✅

    132

    OP_AND

    0x84

    ✅

    ✅

    133

    OP_OR

    0x85

    ✅

    ✅

    134

    OP_XOR

    0x86

    ✅

    ✅

    135

    OP_EQUAL

    0x87

    ✅

    ✅

    136

    OP_EQUALVERIFY

    0x88

    ✅

    ✅

    137

    OP_RESERVED1

    0x89

    Reserved

    Reserved

    138

    OP_RESERVED2

    0x8a

    Reserved

    Reserved

    139

    OP_1ADD

    0x8b

    ✅

    ✅

    140

    OP_1SUB

    0x8c

    ✅

    ✅

    141

    OP_2MUL

    0x8d

    ❌

    ✅

    142

    OP_2DIV

    0x8e

    ❌

    ✅

    143

    OP_NEGATE

    0x8f

    ✅

    ✅

    144

    OP_ABS

    0x90

    ✅

    ✅

    145

    OP_NOT

    0x91

    ✅

    ✅

    146

    OP_0NOTEQUAL

    0x92

    ✅

    ✅

    147

    OP_ADD

    0x93

    ✅

    ✅

    148

    OP_SUB

    0x94

    ✅

    ✅

    149

    OP_MUL

    0x95

    ✅

    ✅

    150

    OP_DIV

    0x96

    ✅

    ✅

    151

    OP_MOD

    0x97

    ✅

    ✅

    152

    OP_LSHIFT

    0x98

    ✅

    ✅

    153

    OP_RSHIFT

    0x99

    ✅

    ✅

    154

    OP_BOOLAND

    0x9a

    ✅

    ✅

    155

    OP_BOOLOR

    0x9b

    ✅

    ✅

    156

    OP_NUMEQUAL

    0x9c

    ✅

    ✅

    157

    OP_NUMEQUALVERIFY

    0x9d

    ✅

    ✅

    158

    OP_NUMNOTEQUAL

    0x9e

    ✅

    ✅

    159

    OP_LESSTHAN

    0x9f

    ✅

    ✅

    160

    OP_GREATERTHAN

    0xa0

    ✅

    ✅

    161

    OP_LESSTHANOREQUAL

    0xa1

    ✅

    ✅

    162

    OP_GREATERTHANOREQUAL

    0xa2

    ✅

    ✅

    163

    OP_MIN

    0xa3

    ✅

    ✅

    164

    OP_MAX

    0xa4

    ✅

    ✅

    165

    OP_WITHIN

    0xa5

    ✅

    ✅

    166

    OP_RIPEMD160

    0xa6

    ✅

    ✅

    167

    OP_SHA1

    0xa7

    ✅

    ✅

    168

    OP_SHA256

    0xa8

    ✅

    ✅

    169

    OP_HASH160

    0xa9

    ✅

    ✅

    170

    OP_HASH256

    0xaa

    ✅

    ✅

    171

    OP_CODESEPARATOR

    0xab

    ✅

    ✅

    172

    OP_CHECKSIG

    0xac

    ✅

    ✅

    173

    OP_CHECKSIGVERIFY

    0xad

    ✅

    ✅

    174

    OP_CHECKMULTISIG

    0xae

    ✅

    ✅

    175

    OP_CHECKMULTISIGVERIFY

    0xaf

    ✅

    ✅

    176

    OP_NOP1

    0xb0

    ✅

    ✅

    177

    OP_NOP2

    0xb1

    ✅

    ✅

    178

    OP_NOP3

    0xb2

    ✅

    ✅

    179

    OP_SUBSTR

    0xb3

    ❌

    ✅

    180

    OP_LEFT

    0xb4

    ❌

    ✅

    181

    OP_RIGHT

    0xb5

    ❌

    ✅

    182

    OP_NOP4

    0xb6

    ✅

    ✅

    183

    OP_NOP5

    0xb7

    ✅

    ✅

    184

    OP_NOP6

    0xb8

    ✅

    ✅

    185

    OP_NOP7

    0xb9

    ✅

    ✅

    186

    OP_NOP8

    0xba

    ✅

    ✅

    187

    OP_NOP9

    0xbb

    ✅

    ✅

    188

    OP_NOP10

    0xbc

    ✅

    ✅

    253

    OP_PUBKEYHASH

    0xfd

    Pseudo

    Pseudo

    254

    OP_PUBKEY

    0xfe

    Pseudo

    Pseudo

    255

    OP_INVALIDOPCODE

    0xff

    Invalid

    Invalid

    0

    OP_FALSE

    0x00

    ✅

    ✅

    1-75

    OP_PUSHDATA

    0x01-0x4b

    ✅

    ✅

    here
    BRC-14

    76

       Hex:  0x00 0x51
       ASM:  OP_FALSE OP_TRUE
       Not:  OP_0 OP_1
       // All of these should parse to 0x00
       parseASM("OP_0")      // ✓ valid
       parseASM("OP_FALSE")  // ✓ valid
       
       // Both should output the same hex
       parseASM("OP_0") === parseASM("OP_FALSE")  // true
       // Input hex, always outputs human-readable form
       toASM(0x00)  // "OP_FALSE" (not "OP_0")
       toASM(0x51)  // "OP_TRUE"  (not "OP_1")

    PCW-1 : Peer Cash Wallet Protocol

    This file contains the full specification from the Substack article by Dr. Craig S Wright, including abstract, sections 1-17, and state machine diagram description.

    The PCW-1 specification was designed and architected by Dr. Craig S. Wright and the protocol was engineered and implemented by Dr. Roy Murphy. The reference protocol implementation is located here.

    Abstract

    This work specifies a Bitcoin wallet workflow that conducts direct IP-to-IP negotiation between two identified parties and settles a payment as many independent on-chain transactions (“notes”). Identity keys are used only for ECDH and message authentication; they never appear on-chain. For each invoice and note index, a shared secret and an invoice fingerprint deterministically derive a unique recipient public key, ensuring unlinkability outside the two parties. The payer splits the total into bounded denominations agreed with the recipient and constructs one standard P2PKH transaction per note. Each transaction is funded with a disjoint input set and (if required) returns change to a per-note sender address derived deterministically so that change never overlaps across notes. Either party may submit any subset of fully signed transactions at any time; settlement is established by confirmation depth. The paper formalises notation, message frames, per-note key derivation, deterministic bounded splitting, disjoint coin-selection and change algorithms, ordering and pacing of broadcasts, selective-disclosure receipts, reissue rules prior to broadcast, and behaviours under reorgs. The result is a practical, auditable, and privacy-preserving method to enforce recipient constraints while keeping every note an independent on-chain payment.

    Bitcoin IP-to-IP Note Settlement: Purpose, Rationale, and Implementation

    1. What is it.

    A payment is settled as a set of small, standard on-chain transactions (“notes”), each paying a bounded amount to a unique address that only the recipient can spend. Bounds (per-note minimum and maximum) are negotiated up front, and the total is split into note amounts that sum exactly to the invoice total. Every note is valid on its own, funded by inputs that no other note in the same invoice uses, and optionally returns change to a unique, invoice-scoped sender address. Either side may submit any note to the network; confirmation depth defines settlement for that note.

    Two long-lived identity keys authenticate the off-chain session and never appear on-chain. A per-invoice shared element derived from those identities, together with the hash of the canonical invoice JSON, scopes all derivations: per-note recipient addresses, per-note sender change addresses, the exact split of amounts, labels, and receipts. Because the scope is per invoice, derivations are never reused across invoices, and the same index i under a different invoice produces unrelated addresses.

    1. Why it exists.

    Policy-compliant intake for the payee. A recipient can publish firm bounds and a fee-rate floor once, then accept large totals without ever receiving an out-of-policy note. This simplifies operations and avoids exposing internal wallet structure. • Determinism and symmetry for the payer. The payer derives exactly the same note set the recipient expects, without shipping secrets or bespoke scripts. If both ends can parse the same canonical JSON and run the same hashes and curve operations already used in Bitcoin, they interoperate. • Audit without surveillance. A Merkle root commits to the entire set of notes. Later, either party can reveal proofs for any subset (for example, to an auditor) without disclosing the remainder. Off-chain logs are signed by identity keys, allowing reconstruction of intent without putting identities on-chain.

    All of this uses only primitives that already exist in Bitcoin: secp256k1 keys, SHA-256 and RIPEMD-160, standard P2PKH outputs, and raw transaction serialisation. No new opcodes, no new script types, no new cryptographic gadgets.

    1. What does it do (functional view)

    Identity and scope. Alice (payer) and Bob (payee) authenticate using long-lived identity keypairs. They exchange two compact, signed messages: the policy (Bob’s bounds, anchor, fee floor, expiry) and the invoice (Alice’s total, unit, terms, and a reference to the policy). From these they compute (i) a shared element via ECDH and (ii) the invoice fingerprint, the SHA-256 hash of the canonical invoice JSON. The pair {Z, H_I} defines the scope for everything that follows.

    Bounded splitting. Within the published bounds, the total is decomposed into N note amounts. The number N is feasible by construction (between ceil(T ÷ v_max) and floor(T ÷ v_min)). The amounts are derived deterministically from {Z, H_I} so both parties compute the same vector and then permute it to remove any index-to-size correlation. Off-chain, the split leaks only that each note lies within bounds.

    Per-note addressing. For each index i, the payer derives the recipient’s public key for that note by tweaking the recipient’s on-chain anchor with a scalar computed from {Z, H_I, i} and a role label. Only the recipient can compute the corresponding private key. In the same scope, the payer derives a unique sender change address for index i. Identity keys are never used on-chain; only anchors appear in settlement keys.

    Disjoint funding and change. The payer assigns a strictly disjoint set of inputs to each note from a snapshot of her UTXO pool. No input appears in two notes. A standard size estimator and the negotiated fee-rate floor decide whether a note has one output (exact) or two (payee + change). When present, change always pays to the per-note sender change address. Change from one note never funds another note in the same invoice.

    Transaction formation and broadcast. Each note is a standard P2PKH transaction, fully signed and valid in isolation. Either party may broadcast any subset; duplicate submission is benign. Broadcast may be all-at-once, paced, or in bursts; confirmation depth chosen by the recipient defines finality per note.

    Receipts and selective disclosure. After notes exist, each side can compute a per-note leaf that commits to the index, txid, amount, and address payload, and then a Merkle root over the set of leaves. The root and a manifest of indices and txids provide a commitment that later supports selective proofs for any subset.

    Failure handling. Deterministic behaviours cover insufficient inputs, pre-broadcast fee changes, external conflicts, reorgs, and expiry. Reissue preserves indices and addresses; older raw bytes are marked “superseded” off-chain and are not broadcast.

    1. How it does it (implementation narrative)

    Module 1 — Canonical JSON and signing. Provide byte-identical encodings of policy, invoice, logs, and receipts. Every signed artefact includes a detached signature made by the relevant identity key over the canonical bytes (signature fields omitted from the preimage). This guarantees both sides hash the same content when computing the invoice fingerprint and policy hash.

    Module 2 — Scope and derivations. Given {Z, H_I}, derive deterministically: (a) per-note recipient keys (label “recv”), (b) per-note sender change keys (label “snd”), (c) the split of amounts (label “split”), and (d) any pacing schedule (label “pace”). Output: reproducible addresses, labels, and amounts that both wallets compute locally without sharing per-note data.

    Module 3 — Coin selection with reservation. Take a snapshot of the payer’s spendable UTXOs and allocate disjoint input sets to each note. Preference order: exact matches; then single-input near-over with valid change; then few-input combinations with minimal overshoot, always respecting dust and fee floors. If inputs are too coarse, perform one payer→payer fan-out and restart reservations. Reservations are tagged by the note identifier so rebuilding from logs yields the same table.

    Module 4 — Transaction builder. For each index, combine reserved inputs with the payee output (and optional change), order inputs and outputs deterministically, compute the fee at the floor, and sign every input in the standard way. Output: raw transaction bytes and txid per note. Log the per-note metadata (index, note id, invoice hash, recipient address, amount, txid) with signatures.

    Module 5 — Broadcast manager. Compute a nominal plan (all-at-once, paced, or bursts) using seeds derived from {Z, H_I}. Either side may submit; duplicate submissions yield the same txid. Periodic rebroadcast continues until the recipient’s depth is reached or a note is cancelled or reissued. Hold-time limits trigger automatic reissue or cancel actions; all transitions are signed in the log.

    Module 6 — Receipts and proofs. Compute the Merkle root over per-note leaves and store a manifest of indices and txids. Later, produce compact proofs for any subset by disclosing only those leaves and paths; a verifier recomputes the root without learning undisclosed notes.

    Module 7 — Logging and audit. Every state transition—reservation, signing, broadcast, reissue, cancel, orphan—is recorded as canonical JSON with timestamps and identity signatures and chained by a “prev_hash” field. Given these logs plus the public chain, an auditor can reconstruct the intended settlement set and verify that exactly one transaction per index was meant to settle.

    1. The need and its consequences

    Operational fit. Many recipients want steady, bounded inflows rather than sporadic large hits. By decomposing a purchase into bounded notes, intake risk and internal accounting become simpler, while the payer gains a clear, deterministic procedure that never leaks identity keys on-chain.

    Robustness. Notes are independent and inputs are disjoint, so partial progress is meaningful: a subset can confirm while the rest are queued or reissued. Reorg handling is straightforward: rebroadcast the same bytes.

    Privacy by construction. Identity keys stay off-chain. Per-invoice and per-note derivations require the off-chain scope to reproduce, so outsiders cannot link the recipient’s addresses across the set. Change addresses are unique per note, defeating shared-change clustering. Pacing reduces simple time-based clustering. Selective receipts allow proving exactly what is needed—no more.

    Determinism and interoperability. Independent implementations that follow the rules produce the same addresses, the same split, the same reservations, and the same receipts. Disputes are resolvable by recomputation from signed logs.

    Scope discipline. Binding all derivations to {Z, H_I} prevents cross-invoice reuse. Index i is meaningful only within the invoice that defined it. This keeps the address space clean and prevents accidental collisions when many invoices are active.

    1. Limitations and boundaries

    The design uses standard transaction forms and well-understood cryptographic primitives. It does not compress notes into nonstandard constructs, introduce new script paths, or rely on external relays. Fees and confirmation policies remain subject to network conditions. The payer’s own inputs are clustered within each note by necessity; the privacy goal here is to avoid linking recipient notes to each other, not to conceal that a single payer funded each note.

    1. What it means

    This recentres Bitcoin settlement on two authenticated endpoints who deterministically derive everything needed for a payment and act independently to bring it to finality. The outcome is not merely “many small transactions”; it is a protocol for invoice-scoped, symmetric, auditable settlement:

    Invoice-scoped: every artefact—addresses, amounts, labels, receipts—derives from the invoice fingerprint and shared element. • Symmetric: either party can complete settlement of any note at any time. • Auditable: small, signed JSON records and a single Merkle root suffice to reconstruct and prove the payment’s history.

    An engineer following the formal sections can implement these modules with no new cryptography, no changes to standard transaction formats, and no special network behaviour. A reader evaluating the design can see what it is, why it exists, how it works, and what it achieves, while staying strictly within Bitcoin’s established toolset.

    1. Objective and model

    Objective. Specify a direct, invoice-scoped payment workflow in Bitcoin in which two principals — Alice (payer) and Bob (payee) — agree explicit bounds for the value of each note and settle a total as many independent on-chain transactions. Each note is a standard transaction paying a bounded amount to a unique recipient address computable by the payer yet spendable only by the payee. Identity keys have a single role: authenticate the off-chain session and yield shared material that scopes all deterministic derivations; identity keys never appear in locking scripts, never fund or receive outputs, and never enter the on-chain graph. “IP-to-IP” denotes a direct, mutually authenticated message channel adequate to exchange compact UTF-8 JSON documents and raw transaction serialisations; transport mechanics are outside scope and irrelevant to correctness. Either party may submit any fully formed note at any time; settlement finality is defined solely by the confirmation depth the payee requires for that note. The design enforces three global guarantees: note independence, strict non-overlap of inputs, and determinism sufficient for audit and replay.

    Actors and keys. Alice maintains a long-lived identity pair Kₐ = (kₐ, Pₐ) and a sender anchor A = a·G used only to derive per-note change addresses. Bob maintains a long-lived identity pair Kᵦ = (kᵦ, Pᵦ) and a recipient anchor B = b·G used only to derive per-note receiving keys. Identity keys authenticate and scope; anchors settle on-chain. For each invoice the parties compute a shared secret Z := ECDH(kₐ, Pᵦ) = ECDH(kᵦ, Pₐ), and an invoice fingerprint Hᴵ := SHA-256(canonical-JSON(invoice)), which together bind all subsequent derivations to that invoice.

    Scope and channel model. The off-chain state for a payment is a finite, authenticated transcript: policy → invoice → acknowledgements → (optional) per-note metadata → (optional) raw transactions → receipts. The only required capability of the channel is confidential, integrity-protected exchange of these small artefacts; routing, addressability, and link maintenance are orthogonal and out of scope.

    Payment decomposition. Let T be the invoice total (in the smallest unit) and let the payee’s bounds be [vₘᵢₙ, vₘₐₓ] with 0 < vₘᵢₙ ≤ vₘₐₓ. The payment is decomposed into N ≥ 2 notes with amounts a = (a₀, a₁, …, aₙ₋₁), such that for every index i: vₘᵢₙ ≤ aᵢ ≤ vₘₐₓ and Σ aᵢ = T. Feasibility requires ⌈T ÷ vₘₐₓ⌉ ≤ N ≤ ⌊T ÷ vₘᵢₙ⌋. The pair (N, a) and all per-note labels are deterministically derived from (Z, Hᴵ) and the accepted policy so that both parties — given the same inputs — arrive at the identical target set without exchanging per-note values in the clear.

    Recipient addressing (model-level). For each index i ∈ {0, …, N−1} a unique recipient public key Pᴮ,ᵢ is derived so that: (1) Alice can compute Pᴮ,ᵢ and therefore the standard address Addrᴮ,ᵢ for the note; (2) only Bob can compute the corresponding private key kᴮ,ᵢ that spends from Addrᴮ,ᵢ; (3) no two notes of the invoice share a recipient key; and (4) observers lacking Z and B cannot link these addresses to identities or to one another.

    Funding and change (model-level). Let U be Alice’s snapshot of available unspent outputs at construction time. A reservation mapping R assigns to each index i a finite, exclusive input set Sᵢ ⊆ U with pairwise disjointness Sᵢ ∩ Sⱼ = ∅ for all i ≠ j. Each note transaction Tᵢ is funded only by Sᵢ. Where change is required, it is paid to a per-note sender address Addrᴬ,ᵢ derived deterministically from (Z, Hᴵ) and the sender anchor A. Change from one note never overlaps with change from any other note in the same invoice and is never selected to fund a different note of that invoice; intra-invoice reuse is prohibited by construction.

    Broadcast and finality. Because every Tᵢ is fully formed and independent, either party may broadcast any subset in any order or schedule (all-at-once, paced, or opportunistic). Settlement finality for a note is established when its transaction to Addrᴮ,ᵢ reaches the payee’s required confirmation depth d. Duplicate submission is benign. Conflicts cannot arise within the invoice because input sets are disjoint.

    Determinism and auditability. Determinism is a first-class requirement: given the same policy, invoice fingerprint, identities, and input snapshot U, both parties compute the same (N, a), the same recipient and change address sets (Addrᴮ,ᵢ, Addrᴬ,ᵢ), and the same per-note labels. A complete audit is reconstructible from persisted canonical JSON logs and the chain: the invoice and policy, Hᴵ, the mapping i ↦ txidᵢ, and an optional Merkle root over note receipts. No external oracle is required to re-derive or verify the set.

    Definitions (normative)

    D1 — Policy. A signed statement by the payee declaring [vₘᵢₙ, vₘₐₓ], any per-address cap (≤ vₘₐₓ), a fee-rate floor, and an expiry; hashed and referenced by the invoice.

    D2 — Invoice. A signed statement by the payer declaring T, unit, terms, invoice number, and the hash of the accepted policy; its canonical hash Hᴵ scopes all derivations.

    D3 — Note. A single standard on-chain transaction Tᵢ that pays aᵢ to Addrᴮ,ᵢ and, if necessary, returns change to Addrᴬ,ᵢ; valid, complete, and broadcastable in isolation.

    D4 — Reservation. An exclusive assignment R(i) = Sᵢ of inputs to index i with Sᵢ ∩ Sⱼ = ∅ for i ≠ j.

    D5 — Either-side broadcast. The right of both principals to announce any subset of {Tᵢ}; correctness and finality depend only on confirmation depth.

    Invariants (safety and liveness)

    I1 — Identity/settlement separation: identity keys authenticate and scope derivations; anchors alone appear in locking scripts. I2 — Per-invoice scoping: all per-note derivations and labels are functions of (Z, Hᴵ); nothing is reused across invoices. I3 — Note independence: each Tᵢ is valid without reference to any Tⱼ; no chained dependence within the invoice. I4 — Disjoint inputs: Sᵢ ∩ Sⱼ = ∅ for all i ≠ j; input reuse within an invoice is impossible by construction. I5 — Determinism: for fixed inputs (policy, invoice, Kₐ, Kᵦ, U) both parties derive the same (N, a), address sets, and labels. I6 — Non-overlapping change: for any i ≠ j, change outputs of Tᵢ and Tⱼ pay to distinct Addrᴬ,ᵢ and Addrᴬ,ⱼ and are never selected to fund another note of the same invoice. I7 — Finality by confirmation: a note is settled when its transaction has ≥ d confirmations to Addrᴮ,ᵢ; other notes are unaffected. I8 — Multiplicity: the cardinality of the note set satisfies |{Tᵢ}| = N ≥ 2; aggregation into a single multi-output transaction is out of model.

    1. Primitives, notation, and encodings

    Keys and curve (secp256k1). Private keys are scalars k in the range 1 ≤ k ≤ n−1 over the prime field 𝔽ₚ, with p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F (decimal p = 2²⁵⁶ − 2³² − 977). The base point (generator) G has order n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141. Public keys are elliptic-curve points P = k·G on the curve y² = x³ + 7 (mod p). Private scalars are represented as fixed-length 32-byte big-endian values when serialised; public keys are represented in compressed SEC1 form (see serP).

    Generator G. G is the unique base point defined by secp256k1 with affine coordinates (x_G, y_G) on 𝔽ₚ. All public keys and derivations are computed by scalar multiplication on this generator, using constant-time algorithms. No alternative generator is permitted; all parties MUST compute on the canonical G to guarantee interoperation and reproducibility.

    Group order n. The order n is the prime 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141. All scalar arithmetic (addition, subtraction, multiplication) is carried out modulo n. Any derived scalar equal to 0 is invalid and MUST be skipped deterministically (e.g., by advancing the index) to maintain a one-to-one mapping between indices and usable keys.

    ECDH shared element Z. ECDH(k, P′) is defined as the 32-byte big-endian x-coordinate of the point k·P′, where k is the caller’s private scalar and P′ is the counterparty’s public point. The raw ECDH output used in this specification is Z, a 32-byte array (left-padded with zeros if necessary). Only the x-coordinate is used; no further key-derivation primitive is introduced in this section.

    Hash functions H and H160. H(x) denotes SHA-256 over the exact byte sequence x, returning 32 bytes. H160(x) denotes RIPEMD-160(SHA-256(x)), returning 20 bytes. All inputs to H and H160 are byte strings formed by the concatenation conventions defined below; strings such as literal labels (“recv”, “snd”, “split”) are 7-bit ASCII bytes in the concatenation, not hex text.

    Generator-based serialisation serP(P). serP(P) denotes the compressed SEC1 encoding of the public point P: a single prefix byte 0x02 if y(P) is even or 0x03 if y(P) is odd, followed by the 32-byte big-endian x-coordinate. This yields 33 bytes. Uncompressed encodings (0x04 + x + y) are not used in this specification.

    Base58Check(version ∥ payload ∥ checksum). Addresses are Base58Check encodings of a 1-byte version, a payload, and a 4-byte checksum. For pay-to-public-key-hash (P2PKH), version = 0x00, payload = H160(serP(P)), checksum = first four bytes of SHA-256(SHA-256(version ∥ payload)). The encoded address is the Base58 string of version ∥ payload ∥ checksum with no whitespace, no separators, and no leading “0x”.

    Concatenation operator “∥”. The operator “∥” denotes byte-level concatenation: if x and y are byte strings, then x ∥ y is the byte string consisting of x immediately followed by y. When concatenating integers (other than LE32 below) they MUST first be encoded as fixed-length big-endian byte strings of their canonical size (e.g., 32 bytes for secp256k1 scalars). When concatenating literal labels, the labels are included as their raw ASCII bytes. No implicit conversions are permitted.

    Little-endian index LE32(i). LE32(i) is the 4-byte little-endian encoding of the non-negative integer i modulo 2³². If i ≥ 2³², then LE32(i) = LE32(i mod 2³²). The index domain for this specification is 0 ≤ i ≤ 2³²−1; indices outside this range are invalid. LE32 is used only where explicitly stated; all other integers are big-endian.

    Invoice fingerprint H_I. The invoice fingerprint H_I is a 32-byte value defined as H(canonical_json(invoice)). The function canonical_json(·) produces an unambiguous UTF-8 byte sequence for the invoice object according to the encoding rules below (key ordering, whitespace, numeric form, and normalisation are fixed). Any party recomputing H_I over the same invoice MUST obtain the same 32-byte value.

    Note identifier NoteID. For a given invoice fingerprint H_I and note index i, the note identifier is NoteID = H(H_I ∥ LE32(i)), a 32-byte value. NoteID uniquely labels a note within an invoice scope; it MUST be used in off-chain logs, reservation locks, and receipts to reference the note without revealing addresses or amounts. For fixed H_I, distinct indices yield distinct NoteIDs up to the collision resistance of SHA-256.

    Encoding rules for canonical JSON (normative).

    Character encoding. All JSON text is encoded as UTF-8. No byte order mark (BOM) is permitted.

    Unicode normalisation. All JSON string values MUST be normalised to NFC prior to byte-level serialisation. Field names are ASCII and need no normalisation.

    Object key order. Within every JSON object, keys MUST be sorted in strict lexicographic order by Unicode code point of the key strings (e.g., “addr” < “amount” < “invoice_hash” < “txid”). No deviations per locale are allowed.

    Whitespace. No insignificant whitespace is permitted in canonical JSON. Specifically: no spaces or tabs before or after “:”; no spaces after “,”; no trailing commas; no leading or trailing spaces around values. Arrays and objects are compact (e.g., {"a":1,"b":2}).

    Numbers. Integers are encoded in base-10 without leading zeros (except zero itself, which is “0”). No “+” sign. No fractional or scientific notation unless the field is explicitly defined as a float; in that case, use the shortest round-trip decimal form that parses identically (IEEE-754 round-trip), with a dot as decimal separator.

    Booleans and null. Encode as the lowercase literals “true”, “false”, and “null”.

    Byte strings. Fields that carry bytes (keys, hashes, signatures) are encoded as lowercase hexadecimal strings without “0x” prefix, unless a field is explicitly defined to contain Base58 (addresses) or base64url. For public keys, use hex of serP(P). For hashes (H, H160), use full-length lowercase hex.

    Time. Timestamp fields use ISO-8601 basic or extended form with UTC “Z” (e.g., “2025-08-26T00:00:00Z”). Offsets other than “Z” are not permitted in canonical form.

    Field presence. All required fields MUST appear exactly once. Optional fields MUST be omitted (not null) when absent.

    Determinism. canonical_json(x) is the byte sequence obtained after applying all the above rules; H_I is computed over those exact bytes. Any semantically equivalent but differently formatted JSON MUST NOT be used for hashing.

    Unambiguous definitions (summary).

    H_I := H(canonical_json(invoice)) ∈ {0,1}²⁵⁶. This binds all derivations to a single, byte-exact invoice representation. Any alteration of any invoice field (including reordering or whitespace) changes H_I.

    NoteID := H(H_I ∥ LE32(i)) ∈ {0,1}²⁵⁶. This labels note i within the scope of H_I. NoteIDs are independent of addresses, amounts, and inputs; they exist to coordinate construction, logging, and receipts without exposing settlement details.

    Implementation notes (conformance).

    All scalar reductions are mod n; all field reductions are mod p. Any derived scalar equal to 0 MUST trigger deterministic skip logic to preserve a total, collision-free mapping from indices to usable keys.

    All cryptographic hashes operate on the exact concatenated byte strings as defined; mixing hex text with raw bytes is an error. Literal labels used for domain separation are 7-bit ASCII and MUST be included as their byte values.

    Base58Check outputs are case-sensitive and MUST match the standard Bitcoin alphabet; no whitespace or line breaks are permitted in encoded addresses.

    When serialising or parsing serP(P), only 33-byte compressed encodings (0x02/0x03 + x) are valid in this specification; 65-byte uncompressed form MUST be rejected.

    3.. Identities, policy, invoice, and scope

    3.1 Roles and key material Alice (payer) holds a long-lived identity pair Kₐ = (kₐ, Pₐ) on secp256k1. Bob (payee) holds a long-lived identity pair Kᵦ = (kᵦ, Pᵦ) and a distinct settlement anchor b/B with B = b·G. Identity keys authenticate and sign off-chain artefacts; they do not appear in locking scripts. The anchor B is the sole on-chain base from which Bob’s per-note recipient keys are derived. Identity and anchor domains are strictly separated: kₐ, kᵦ are never used to authorise on-chain spends; b is never used to sign off-chain identity artefacts.

    3.2 Shared secret and invoice scope For each invoice, both parties compute a shared element Z := ECDH(kₐ, Pᵦ) = ECDH(kᵦ, Pₐ) (32-byte x-coordinate, big-endian). Define the invoice fingerprint Hᴵ := H(canonical_json(invoice)) (SHA-256 over the exact UTF-8 bytes). All derivations and labels for this invoice are functions of the pair {Z, Hᴵ}. This scoping is normative: any key, address, amount split, label, reservation lock, or receipt root that does not include {Z, Hᴵ} in its preimage is invalid for this specification. Cross-invoice reuse is forbidden by construction because Hᴵ is invoice-unique and Z is recomputed per counterparty pair.

    3.3 Policy (payee → payer): JSON schema and signature Bob issues a signed policy describing bounds and operational parameters that the payer must satisfy when constructing notes. The policy is a single JSON object encoded canonically (see §2), then signed by Bob’s identity key kᵦ.

    Canonical key order and field types (normative):

    1. "pk_anchor": string — hex(serP(B)), 66 chars (0x02/0x03 + 64 hex).

    2. "vmin": integer — minimum per-note amount (smallest unit), vmin > 0.

    3. "vmax": integer — maximum per-note amount (smallest unit), vmax ≥ vmin.

    4. "per_address_cap": integer — cap per derived recipient address; MUST satisfy vmin ≤ per_address_cap ≤ vmax.

    Constraints and verification (normative): • pk_anchor MUST equal the compressed SEC1 encoding of B; the private b MUST be distinct from kᵦ. • vmin MUST be ≥ the current dust threshold; vmax MUST be ≥ vmin; per_address_cap MUST be within [vmin, vmax]. • feerate_floor MUST be a positive integer measured per byte; both parties compute size estimates identically. • expiry MUST be strictly in the future at the time of acceptance. • sig MUST verify under sig_key over the canonical bytes of the policy with "sig", "sig_key", "sig_alg" omitted from the preimage. • H_policy := H(canonical_json(policy)) is the stable identifier referenced by the invoice.

    Canonical skeleton (bytes hashed exactly as shown, no whitespace other than mandated): {"pk_anchor":"…","vmin":…,"vmax":…,"per_address_cap":…,"feerate_floor":…,"expiry":"…","sig_key":"…","sig_alg":"secp256k1-sha256","sig":"…"}

    3.4 Invoice (payer → payee): JSON schema and signature Alice issues a signed invoice binding the total to the accepted policy and establishing the scope Hᴵ. The invoice is a single JSON object encoded canonically and signed by Alice’s identity key kₐ.

    Canonical key order and field types (normative):

    1. "invoice_number": string — UTF-8 identifier under the payer’s namespace.

    2. "terms": string — UTF-8 human-readable terms or reference thereto.

    3. "unit": string — unit of account label (e.g., "sat", "USD" when quoting; settlement remains on-chain).

    4. "total": integer — total amount in the smallest settlement unit.

    Constraints and verification (normative): • policy_hash MUST equal H_policy of the policy accepted for this invoice. • total MUST satisfy feasibility with the accepted bounds: ⌈total ÷ vmax⌉ ≤ N ≤ ⌊total ÷ vmin⌋ for some integer N ≥ 2 (checked later during split). • sig MUST verify under sig_key over the canonical bytes of the invoice with "sig", "sig_key", "sig_alg" omitted from the preimage. • Hᴵ MUST be computed as H(canonical_json(invoice)) after the signature is attached; the same Hᴵ MUST be used in all subsequent derivations for this invoice.

    Canonical skeleton: {"invoice_number":"…","terms":"…","unit":"…","total":…,"policy_hash":"…","expiry":"…","sig_key":"…","sig_alg":"secp256k1-sha256","sig":"…"}

    3.5 Authenticity and scoping procedure (end-to-end)

    1. Bob constructs the policy object with fields 1–6, sets sig_key = hex(serP(Pᵦ)), sig_alg = "secp256k1-sha256", signs the canonical bytes of the object excluding the signature triplet, and attaches sig. He sends the exact UTF-8 bytes.

    2. Alice verifies pk_anchor structure, bounds, feerate_floor, expiry, and the signature under Pᵦ; she computes H_policy = H(canonical_json(policy)).

    3. Alice constructs the invoice object with fields 1–6, sets sig_key = hex(serP(Pₐ)), sig_alg = "secp256k1-sha256", signs the canonical bytes excluding the signature triplet, attaches sig, and sends the exact UTF-8 bytes.

    4. Bob verifies policy_hash matches his H_policy, checks total and (optional) expiry, verifies Alice’s signature under Pₐ, and computes Hᴵ = H(canonical_json(invoice)).

    3.6 Security properties (normative) • Domain separation by {Z, Hᴵ} prevents cross-invoice linkage and replay: the same index i under a different invoice produces unrelated recipient and change keys. • Identity/anchor separation prevents misuse of long-term identity material on-chain and constrains blast radius of compromise: kₐ or kᵦ compromise does not expose b; b compromise affects only settlement keys, not identity assertions. • Signatures bind human-readable terms to cryptographic scope: any alteration of policy or invoice (including key order or whitespace) changes the hash and invalidates the signature.

    3.7 Rejection conditions (must fail) • Missing or malformed "pk_anchor", "sig_key", or signatures in either artefact. • vmin ≤ 0, vmax < vmin, per_address_cap outside [vmin, vmax], feerate_floor ≤ 0, or expired artefacts. • policy_hash mismatch between invoice and policy. • Failure to compute Z (invalid public keys). • Any attempt to reuse an existing Hᴵ for a different set of invoice fields.

    This section defines the precise identities, artefacts, and scoping required so that the remainder of the construction (per-note derivations, bounded splitting, disjoint funding, and receipts) operates deterministically and remains auditable without revealing identity keys on-chain.

    1. Deterministic per-note recipient keys (sender can address; recipient alone can spend)

    4.1 Inputs and domain separation Inputs: the recipient anchor B = b·G (public), the per-invoice shared element Z (32 bytes), and the invoice fingerprint Hᴵ (32 bytes). Domain separation: the literal ASCII label “recv” is included in the preimage; indices use LE32(i). All byte concatenations are with the operator “∥”. Identity keys never appear on-chain.

    4.2 Scalar derivation per note For each note index i ≥ 0 derive a scalar tᵢ as a function of {Z, Hᴵ, i}: tᵢ := int( SHA-256( Z ∥ Hᴵ ∥ "recv" ∥ LE32(i) ) ) mod n. Reject-zero rule: if tᵢ = 0, re-derive with a counter appended until non-zero, leaving the index stable: tᵢ := int( SHA-256( Z ∥ Hᴵ ∥ "recv" ∥ LE32(i) ∥ LE32(ctr) ) ) mod n, where ctr = 1,2,… until tᵢ ≠ 0. This “counter bump” preserves a one-to-one mapping from index i to a usable scalar without shifting indices and without introducing a new primitive.

    4.3 Recipient public key and address (sender view) The sender computes the per-note recipient public key by a single public-key tweak anchored at B: Pᴮ,ᵢ := B + tᵢ·G. Encode the recipient address as a standard P2PKH address: Addrᴮ,ᵢ := Base58Check( 0x00 ∥ H160( serP( Pᴮ,ᵢ ) ) ). Properties: (a) Pᴮ,ᵢ ≠ B because tᵢ ≠ 0; (b) for fixed B, different i give independent points with overwhelming probability; (c) the sender never learns any private scalar corresponding to Pᴮ,ᵢ.

    4.4 Recipient private key (recipient view) Only the recipient, who knows b, computes the spending scalar: kᴮ,ᵢ := ( b + tᵢ ) mod n, with corresponding public key Pᴮ,ᵢ = kᴮ,ᵢ·G by linearity. The recipient uses kᴮ,ᵢ to spend outputs paid to Addrᴮ,ᵢ. The base scalar b is never revealed and never used to sign off-chain artefacts.

    4.5 Collision resistance and non-reuse Per-invoice scope: because tᵢ is a function of (Z, Hᴵ, "recv", i), two different invoices (different Hᴵ and/or Z) produce unrelated tᵢ values even at the same index. Per-note uniqueness: for a fixed invoice and anchor B, equality Pᴮ,ᵢ = Pᴮ,ⱼ with i ≠ j would require tᵢ ≡ tⱼ (mod n), which has negligible probability under SHA-256. Cross-role separation: the label “recv” fixes the derivation to recipient keys and prevents accidental overlap with other derivation namespaces (e.g., sender change which uses a different label).

    4.6 One-wayness (proof sketch) Sender cannot recover kᴮ,ᵢ. The sender knows tᵢ and the public keys B and Pᴮ,ᵢ = B + tᵢ·G. Suppose the sender could compute kᴮ,ᵢ from these. Then b ≡ kᴮ,ᵢ − tᵢ (mod n) would be recoverable, yielding the discrete logarithm of B to the base G. This contradicts the hardness of the elliptic-curve discrete logarithm problem on secp256k1. Therefore, learning kᴮ,ᵢ without b is infeasible. Outsiders cannot link Pᴮ,ᵢ across notes or invoices. An observer sees addresses derived from Pᴮ,ᵢ but lacks Z and typically lacks Hᴵ. Without Z the observer cannot reproduce tᵢ, hence cannot predict or recognise the set {Pᴮ,ᵢ}. Because Pᴮ,ᵢ = B + tᵢ·G with tᵢ pseudorandom in [1, n−1], the distribution of Pᴮ,ᵢ is computationally indistinguishable from uniform over the subgroup generated by G given B, and linkage reduces to breaking the preimage resistance of SHA-256 or the ECDLP.

    4.7 Side-channel and constant-time requirements Scalar and point operations MUST be executed in constant time with respect to secret values (b and kᴮ,ᵢ). Implementations MUST avoid secret-dependent branches and table lookups during scalar multiplication and addition. The reduction “mod n” MUST be constant time. The counter-bump loop executes at most a negligible expected number of iterations (usually zero); its decision is data-independent with respect to b and only depends on the public hash tᵢ = 0 test, which is uniform at 1/n.

    4.8 Derivation pseudocode (Unicode, canonical, no LaTeX)

    Inputs • Z: 32-byte ECDH element (x-coordinate). • Hᴵ: 32-byte invoice fingerprint. • B: recipient anchor public key (compressed or internal point). • i: note index (0 ≤ i ≤ 2³²−1).

    Functions • H(x) := SHA-256(x). • H160(x) := RIPEMD-160(SHA-256(x)). • serP(P) := SEC1 compressed encoding of point P (33 bytes). • LE32(u) := 4-byte little-endian of integer u. • Base58Check(v ∥ p) := Base58Check with version v and payload p (checksum = first 4 bytes of double-SHA-256).

    Procedure (sender view)

    1. tᵢ ← int( H( Z ∥ Hᴵ ∥ "recv" ∥ LE32(i) ) ) mod n.

    2. if tᵢ = 0 then ctr ← 1; repeat tᵢ ← int( H( Z ∥ Hᴵ ∥ "recv" ∥ LE32(i) ∥ LE32(ctr) ) ) mod n; ctr ← ctr + 1; until tᵢ ≠ 0.

    3. Pᴮ,ᵢ ← point_add( B, scalar_mul( tᵢ, G ) ).

    4. addrᴮ,ᵢ ← Base58Check( 0x00 ∥ H160( serP( Pᴮ,ᵢ ) ) ).

    Procedure (recipient view)

    1. Recompute tᵢ from {Z, Hᴵ, i} with the same counter-bump if necessary.

    2. kᴮ,ᵢ ← ( b + tᵢ ) mod n.

    3. Verify kᴮ,ᵢ·G equals Pᴮ,ᵢ (optional local check).

    4. Use kᴮ,ᵢ to spend outputs paying to addrᴮ,ᵢ.

    4.9 Conformance and rejection rules • If serP(B) is not a valid compressed SEC1 encoding or not on curve, reject the invoice before derivation. • If any tᵢ = 0 after counter-bump exhaustion (theoretically impossible for practical counters), reject index i and halt with an error state. • Implementations MUST record the counter value used for each i (if any) in off-chain logs to guarantee reproducibility. • Any per-note artefact (address, label, receipt) that cannot be recomputed from {Z, Hᴵ, i, B} MUST be considered invalid for this specification.

    1. Deterministic bounded note-splitting (exact sum; indices independent of sizes)

    5.1 Inputs and feasibility

    Input parameters (all in the smallest settlement unit): total T ≥ 1; bounds [v_min, v_max] with 1 ≤ v_min ≤ v_max; per-invoice scope {Z, H_I}. Define the feasible note-count interval N_min := ⌈T ÷ v_max⌉ and N_max := ⌊T ÷ v_min⌋. Validity requires N_min ≤ N_max (otherwise the invoice is infeasible). A valid split consists of an integer N with N_min ≤ N ≤ N_max and an amount vector a[0…N−1] such that for all i: v_min ≤ a[i] ≤ v_max and Σ a[i] = T.

    5.2 Deterministic seeding

    Define a seed S := H( Z ∥ H_I ∥ "split" ) (32 bytes, SHA-256 of the exact bytes). All randomness below is deterministically derived from S. A counter-based PRNG is used: for j = 0,1,2,… define R_j := H( S ∥ LE32(j) ) and let u_j be the 64-bit unsigned integer formed from the first 8 bytes of R_j (big-endian). The function next_u64() returns u_j and increments j. This yields a reproducible, stateless stream for both parties.

    5.3 Choosing N (reproducible, interior-biased) If N_min = N_max, set N := N_min. Otherwise set span := N_max − N_min, mid := ⌊(N_min + N_max)/2⌋, and Δ := ⌊span/4⌋. Draw u := next_u64(). Map u to a symmetric jitter J in [−Δ, +Δ] by J := (u mod (2Δ+1)) − Δ. Set N₀ := mid + J, then clamp to the feasible interval: N := min( max(N₀, N_min), N_max ). This rule is deterministic, prefers interior counts when unconstrained, and never violates feasibility.

    5.4 Range-safe uniform integer draws To draw an integer r uniformly from [0, R−1] using next_u64() without modulo bias, use rejection sampling: let M := 2⁶⁴, lim := ⌊M/R⌋·R. Repeatedly draw u := next_u64() until u < lim, then return r := u mod R. This is used below for bounded choices.

    5.5 Prefix-clamped construction (exact sum, bounds preserved) Initialise rem := T. For i from 0 to N−2 do:

    1. Compute the feasible interval for a[i] given the remaining slots: slots := N−1−i low := max( v_min, rem − v_max·slots ) high := min( v_max, rem − v_min·slots ) (low ≤ high must hold by feasibility; see §5.7.)

    2. Draw r ∈ [0, (high−low)] uniformly using the range-safe method and set a[i] := low + r.

    3. Set rem := rem − a[i]. After the loop set a[N−1] := rem. By construction v_min ≤ a[N−1] ≤ v_max (proof in §5.7). This produces v_min ≤ a[i] ≤ v_max for all i and Σ a[i] = T exactly.

    5.6 Index/size de-correlation by permutation To ensure indices are independent of sizes, apply a deterministic Fisher–Yates shuffle to the completed vector a using a seed derived from S but disjoint from the draw sequence above. Define S_perm := H( S ∥ "permute" ). Instantiate a second counter-based PRNG with S_perm and perform Fisher–Yates on positions 0…N−1, using range-safe draws for each swap index. The permutation is thus fixed by {Z, H_I} and independent of the prefix-clamping choices, so no structural correlation between index and size remains.

    5.7 Correctness and termination Feasibility of each step. Assume at step i (0 ≤ i ≤ N−2) that rem satisfies v_min·(N−i) ≤ rem ≤ v_max·(N−i). Then: • Lower bound low = max( v_min, rem − v_max·(N−1−i) ) ensures that after choosing a[i] ≥ low the remaining rem′ = rem − a[i] can still be paid using at most (N−1−i) notes each of size ≤ v_max, because rem′ ≤ rem − (rem − v_max·(N−1−i)) = v_max·(N−1−i). • Upper bound high = min( v_max, rem − v_min·(N−1−i) ) ensures that after choosing a[i] ≤ high the remaining rem′ can still be paid using at least (N−1−i) notes each of size ≥ v_min, because rem′ ≥ rem − (rem − v_min·(N−1−i)) = v_min·(N−1−i). Hence low ≤ a[i] ≤ high implies v_min·(N−1−i) ≤ rem′ ≤ v_max·(N−1−i), maintaining the invariant. The base case at i = 0 holds by the choice of N (N_min ≤ N ≤ N_max). By induction the invariant holds for all i ≤ N−2. Termination occurs after exactly N steps. At i = N−1 we have rem′ = a[N−1] and v_min ≤ a[N−1] ≤ v_max by the invariant, and Σ a[i] = T by construction.

    5.8 Determinism and replay Every choice is a pure function of {Z, H_I}, the accepted bounds, and the deterministic PRNG streams from S and S_perm. Given identical inputs, independent implementations compute identical N, identical pre-permutation a, and an identical permutation. No per-note amounts need to be exchanged off-chain; both parties recompute the same vector.

    5.9 Edge cases and rejection rules • Infeasible invoice: if N_min > N_max (e.g., T < v_min or T > v_max·N_max under external constraints), reject the invoice before splitting. • Tight bounds: if v_min = v_max then N is forced to N_min = N_max and the vector is constant a[i] = v_min for all i. • Degenerate last step: if N = 1 the construction degenerates to a[0] := T, which must equal v_min = v_max = T to be feasible; otherwise reject at §5.1. • Deterministic streams: the PRNG counters MUST NOT be shared between “split” and “permute”; S_perm isolates the shuffle. Counters MUST be reset to zero for each new seed.

    5.10 Pseudocode (Unicode; canonical; no bias)

    Seed and PRNG seed_split := H( Z ∥ H_I ∥ "split" ) seed_perm := H( seed_split ∥ "permute" )

    function next_u64(seed, counter): R := H( seed ∥ LE32(counter) ) counter := counter + 1 return (first 8 bytes of R as uint64 big-endian), counter

    function draw_uniform(R, range): # range ≥ 1 M := 2⁶⁴ lim := (M ÷ range) × range loop: (u, ctr) := next_u64(R.seed, R.ctr) if u < lim: return (u mod range), (R.seed, ctr) else: continue

    Choosing N span := N_max − N_min if span = 0: N := N_min else: mid := ⌊(N_min + N_max)/2⌋ Δ := ⌊span/4⌋ (r, R_split) := draw_uniform( R_split, 2Δ + 1 ) J := r − Δ N := clamp( mid + J, N_min, N_max )

    Constructing a rem := T for i in 0 … N−2: slots := N−1−i low := max( v_min, rem − v_max × slots ) high := min( v_max, rem − v_min × slots ) (r, R_split) := draw_uniform( R_split, high − low + 1 ) a[i] := low + r rem := rem − a[i] a[N−1] := rem

    Permutation (Fisher–Yates using seed_perm) for j in (N−1) down to 1: (r, R_perm) := draw_uniform( R_perm, j+1 ) swap a[j] ↔ a[r]

    5.11 Rationale for the permutation step Without permutation, prefix-clamping tends to bias early indices toward interior values of [v_min, v_max] when T is near a boundary, creating a weak but systematic index→size correlation. A seeded Fisher–Yates shuffle removes positional information while preserving multiset equality and the exact sum. Using S_perm derived from S ensures determinism tied to {Z, H_I} and prevents stream re-use, so the shuffle cannot be predicted or recomputed by third parties lacking the invoice scope.

    5.12 Security and leakage considerations The split leaks only that all amounts lie in [v_min, v_max]; no per-note sizes are revealed off-chain because both wallets compute a independently. On-chain, an external observer learns the multiset of paid amounts if all notes are broadcast promptly; timing diversity in broadcast is handled elsewhere. The permutation ensures indices carry no information about sizes in off-chain logs or receipts. Deterministic seeding binds all outcomes to the invoice; cross-invoice linkage by split structure is prevented by H_I.

    1. Disjoint coin selection and strict non-overlap across notes

    6.1 Snapshot and reservation model Input pool U is the payer’s spendable UTXOs at invoice start, filtered for script type (payer’s own keys), maturity, and policy (confirmations, timelocks). U is a set of outpoints ⟨txid, vout, value, scriptPubKey, keyref⟩. At construction time the wallet takes a read-only snapshot U₀ and builds a reservation table R mapping each note index i to an exclusive input set Sᵢ ⊂ U₀. Exclusivity is strict: Sᵢ ∩ Sⱼ = ∅ for all i ≠ j. Each outpoint carries a reservation state: free → reserved(i) → committed(i) or free (on cancel). Reservations are keyed by NoteID to ensure stable recovery from logs.

    6.2 Deterministic ordering To maximise success and ensure reproducibility, notes are funded in a fixed order: sort indices by descending a[i]; ties break by ascending i. The UTXO pool is iterated in a fixed order: sort by (value ascending, then txid lexicographic ascending, then vout ascending). No random tie-breakers appear in selection; given U₀ and a[·], the same R is produced.

    6.3 Fee and dust parameters Let feerate_floor be the minimum units-per-byte. For a candidate with m inputs and n outputs (n ∈ {1,2}), estimate bytes as size ≈ 10 + 148·m + 34·n. Required fee = feerate_floor × size (integer, round up). Dust threshold δ_dust is the minimum output value permitted by local policy; any output < δ_dust is invalid. Change outputs must be either ≥ δ_dust or omitted (surplus folded into the fee only when explicitly permitted by policy).

    6.4 Selection policy (bounded-knapsack with exact-match preference) Goal for note i: choose Sᵢ such that Σ value(Sᵢ) = a[i] + fee + change, with change ∈ {0} ∪ [δ_dust, ∞). Preference order: (1) exact match with zero change; (2) single-input just-over target with valid change; (3) fewest inputs subject to minimal overshoot and valid change. Any candidate that would produce an output < δ_dust or violate feerate_floor is rejected.

    6.5 Algorithm for building R (normative)

    Inputs: U₀ (ordered), vector a[0…N−1], feerate_floor, δ_dust. Outputs: reservation table R or failure.

    Pre-pass: remove from U₀ any outpoint < δ_dust or not controlled by the payer. Initialise R := ∅. Let Used := ∅.

    For i in sort_descending_by a[i] then ascending i:

    1. Target initialisation target := a[i] best := ⊥

    2. Stage A — exact single-input For each u ∈ U₀ \ Used: fee₁ := feerate_floor × (10 + 148·1 + 34·1) if value(u) = target + fee₁: best := {u}; goto Commit

    3. Stage B — exact few-inputs (bounded subset) Search over combinations of up to K_max inputs (K_max default 4) from U₀ \ Used in ascending cardinality. For each candidate set C: m := |C|; fee_m := feerate_floor × (10 + 148·m + 34·1) if Σ value(C) = target + fee_m: best := C; goto Commit (Prune by value sums exceeding target + fee_m + δ_dust unless Stage C.)

    4. Stage C — single-input near-over For each u ∈ U₀ \ Used: fee₂ := feerate_floor × (10 + 148·1 + 34·2) change := value(u) − target − fee₂ if change ≥ δ_dust and change is minimal among examined: best := {u}

    FailureForI: Attempt optional fan-out (once per invoice). If fan-out succeeds and confirms per policy, refresh U₀ := U_fanout ⊎ (U₀ \ Used) and restart from i = 0. If fan-out is disabled or fails, abort with “insufficient granularity”.

    Return R upon success for all i.

    6.6 Definition of “locked” UTXO A locked UTXO is an outpoint in state reserved(i) with metadata {NoteID, timestamp, size_estimate, fee_rate_used}. While reserved, it MUST NOT be considered by selection for any j ≠ i within the same invoice. A reserved UTXO transitions to committed(i) once Tᵢ is fully signed. If a note is cancelled before broadcast, all Sᵢ return to free; if reissued, Sᵢ remain reserved until the new Tᵢ is committed.

    6.7 Failure modes and outcomes • Insufficient value: Σ value(U₀) < Σ a[i] + fees_min → abort invoice (fan-out cannot create value). • Insufficient granularity: value(U₀) is concentrated in large outputs so that every candidate either violates δ_dust for change or exceeds K_max/M_max → attempt fan-out. • Conflicting external spend: if a reserved outpoint is spent externally (wallet mutation), invalidate R and rebuild from a fresh U snapshot; log the conflict under the offending outpoint. • Policy violation: any candidate producing outputs below δ_dust or underpaying fee is rejected; if no candidate remains, treat as insufficient granularity.

    6.8 Optional preparatory fan-out (payer-only, outside the note set) Purpose: reshape coarse inputs into a set of smaller payer-owned outputs suitable for the target a[·]. Rules: • Destination: strictly to the payer’s own addresses derived from the sender anchor under a distinct namespace label “fund” (not “snd”), e.g., Addr_fund,j; never to the payee; never counted as a note. • Granularity: choose output sizes to cover the histogram of a[·] and expected change values, typically near v_max and mid-range values; all fan-out outputs ≥ max(δ_dust, v_min). • Count: minimise number of fan-out outputs while ensuring coverage; a practical target is ⌈Σ a[i] ÷ v_max⌉ plus a small buffer. • Fee and confirmation: construct with feerate ≥ feerate_floor and, by default, require at least one confirmation before using the resulting outputs in R (deterministic policy); if unconfirmed chaining is allowed by local policy, mark chained notes as risk-accepted in logs. • Scope: fan-out transactions are labelled funding-only with a distinct manifest and are excluded from receipt accounting. • Idempotence: perform at most one fan-out attempt per invoice; repeated fan-outs can re-fragment and harm determinism.

    6.9 Determinism and auditability Given U₀, a[·], feerate_floor, δ_dust, K_max, M_max, and the fixed iteration orders, the algorithm produces a unique R. The wallet MUST persist U₀ snapshot metadata, the reservation table R, size/fee calculations, and any fan-out manifest to allow exact recomputation. Change outputs created by notes MUST NOT be admitted into U₀ for funding other notes within the same invoice; they become eligible only after the invoice is closed (completed or aborted).

    6.10 Pseudocode (Unicode; canonical)

    function build_reservations(U₀, a[0…N−1], feerate_floor, δ_dust): order_notes := sort_desc( (a[i], −i) ) # by amount desc, then i asc order_utxo := sort_asc( (value, txid, vout) ) # deterministic pool order Used := ∅; R := {} fanout_done := false repeat: for i in order_notes: best := select_inputs_disjoint(order_utxo \ Used, a[i], feerate_floor, δ_dust) if best = ⊥: if not fanout_done and policy_allows_fanout(): F := build_fanout(order_utxo \ Used, histogram(a), feerate_floor, δ_dust) if F.success and F.confirmed: U₀ := (U₀ \ F.inputs) ⊎ F.outputs Used := ∅; R := {}; fanout_done := true; goto repeat return ⊥ R[i] := best; Used := Used ∪ best return R

    6.11 Guarantees • Strict non-overlap: by construction Sᵢ ∩ Sⱼ = ∅ for i ≠ j, and change from Tᵢ is excluded from funding Tⱼ. • Independence: each Tᵢ can be signed and broadcast without reference to any Tⱼ. • Compliance: every output is ≥ δ_dust; every transaction meets or exceeds feerate_floor. • Reproducibility: with the persisted U₀ and logs, the same R is reconstructed exactly.

    1. Per-note change addresses and change calculation (no overlap; deterministic; auditable)

    7.1 Scope and requirements Change outputs are per-note, invoice-scoped artefacts. For each index i, the payer derives exactly one sender-side change address Addrᴬ,ᵢ deterministically from {Z, Hᴵ} and a sender anchor A = a·G. Change produced by note i MUST pay to Addrᴬ,ᵢ. No change output from note i is eligible to fund any other note j ≠ i within the same invoice. Reissues before broadcast preserve the index i and Addrᴮ,ᵢ; Addrᴬ,ᵢ remains stable for i.

    7.2 Sender change derivation (deterministic, per note) Inputs: sender anchor A = a·G (public), per-invoice scope {Z, Hᴵ}. Domain separation uses the ASCII label “snd”.

    Define the per-note tweak scalar: sᵢ := int( SHA-256( Z ∥ Hᴵ ∥ "snd" ∥ LE32(i) ) ) mod n.

    Reject-zero rule: if sᵢ = 0, deterministically bump a counter until non-zero: sᵢ := int( SHA-256( Z ∥ Hᴵ ∥ "snd" ∥ LE32(i) ∥ LE32(ctr) ) ) mod n, ctr = 1,2,...

    Define the per-note sender public key and address: Pᴬ,ᵢ := A + sᵢ·G. Addrᴬ,ᵢ := Base58Check( 0x00 ∥ H160( serP(Pᴬ,ᵢ) ) ).

    Uniqueness and separation: for fixed A and invoice scope, indices map to distinct Pᴬ,ᵢ with overwhelming probability; “snd” prevents namespace collision with recipient derivations (“recv”).

    7.3 Fee and change arithmetic (standard P2PKH) Parameters: • m = number of inputs for note i. • n ∈ {1, 2} = number of outputs (1 = pay-only, 2 = pay + change). • size_bytes ≈ 10 + 148·m + 34·n (P2PKH approximation). • fee_rate_floor = minimum units-per-byte (smallest unit per byte). • fee := ceil( fee_rate_floor × size_bytes ). • δ_dust = dust threshold (policy parameter, smallest unit). • sum_inputs := Σ value(inputⱼ) over the reserved set Sᵢ. • target := a[i] (the note’s recipient amount).

    Deterministic evaluation (no circularity): Step A — assume n = 1 (no change). Compute fee₁ := ceil( fee_rate_floor × (10 + 148·m + 34·1) ). • If sum_inputs = target + fee₁ → construct a 1-output transaction: pay target to Addrᴮ,ᵢ; no change. • Else proceed to Step B.

    Step B — assume n = 2 (pay + change). Compute fee₂ := ceil( fee_rate_floor × (10 + 148·m + 34·2) ). • change := sum_inputs − target − fee₂. • If change ≥ δ_dust → construct a 2-output transaction: pay target to Addrᴮ,ᵢ and change to Addrᴬ,ᵢ. • If change ∈ [1, δ_dust−1] → invalid (dust). Either add one more input (recompute m, fee₂, change) or reselect Sᵢ per §6; if no valid candidate exists, fail funding for i. • If change ≤ 0 → underfunded; add inputs or reselect Sᵢ.

    Rounding rule: fees are rounded up to the nearest integer unit to avoid underpayment. All implementations MUST use identical size estimates and rounding to preserve determinism.

    7.4 No-overlap and pool eligibility No intra-invoice reuse: change created by Tᵢ MUST NOT be inserted into the funding pool U for any j ≠ i while the invoice is open (building, broadcasting, or awaiting confirmations). Enforcement is by NoteID tagging: every change UTXO carries {invoice_hash = Hᴵ, index = i} and a state “locked(change,i)” until closure.

    7.5 Reissue semantics (pre-broadcast) If a different fee rate is desired before broadcast, reissue note i by constructing a new transaction with possibly different inputs but the same index i, the same recipient address Addrᴮ,ᵢ, and the same sender change address Addrᴬ,ᵢ. Update fee, change, and txid in logs; mark the prior, unbroadcast serialisation as superseded. Addrᴬ,ᵢ stability guarantees that all change for i remains isolated to that index across reissues.

    7.6 Security and leakage Identity keys are not used on-chain. Sender change keys are invoice-scoped and per-note; without {Z, Hᴵ, A} an observer cannot regenerate Addrᴬ,ᵢ. Because change pays to unique addresses per index, clustering by shared change across notes of the same invoice is prevented by construction.

    7.7 Conformance and rejection rules • Reject if serP(A) is invalid or not on curve. • Reject if sᵢ = 0 after counter-bump exhaustion (theoretical). • Reject any candidate where change ∈ (0, δ_dust). • Reject any construction whose fee < fee_rate_floor × estimated size (post-rounding). • Persist {i, sum_inputs, m, n, size_bytes, fee, change, Addrᴮ,ᵢ, Addrᴬ,ᵢ, txid} for audit.

    7.8 Pseudocode (Unicode; canonical)

    Inputs • a[i], Sᵢ (reserved inputs for i), fee_rate_floor, δ_dust, A, Z, Hᴵ. • serP, H, H160, Base58Check as defined earlier.

    Derive change address sᵢ := int( H( Z ∥ Hᴵ ∥ "snd" ∥ LE32(i) ) ) mod n if sᵢ = 0: ctr := 1 repeat: sᵢ := int( H( Z ∥ Hᴵ ∥ "snd" ∥ LE32(i) ∥ LE32(ctr) ) ) mod n ctr := ctr + 1 until sᵢ ≠ 0 Pᴬ,ᵢ := point_add( A, scalar_mul( sᵢ, G ) ) Addrᴬ,ᵢ := Base58Check( 0x00 ∥ H160( serP(Pᴬ,ᵢ) ) )

    Compute fee and change m := |Sᵢ| size₁ := 10 + 148×m + 34×1 fee₁ := ceil( fee_rate_floor × size₁ ) if Σ value(Sᵢ) = a[i] + fee₁: outputs := [ (Addrᴮ,ᵢ, a[i]) ] # n = 1, no change else: size₂ := 10 + 148×m + 34×2 fee₂ := ceil( fee_rate_floor × size₂ ) change := Σ value(Sᵢ) − a[i] − fee₂ if change ≥ δ_dust: outputs := [ (Addrᴮ,ᵢ, a[i]), (Addrᴬ,ᵢ, change) ] # n = 2 else if 0 < change < δ_dust: fail "dust-change" # add input or reselect Sᵢ else: fail "underfunded" # add input or reselect Sᵢ

    Construct transaction Tᵢ := make_tx( inputs = Sᵢ, outputs = outputs ) sign_all_inputs(Tᵢ) record_log( i, Hᴵ, Sᵢ, m, outputs, fee, change, txid(Tᵢ), Addrᴬ,ᵢ, Addrᴮ,ᵢ )

    Policy enforcement mark_change_utxo(Tᵢ, i, Hᴵ, state="locked(change,i)") forbid_selection_of_locked_change_until_invoice_closed(Hᴵ)

    7.9 Bytesize estimator and parameters (normative defaults) • Input (P2PKH): 148 bytes. Output (P2PKH): 34 bytes. Overhead: 10 bytes. • Implementations MAY use precise varint-aware sizing; if so, the same sizing method MUST be used deterministically by both parties. • δ_dust is a fixed policy parameter for the implementation; it MUST be agreed implicitly by equal software or explicitly encoded in policy to avoid disagreements.

    1. Transaction formation per note (independent, standard, fully signed)

    8.1 Build order (normative)

    For each index i:

    1. Inputs (funding). Take the reserved input set Sᵢ from the reservation table (pairwise disjoint across i). Let m = |Sᵢ| and sum_inputs = Σ value(Sᵢ).

    2. Outputs (payee and optional change). • Primary output: (Addrᴮ,ᵢ, a[i]). • Change output (if required by §7): (Addrᴬ,ᵢ, change[i]). Output ordering is deterministic: primary first, change second if present.

    3. Transaction fields. • nVersion = 1 (32-bit little-endian). • vin count = m (varint). • For each input j in Sᵢ in deterministic order (value ascending, then txid lexicographic ascending, then vout ascending): – prevout.txid (32-byte little-endian), prevout.vout (4-byte little-endian). – scriptSig = empty during preimage construction. – nSequence = 0xFFFFFFFF unless explicitly negotiated otherwise. • vout count = 1 or 2 (varint). • For each output in the order specified: – value (8-byte little-endian). – scriptPubKey = standard P2PKH: OP_DUP OP_HASH160 <20-byte H160(serP(P))> OP_EQUALVERIFY OP_CHECKSIG. • nLockTime = 0 unless explicitly negotiated otherwise.

    8.2 Independence and validity (normative)

    Tᵢ references only inputs from Sᵢ and pays only to Addrᴮ,ᵢ and (if present) Addrᴬ,ᵢ. • Tᵢ contains no pointers to any Tⱼ, j ≠ i; no input or change overlap is permitted within the invoice. • Any subset of {Tᵢ} may be broadcast in any order without invalidating or starving the remainder.

    8.3 NoteMeta schema (canonical JSON; log-only)

    Minimal, required fields:

    {"i": , "note_id": "<hex 32-byte NoteIDᵢ>", "invoice_hash": "<hex 32-byte Hᴵ>", "addr": "<base58 Addrᴮ,ᵢ>", "amount": <int a[i]>, "txid": "<hex 32-byte txidᵢ>"}

    Recommended extensions for audit (all integers in smallest unit; strings lowercase hex unless noted):

    {"size_bytes": , "fee": , "feerate_used": , "change_addr": "<base58 Addrᴬ,ᵢ or empty>", "change_amount": <int or 0>, "inputs": [ {"txid":"","vout":,"value":,"scriptPubKey":""} ], "outputs": [ {"addr":"","value":}, {"addr":"","value":}? ], "sig_alg": "secp256k1-sha256", "created_at": "", "status": "unsigned|signed|broadcast|confirmed|reissued|cancelled"}

    All NoteMeta objects MUST be encoded canonically (UTF-8, sorted keys, no extraneous whitespace) when hashed or signed. The tuple (i, NoteIDᵢ, txidᵢ) is the stable handle for the note within an invoice.

    8.4 Deterministic ordering and tie-breaking (normative)

    Inputs inside Tᵢ are ordered by (value ascending, txid lexicographic ascending, vout ascending). • Outputs are ordered: primary primary first, change second if present. • scriptSig contains exactly one DER-encoded ECDSA signature with appended 0x01 hash-type byte and one compressed public key; no additional pushes are permitted.

    8.5 Conformance and rejection rules

    Reject Tᵢ if any output value < 0 or > 2⁶³−1, or if Σ outputs + fee ≠ Σ inputs. • Reject if any output < δ_dust. • Reject if fee < fee-rate floor × size_bytes (post-rounding). • Reject if any scriptSig is empty or fails standard verification under SIGHASH_ALL. • Reject if NoteIDᵢ mismatches {Hᴵ, i}, or if addr ≠ Addrᴮ,ᵢ derived from {Z, Hᴵ, i, B}. • On reissue prior to broadcast, the new transaction replaces txidᵢ in logs for the same i and NoteIDᵢ; Addrᴮ,ᵢ and Addrᴬ,ᵢ remain unchanged.

    1. Ordering, pacing, and broadcast authority (either side may settle)

    9.1 Authority and symmetry Either party may broadcast any subset of the note transactions at any time. The payer (Alice) and the recipient (Bob) hold identical authority to submit a fully signed note TiTᵢ to the network. Duplicate broadcast of identical bytes is benign: identical transactions share the same txid and are deduplicated by nodes. Settlement for a note is defined solely by confirmation depth dd selected by the recipient in policy; once TiTᵢ achieves ≥ dd confirmations to Addrᴮ,ᵢ, that note is settled irrespective of the status of other notes in the invoice.

    9.2 Broadcast strategies (permissible) • All-at-once — submit all TiTᵢ immediately. • Paced — submit TiTᵢ according to a deterministic schedule over a window [t0,t1][t₀, t₁] with minimum spacing. • Grouped bursts — partition notes into batches of size β; submit batches with inter-batch gaps.

    A strategy is advisory; either party may accelerate or decelerate within the agreed bounds.

    9.3 Policy fields (broadcast) — payee → payer (canonical JSON) Augment the policy (§3.3) with:

    "broadcast": { "authority": "either", // fixed literal "strategy_default": "paced|all_at_once|bursts", "min_spacing_ms": <int ≥ 0>, // minimum inter-note gap "max_spacing_ms": <int ≥ min_spacing>, // upper bound for paced jitter "burst_size": <int ≥ 1>, // used when strategy_default = "bursts" "burst_gap_ms": <int ≥ 0>, // inter-burst gap "window_start": "|"" ", "window_end": "|"" ", "rebroadcast_interval_s": <int ≥ 60>, // periodic re-announce until confirmed "hold_time_max_s": <int ≥ 0>, // max age for unbroadcast notes before action "confirm_depth": <int ≥ 0> // d, settlement depth }

    Normative constraints: • If "window_start" and "window_end" are both present, require window_start < window_end. • If "strategy_default" = "bursts", "burst_size" ≥ 2; otherwise "burst_size" is ignored. • "confirm_depth" defines finality dd for all notes unless overridden in the invoice.

    9.4 Invoice overrides — payer → payee (canonical JSON) An invoice MAY propose narrower pacing within policy bounds:

    "broadcast_overrides": { "strategy": "paced|all_at_once|bursts", // optional; must be allowed by policy "min_spacing_ms": , // ≤ policy.max_spacing_ms "max_spacing_ms": , // ≥ min_spacing_ms and ≤ policy.max_spacing_ms "burst_size": , // if strategy = "bursts" and ≤ policy.burst_size "burst_gap_ms": , // ≤ policy.burst_gap_ms or equal "window_start": "|"" ", "window_end": "|"" ", "confirm_depth": // ≥ policy.confirm_depth }

    Validation: every override must satisfy policy bounds; otherwise the invoice is invalid.

    9.5 Deterministic pacing schedule (sender/recipient can compute identically) Seed for schedule: S_pace := H( Z ∥ Hᴵ ∥ "pace" ). Derive a reproducible jitter stream from S_pace (as in §5.2). Let order of notes for scheduling be the stable index order 0…N−1.

    All-at-once: for all i, schedule_time[i] := max(now, window_start). Paced: for i = 0…N−1, draw δᵢ uniformly from [min_spacing_ms, max_spacing_ms] via deterministic PRNG; set schedule_time[0] := max(now, window_start); schedule_time[i] := schedule_time[i−1] + δᵢ ms; if schedule_time[i] > window_end (when set), cap at window_end. Bursts: partition indices into batches of size β (β = burst_size). For batch k, set batch_time[k] := (k = 0 ? max(now, window_start) : batch_time[k−1] + burst_gap_ms). All notes in batch k share batch_time[k]; within a batch, apply a tiny deterministic intra-batch offset εᵢ ∈ [0, min_spacing_ms] to break ties.

    Either party may use the same schedule; divergence does not affect correctness. The schedule is an off-chain convenience that does not appear on-chain.

    9.6 Hold-time and lifecycle timers Define τ_hold_max := hold_time_max_s (policy). A note ii moves through states:

    constructed → signed → queued → broadcast → seen → confirmed | orphaned ↘ reissued → signed → queued … ↘ cancelled

    Timer rules (normative): • If queued and now − created_at(i) ≥ τ_hold_max, choose exactly one: (a) reissue ii with new inputs Sᵢ′ (same i, same Addrᴮ,ᵢ, same Addrᴬ,ᵢ), reset created_at; or (b) cancel ii explicitly (see §9.8). • If broadcast but not seen by the counterparty within 2 × rebroadcast_interval_s, rebroadcast. • If seen but unconfirmed for more than κ × rebroadcast_interval_s (κ ≥ 3), continue periodic rebroadcast until confirmed or cancelled.

    9.7 Reissue procedure (pre-broadcast; deterministic labels preserved) Preconditions: note ii is not confirmed; the previous candidate Tᵢ has not been announced or is to be superseded; reasons include fee adjustment or input conflict.

    Steps:

    1. Release prior reservation Sᵢ to free (unless already conflicted on-chain).

    2. Select new Sᵢ′ disjoint from every Sⱼ, j ≠ i (see §6).

    3. Recompute fee and change at the negotiated floor (§7); derive the same Addrᴮ,ᵢ and Addrᴬ,ᵢ.

    4. Build and sign new transaction Tᵢ′.

    Only the latest version for index i is eligible for broadcast. Earlier versions MUST NOT be re-broadcast once superseded.

    9.8 Cancellation procedure (explicit, off-chain) If a note will not be used:

    1. Set NoteMeta[i].status := "cancelled".

    2. Clear reservation Sᵢ to free; do not derive a new candidate unless re-enabled.

    3. Record a signed cancellation entry by the party effecting the cancel: {"i": i, "note_id": "<NoteIDᵢ>", "invoice_hash": "<Hᴵ>", "action": "cancel", "by": "<sig_key>", "at": "", "sig": ""}.

    9.9 Duplicate broadcast semantics • Identical bytes: if Alice and Bob both submit the same Tᵢ, the txid is identical; network deduplicates; state becomes "seen" then "confirmed". • Divergent bytes (only possible after reissue): the policy forbids broadcasting superseded versions. If an older Tᵢ is propagated accidentally, whichever transaction confirms first defines settlement for i; the other is a double-spend loser and MUST be marked "obsolete" in logs. Implementations SHOULD guard by refusing to broadcast any version where NoteMeta[i].version < current_version.

    9.10 Logging fields (canonical JSON; per note) Extend NoteMeta (§8.3) with broadcast management:

    { "i": , "note_id": "", "invoice_hash": "", "txid": "", "version": <int ≥ 1>, "status": "queued|broadcast|seen|confirmed|reissued|cancelled|obsolete|orphaned", "scheduled_at": "", "broadcast_at": "|""", "last_rebroadcast_at": "|""", "confirm_depth": , // effective d "supersedes": "|""", "superseded_by": "|""" }

    All entries are UTF-8 canonical JSON (sorted keys). Signatures over log events MAY be added using identity keys to bind audit records.

    9.11 Conformance and rejection rules • If "broadcast_overrides" conflicts with policy bounds, reject the invoice. • If a party attempts to broadcast a superseded version (version < current_version), reject locally and log an error; do not transmit. • If a queued note exceeds τ_hold_max without reissue or cancel, mark "stale" and require explicit operator action before any broadcast. • Confirmation acceptance: mark a note "confirmed" only after ≥ d confirmations for its output to Addrᴮ,ᵢ; d is taken from invoice override if present, else from policy.confirm_depth.

    9.12 Determinism and auditability The schedule derived from S_pace ensures both parties can compute the same nominal broadcast plan without coordination. Regardless of who submits, finality is defined by on-chain confirmations. The “supersedes” chain, version counter, and timestamped log records provide an append-only audit trail proving that, for each index i, exactly one transaction version was intended to settle, and any earlier candidates were explicitly voided off-chain before settlement.

    1. Receipts and selective disclosure

    10.1 Purpose Receipts bind a complete set of notes for an invoice into a single commitment that can later be opened selectively. The commitment is a Merkle root M computed over per-note leaves Lᵢ. To acknowledge any subset, the prover discloses those leaves and their Merkle paths; all undisclosed leaves remain hidden. Domain separation by the invoice fingerprint Hᴵ prevents cross-invoice linkage.

    10.2 Exact leaf structure (bytes, canonical) Each leaf is the SHA-256 of a byte-exact concatenation of fixed-width fields. The recipient address is represented as its binary payload (version byte and 20-byte public-key hash), not as Base58 text.

    Definitions

    label := ASCII bytes of the literal string "leaf". • i := note index (0 ≤ i ≤ 2³²−1). • LE32(i) := 4-byte little-endian encoding of i. • txidᵢ := 32-byte transaction identifier in big-endian display order (exact bytes of the hex string). • amountᵢ := 8-byte little-endian unsigned integer (smallest unit). • Pᴮ,ᵢ := recipient public key for note i. • h160ᵢ := RIPEMD-160(SHA-256(serP(Pᴮ,ᵢ))) (20 bytes). • ver := 0x00 (1 byte; P2PKH version). • addr_payloadᵢ := ver ∥ h160ᵢ (21 bytes). (Checksum and Base58 encoding are excluded.)

    Leaf preimage and hash preimageᵢ := label ∥ LE32(i) ∥ txidᵢ ∥ amountᵢ ∥ addr_payloadᵢ Lᵢ := SHA-256(preimageᵢ) (32 bytes)

    Notes • All concatenations are byte-level. • All numeric encodings and endianness are as stated; no alternative formats are permitted. • If the implementation wishes to include additional fields (e.g., change_amount), they MUST be placed after addr_payloadᵢ and MUST also be fixed-width and identically encoded by both parties; otherwise omit them entirely.

    10.3 Merkle tree construction (binary, deterministic) • Leaves: the sequence [L₀, L₁, …, L_{N−1}] in ascending index order. • Internal node hash: H(x ∥ y) := SHA-256(x ∥ y) with x,y each 32 bytes. • Layering: pair adjacent elements left-to-right; if a layer has odd cardinality, duplicate the final element (Bitcoin-style padding) so every parent has two children. Repeat until a single 32-byte value remains; that value is the Merkle root M. • Empty set: N ≥ 1 is required; for N = 1, M = L₀.

    10.4 Stored commitment and manifest (canonical JSON) Persist a compact manifest for the invoice. Canonical JSON rules from §2 apply (UTF-8, NFC, sorted keys, no extraneous whitespace).

    Minimal manifest { "invoice_hash": "<hex 32-byte H_I>", "merkle_root": "<hex 32-byte M>", "count": , "entries": [ {"i": , "txid": "<hex 32-byte>"}, … ] }

    Recommendations • Do not store amounts or addresses in the manifest; keep them private to the payer and payee. • Optionally include "created_at" (ISO-8601 UTC) and detached signatures by identity keys to authenticate the record.

    10.5 Selective disclosure proof (single leaf) A proof for index i consists of: • The disclosed leaf data (i, txidᵢ, amountᵢ, addr_payloadᵢ). • The computed leaf hash Lᵢ. • A Merkle path πᵢ = [(pos₀, s₀), (pos₁, s₁), …, (pos_{h−1}, s_{h−1})], where each sⱼ is a 32-byte sibling hash and posⱼ ∈ {"L","R"} indicates whether L (or the running hash) is on the left or right at that layer. • The root M being claimed.

    Verification procedure

    1. Recompute preimageᵢ := "leaf" ∥ LE32(i) ∥ txidᵢ ∥ amountᵢ ∥ addr_payloadᵢ.

    2. Compute L ← SHA-256(preimageᵢ).

    3. For j = 0…h−1: • If posⱼ = "L": L ← SHA-256( L ∥ sⱼ ). • If posⱼ = "R": L ← SHA-256( sⱼ ∥ L ).

    4. Accept if and only if L equals the claimed merkle_root M (as 32-byte value). Otherwise reject.

    10.6 Selective disclosure proof (multiple leaves) For a subset S ⊆ {0,…,N−1}, provide independent single-leaf proofs (as above) for each i ∈ S, or provide a multi-proof that minimises duplicate siblings by sharing path segments. A multi-proof may be represented as: { "invoice_hash": "", "merkle_root": "", "leaves": [ {"i": , "txid": "", "amount": , "addr_payload": "<hex 21-byte>"}, … ], "sibling_hashes": ["<hex 32-byte>", …], "structure": "" // e.g., a bitstring specifying merge order } Verification recomputes the same frontier using the structure bitstring; if unfamiliar with multi-proofs, verify each leaf independently.

    10.7 Privacy properties • For any disclosed leaf i, the verifier learns (i, txidᵢ, amountᵢ, addr_payloadᵢ). • For any undisclosed leaf j ∉ S, no information beyond the length N and the set of indices S is revealed; sibling hashes are computationally indistinguishable from random without preimages. • The manifest stores only (i, txidᵢ) pairs, avoiding publication of amounts and addresses. • Domain separation by H_I ensures that identical (i, txidᵢ, amountᵢ, addr_payloadᵢ) under a different invoice yields a different leaf and root.

    10.8 Examples of partial proofs (formats)

    Example A — single-leaf proof (index 7) { "invoice_hash": "…h_i…", "merkle_root": "…m…", "leaf": { "i": 7, "txid": "…32-byte-hex…", "amount": 1420, "addr_payload": "00…20-byte-h160…" }, "path": [ {"pos": "L", "hash": "…32-byte-hex…"}, {"pos": "R", "hash": "…32-byte-hex…"}, {"pos": "R", "hash": "…32-byte-hex…"} ] }

    Example B — two-leaf independent proofs (indices 3 and 11) [ { "invoice_hash": "…h_i…", "merkle_root": "…m…", "leaf": {"i": 3, "txid": "…", "amount": 600, "addr_payload": "00…"}, "path": [ … ] }, { "invoice_hash": "…h_i…", "merkle_root": "…m…", "leaf": {"i": 11, "txid": "…", "amount": 785, "addr_payload": "00…"}, "path": [ … ] } ]

    Example C — redacted manifest with selective disclosure Manifest (public): { "invoice_hash": "…h_i…", "merkle_root": "…m…", "count": 72, "entries": [ {"i": 0, "txid": "…"}, {"i": 1, "txid": "…"}, … ] } Disclosure: provide Example A for i = 7 only. Verifier checks that the txid in the proof matches the manifest entry for i = 7 and that the recomputed root equals merkle_root.

    10.9 Edge conditions and rejection rules • Reject any proof where the byte encodings (LE32(i), amountᵢ, addr_payloadᵢ) do not match the normative widths and endianness. • Reject if txidᵢ is not a 32-byte value (invalid hex length or characters). • Reject if any path element has an invalid "pos" or a non-32-byte sibling. • Reject if the recomputed root ≠ merkle_root M. • Reject if invoice_hash in the proof ≠ H_I for the invoice under consideration.

    10.10 Construction and logging (normative) • Both parties compute the same M from the same ordered leaf list. • Store merkle_root M, count N, and entries [(i, txidᵢ)] in the manifest. • Optionally sign the manifest with identity keys to authenticate receipt creation: {"sig_key": "<hex serP(Pₐ or Pᵦ)>", "sig_alg": "secp256k1-sha256", "sig": ""} • For each disclosed proof later, store the presented leaf and path alongside the manifest for audit.

    10.11 Deterministic recomputation Given H_I, the derivation rules, and full knowledge of the note set, either party can recompute every preimage and thus M exactly. Given only the manifest and a subset proof, a third party verifies membership of the disclosed leaves without learning the undisclosed ones.

    10.12 Interoperability notes • The use of addr_payload (ver ∥ h160) avoids ambiguity and normalisation issues inherent in Base58 strings and checksums, while remaining consistent with P2PKH addressing. • If an implementation wishes to future-proof for alternative script types, include an extra 1-byte "script_tag" before addr_payloadᵢ to denote the payload format; for this specification, script_tag = 0x00 (P2PKH) and MUST be present if the extension is adopted by both parties.

    1. Failure handling and exact behaviours

    11.1 Overview (normative) Failures are handled deterministically at two levels: per-note and per-invoice. Every transition is recorded in canonical JSON with timestamps and signatures by the acting party’s identity key. All timers are measured in seconds since the Unix epoch; all timestamps are ISO-8601 UTC.

    — Global timers and flags — • τ_hold_max := policy.broadcast.hold_time_max_s (maximum queued time before action). • τ_rebroadcast := policy.broadcast.rebroadcast_interval_s (periodic re-announce). • d_confirm := effective confirmation depth (invoice override or policy default). • expires_at_policy := policy.expiry. • expires_at_invoice := invoice.expiry (if present). • fanout_allowed := implementation/policy toggle; at most one fan-out per invoice. • supersedes flag := indicates a newer transaction version exists for the same index i. • voided_offchain := indicates older raw bytes must not be broadcast.

    11.2 Per-note state machine (textual diagram)

    States: S0 Constructed → S1 Signed → S2 Queued → S3 Broadcast → S4 Seen → S5 Confirmed ↘ R Reissued (loops back to S1) ↘ C Cancelled (terminal) ↘ O Orphaned (from S5; loops to S3 on rebroadcast) ↘ X Obsolete (terminal; older superseded bytes) ↘ F Conflict (terminal; external spend of reserved inputs)

    Transitions (events → new state): • construct(i) → S0 • sign(i) → S1 • enqueue(i) → S2 • t ≥ scheduled_at(i) ∧ authority_either → broadcast(i) → S3 • mempool_accept(i) → S4 • conf_depth(i) ≥ d_confirm → S5 • t − created_at(i) ≥ τ_hold_max ∧ S2 → reissue(i) → R → S1 • explicit_cancel(i) at S0/S1/S2/S3/S4 → C • superseded(i) (new Tᵢ′ built) → old version → X; new version → S1 • external_conflict(Sᵢ) (reserved input spent elsewhere) → F • reorg_orphan(i) at S5 → O → rebroadcast(i) → S3

    Determinism: given identical logs and timers, the same sequence of transitions occurs.

    11.3 Invoice-level state machine (textual diagram)

    I0 Open → I1 Fan-out-Pending (optional) → I2 Building → I3 Ready → I4 Broadcasting → I5 Closing ↘ IF Insufficient-UTXO (terminal failure) ↘ IE Expired (terminal failure) ↘ IS Stopped (operator abort) ↘ IC Completed (terminal success: all i ∈ [0…N−1] in S5)

    Triggers: • accept(policy, invoice) → I0 • fanout_start (if required) → I1 → fanout_confirmed → I2 • reservations_built(R) → I3 • any_broadcast → I4 • all notes S5 → IC • t ≥ expires_at_invoice or t ≥ expires_at_policy → IE • Σ value(U₀) insufficient or granularity impossible after one fan-out → IF

    11.4 Deterministic behaviours by failure class (normative)

    A) Insufficient UTXOs Condition: Σ value(U₀) < Σ a[i] + fees_min, or granularity failure after bounded-knapsack (§6). Action sequence:

    1. If fanout_allowed = true and no prior fan-out: perform exactly one preparatory fan-out (payer→payer) per §6.8; wait per policy (confirm or risk-accepted) deterministically.

    2. Rebuild U₀ from fan-out result; rebuild R.

    3. If still insufficient, set invoice.state := IF and emit failure record; no notes are issued or all outstanding notes are cancelled (see 11.6). Audit: record {"event":"insufficient_utxo","at":…,"fanout_attempted":true|false}.

    B) Fee change before broadcast Condition: either party requires a new fee rate > fee_rate_floor while a note i is S0/S1/S2 and no broadcast has occurred for i. Action sequence:

    1. Reissue i: select new Sᵢ′ (disjoint), recompute fee at requested rate (must be ≥ floor), preserve Addrᴮ,ᵢ and Addrᴬ,ᵢ.

    2. Set NoteMeta[i].supersedes := txid_old; version := version + 1.

    3. Mark old bytes voided_offchain := true and status := "reissued".

    4. New candidate enters S1 (Signed). Audit: append {"i":i,"event":"reissue","supersedes":"<txid_old>","version":v}.

    C) Conflicting spend detected Condition: any u ∈ Sᵢ appears spent on-chain or reserved contradictorily by external wallet mutation while note i ∈ {S0,S1,S2}. Action sequence:

    1. Abort invoice build immediately: invoice.state := I2 (rebuild) or I5 (closing) depending on operator policy.

    2. Invalidate R; take a fresh snapshot U′; rebuild reservations per §6 or fail IF.

    3. For the conflicted note i, mark status := "conflict" and record the offending outpoint. Audit: record {"i":i,"event":"conflict_external","outpoint":{"txid":…,"vout":…},"at":…}. Determinism: any detected conflict forces a full reservation rebuild; partial salvage is not permitted.

    D) Reorg Condition: a confirmed note i (S5) is orphaned by reorganisation (conf_depth falls below d_confirm). Action sequence:

    1. Transition i → O (Orphaned).

    2. Rebroadcast the same raw bytes of Tᵢ (no reconstruction, no re-sign).

    3. Return to S3 (Broadcast) → S4 (Seen) → S5 (Confirmed) as usual. Audit: record {"i":i,"event":"orphaned","rebroadcast":true,"txid":"","at":…}. Constraint: reissue is not permitted for orphaned-but-valid transactions unless they later double-spend fail; first action is always rebroadcast.

    E) Expiry Condition: t ≥ expires_at_invoice or t ≥ expires_at_policy before all notes reach S5. Action sequence:

    1. For every i ∈ {S0,S1,S2}: set status := "cancelled"; release reservations.

    2. For i ∈ {S3,S4}: continue passive monitoring until either confirmed (counted) or timeout set by operator; no new broadcasts after expiry.

    3. Set invoice.state := IE and emit summary record with counts by status. Audit: record {"event":"invoice_expired","at":…,"counts":{"cancelled":…,"broadcast":…,"confirmed":…}}.

    11.5 Timers and automated actions (per note)

    Scheduler tick (every τ_rebroadcast seconds): • If status = "broadcast" ∨ "seen" and conf_depth < d_confirm → rebroadcast raw bytes. • If status = "queued" and t − created_at >= τ_hold_max → reissue(i) (preferred) or cancel(i) per policy. • If status = "signed" and scheduled_at reached → broadcast(i).

    All actions are idempotent: rebroadcasting identical bytes preserves txid; reissuing increments version and voids older bytes.

    11.6 Precise reissue and cancel records (canonical JSON)

    Reissue record (append-only): { "invoice_hash":"", "i":, "note_id":"<hex NoteIDᵢ>", "event":"reissue", "version":, // new version "supersedes":"", "txid_new":"", "addr_recv":"<base58 Addrᴮ,ᵢ>", "addr_change":"<base58 Addrᴬ,ᵢ>", "fee":, "feerate_used":, "at":"", "by":"<hex serP(Pₐ or Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    Cancel record (append-only): { "invoice_hash":"", "i":, "note_id":"<hex NoteIDᵢ>", "event":"cancel", "reason":"hold_timeout|operator|expiry|insufficient_utxo", "version":, "at":"", "by":"<hex serP(Pₐ or Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    Conflict record (append-only): { "invoice_hash":"", "i":, "note_id":"<hex NoteIDᵢ>", "event":"conflict_external", "outpoint":{"txid":"","vout":}, "at":"", "by":"<hex serP(Pₐ or Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    Orphaned record (append-only): { "invoice_hash":"", "i":, "note_id":"<hex NoteIDᵢ>", "event":"orphaned", "txid":"", "rebroadcast":true, "at":"", "by":"<hex serP(Pₐ or Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    11.7 Rejection conditions (must fail immediately) • Attempt to broadcast a superseded version (version < current_version). • Attempt to broadcast after invoice expiry (except passive rebroadcasts of already-broadcast notes until final state is reached). • Attempt to reuse change from one note to fund another note in the same invoice. • Attempt to continue with reservations after detecting external conflict; a full rebuild is mandatory.

    11.8 Determinism and auditability guarantees • Given identical inputs (policy, invoice, {Z,Hᴵ}, U₀) and identical timer parameters, two independent implementations will produce identical reservation tables, note schedules, and failure-handling transitions. • The append-only reissue/cancel logs, combined with NoteMeta and the receipt manifest (§10), are sufficient to reconstruct the exact intended settlement set and to demonstrate that exactly one transaction per index i was designated to settle, with earlier byte serialisations voided before settlement.

    1. Privacy and linkage analysis (bounded disclosures; role separation)

    12.1 Adversary model (explicit) • A₁ — Passive chain analyst: observes full blocks and mempools, parses scripts, amounts, timings, and addresses; cannot break SHA-256, RIPEMD-160, or the secp256k1 discrete-log problem. • A₂ — Passive network observer: sees when and from which IP a transaction is first announced; cannot tamper with payloads. • A₃ — Inquisitive counterparty: one party attempts to learn more than the protocol reveals; has its own keys and transcript but lacks the other party’s secret scalars. • A₄ — Data-broker adversary: correlates public off-chain artefacts (e.g., leaked policies, screenshots, manifests) with on-chain activity. Assumptions: preimage resistance of SHA-256, collision resistance where invoked, and hardness of ECDLP on secp256k1.

    12.2 Role separation and cryptographic domains Identity keys never appear in locking scripts; only settlement keys derived from anchors do. All recipient keys are derived in the “recv” domain: Pᴮ,ᵢ = B + tᵢ·G, tᵢ := int(SHA-256(Z ∥ Hᴵ ∥ "recv" ∥ LE32(i))) mod n, tᵢ ≠ 0. All sender-change keys are derived in the “snd” domain: Pᴬ,ᵢ = A + sᵢ·G, sᵢ := int(SHA-256(Z ∥ Hᴵ ∥ "snd" ∥ LE32(i))) mod n, sᵢ ≠ 0. Domain labels (“recv”, “snd”) and the invoice fingerprint Hᴵ ensure that the same index i across invoices yields unrelated points; identity/settlement separation prevents anchor leakage via off-chain signatures.

    12.3 What an outsider can and cannot infer

    1. Linking recipient addresses across notes (same invoice). Cannot: Without Z and Hᴵ, an outsider cannot recompute tᵢ and so cannot test membership of any address in the set {B + tᵢ·G}. Observing two spends reveals serP(Pᴮ,ᵢ) and serP(Pᴮ,ⱼ), but the relation Pᴮ,ᵢ − Pᴮ,ⱼ = (tᵢ − tⱼ)·G holds for all random points; without tᵢ, tⱼ it gives no anchor linkage. Limit: If the anchor B itself is leaked off-chain and the adversary also learns Z or Hᴵ (both should remain secret), they could regenerate addresses; by design, neither Z nor Hᴵ is published.

    2. Linking across invoices (same payee). Cannot: Hᴵ changes per invoice; tᵢ depends on Hᴵ. Even with B known, without Z the adversary cannot bind addresses to a particular invoice scope. Limit: Long-term address-reuse does not occur; accidental reuse would require tᵢ collision or (b + tᵢ) mod n repeating—negligible under SHA-256 and modular arithmetic.

    3. Change-based clustering within an invoice. Prevented: Change pays to per-note Addrᴬ,ᵢ under “snd”; selection forbids using change from one note to fund another of the same invoice. The common “shared-change” heuristic therefore does not tie notes i and j together. Limit: Each individual note still clusters its own inputs (multi-input heuristic) to the payer, which is acceptable: the payer’s identity is not a privacy target here; recipient unlinkability is.

    (6) Off-chain artefact correlation. Possible: If a policy or manifest leaks publicly (A₄), an adversary learns B and (i, txid) pairs. Limit: txid alone does not reveal amounts or change; B does not reveal kᴮ,ᵢ or tᵢ; receipts commit to data but selective proofs reveal only chosen leaves.

    12.4 Recommended mitigations (no new primitives)

    M₁ — Either-side broadcast. Let the recipient submit a random subset first. This breaks any single-origin heuristic; first-seen IP attribution no longer correlates the whole set to the payer.

    M₂ — Paced or burst scheduling with deterministic jitter. Use the S_pace-derived schedule (§9) to spread announcements over a window. Choose “bursts” with β ≪ N and non-uniform burst gaps to defeat simple time-window clustering.

    M₃ — Wider published bounds than actually used. Bob may publish [v_min_pub, v_max_pub] with v_min ≤ v_min_pub and v_max_pub ≤ v_max; enforce the true internal bounds off-chain. Observers only learn the loose public interval.

    M₄ — Interleave multiple invoices. When operationally feasible, the payer constructs two or more invoices concurrently and interleaves broadcasts. This raises ambiguity without changing any primitive.

    M₅ — Strict no-reuse within invoice. Enforce “no intra-invoice change reuse” and “no cross-note input reuse” (already normative) to preclude standard clustering hooks.

    M₆ — Avoid deterministic time-of-day fingerprints. Do not always start at the top of the hour; salt schedule start with H(Z ∥ Hᴵ ∥ "pace") to vary timing patterns.

    M₇ — Minimal public metadata. Manifests published externally should contain only (i, txid) and the Merkle root M; keep amounts, addresses, and H160 payloads private. Sign manifests with identity keys to prove authorship without revealing anchors.

    12.5 Specific inferences and their limits (tabular)

    Inference: “These outputs belong to the same payer.” Basis: multi-input heuristic per note. Limit: Does not link different notes together; does not link recipient addresses across notes.

    Inference: “These outputs belong to the same payee.” Basis: proximity, equal denominations in [v_min, v_max]. Limit: Without Z and Hᴵ, cannot prove common derivation from B; pacing and interleaving degrade confidence.

    Inference: “This set is one invoice of size T.” Basis: near-simultaneous group of bounded outputs summing to ≈ T. Limit: Pacing plus concurrent invoices makes partitioning NP-hard in practice; receipts reveal only when the payee consents.

    Inference: “These two payee public keys share an anchor B.” Basis: Pᴮ,ᵢ − Pᴮ,ⱼ is some scalar times G. Limit: Trivial in any cyclic group; provides no test for a shared anchor without tᵢ, tⱼ; computing b from B is ECDLP-hard.

    12.6 Residual risks and operator guidance

    R₁ — Broadcast-pattern fingerprinting. Residual risk: sophisticated a₂ correlates bursts over long windows. Guidance: vary β and gaps per invoice; occasionally switch who broadcasts first.

    R₂ — Anchor disclosure. Residual risk: if B is widely published and Z or Hᴵ leaks, address sets become derivable. Guidance: treat Z and Hᴵ as confidential; never publish invoice JSON or transcripts; rotate anchors periodically (operational) without changing identity keys.

    R₃ — Wallet hygiene. Residual risk: accidental reuse if software ignores reject-zero logic or mis-scopes derivations. Guidance: enforce reject-zero; unit tests that re-derive all Pᴮ,ᵢ and Pᴬ,ᵢ from logs; fail closed on any mismatch.

    Summary. Outsiders cannot link recipient addresses across notes or invoices because identity keys never appear on-chain and per-note keys require {Z, H_I} with domain separation. Amount bounds leak a coarse interval; pacing, interleaving, and wider published bounds blunt inference. Change addresses are per-note under “snd”, eliminating shared-change clustering. All recommendations require no new primitives—only deterministic use of the ones already defined.

    1. Security considerations (keys, transcripts, and logs)

    13.1 Key domains and separation (normative) • Identity (off-chain): Kₐ = (kₐ, Pₐ), Kᵦ = (kᵦ, Pᵦ). Purpose: authenticate messages; sign policy, invoice, and logs. Identity keys MUST NEVER appear in locking scripts or be used to spend on-chain funds. • Anchors (on-chain bases): A = a·G (sender change domain), B = b·G (recipient receive domain). Purpose: derive settlement keys per invoice and per note. Anchor private scalars (a, b) MUST NEVER sign off-chain identity artefacts. • Scope tuple: {Z, Hᴵ}. Z := ECDH(kₐ, Pᵦ) = ECDH(kᵦ, Pₐ) (32-byte x-coordinate). Hᴵ := H(canonical_json(invoice)). Hᴵ MUST be unique per invoice and MUST NOT be reused. Z SHOULD be recomputed on demand and SHOULD NOT be stored at rest unless encrypted under an operator-controlled mechanism (implementation policy).

    13.2 Key-handling checklist (operational) ✓ Generate identity and anchor keys on distinct cryptographic modules or profiles. ✓ Store kₐ, kᵦ, a, b in separate sealed locations; never co-reside identity and anchor secrets for the same principal on the same soft-keystore without OS isolation. ✓ Export only compressed public keys (serP) to peers; never export private material. ✓ Enforce constant-time scalar use; disable debug traces of secret scalars. ✓ Back up identity keys (kₐ, kᵦ) with out-of-band recovery; back up anchors (a, b) with the same or stronger controls; record public anchors (A, B) separately for verification. ✓ Rotate anchors periodically (operational policy) and immediately on suspected compromise; old anchors remain valid only for historical settlement and verification. ✓ Bind every signed artefact to the exact canonical JSON bytes; do not sign ad hoc serialisations. ✓ Treat transcripts and logs as confidential; encrypt at rest per environment policy; access is least-privilege. ✓ Never reuse Hᴵ; never derive keys or amounts without {Z, Hᴵ} and the correct domain label (“recv”, “snd”). ✓ Refuse to proceed if any signature verification or canonicalisation check fails.

    13.3 Compromise impact summary • kₐ or kᵦ compromised → attacker can forge off-chain messages/logs for that identity; on-chain funds unaffected; rotate identity key; rebind future policies/invoices; mark prior logs with rotation event. • a (sender anchor) compromised → attacker can spend sender change if they control UTXOs addressed to Pᴬ,ᵢ; recipient funds unaffected; rotate A, quarantine outstanding change, rebuild change policy. • b (recipient anchor) compromised → attacker may spend future notes to Addrᴮ,ᵢ; rotate B immediately; cease using the compromised anchor; existing receipts remain valid.

    13.4 Log and transcript principles • Canonical JSON only: UTF-8, NFC, sorted keys, no extraneous whitespace (see §2). • Detached signatures: every signed record includes {"sig_key","sig_alg","sig"} where the signature is computed over the canonical bytes of the record with the signature triplet omitted from the preimage. • Append-only: logs are monotone sequences with sequence numbers and a hash-chain (“prev_hash”) for tamper evidence. • Append-only: logs are monotone sequences with sequence numbers and a hash-chain (“prev_hash”) for tamper evidence. • Append-only: logs are monotone sequences with sequence numbers and a hash-chain (“prev_hash”) for tamper evidence. • Append-only: logs are monotone sequences with sequence numbers and a hash-chain (“prev_hash”) for tamper evidence.

    13.5 Signature placement (normative) • Policy (Bob) — signed by kᵦ. • Invoice (Alice) — signed by kₐ. • Reservation table R and per-note NoteMeta updates — signed by the party performing the action (payer when constructing/funding; either when broadcasting). • Receipt manifest (Merkle root M) — at least signed by the recipient; co-signature by the payer is RECOMMENDED for bilateral acknowledgement. • Reissue / cancel / conflict / orphan records — signed by the actor identity key initiating the state change.

    13.6 Core log schemas (canonical JSON; required fields; sorted keys)

    A) Key registry (local, not exchanged) { "anchors": { "payer": {"pub":"<hex serP(A)>"}, "payee": {"pub":"<hex serP(B)>"} }, "identities": { "payer": {"pub":"<hex serP(Pₐ)>"}, "payee": {"pub":"<hex serP(Pᵦ)>"} }, "created_at":"", "sig_alg":"secp256k1-sha256", "sig_key":"<hex serP(Pₐ or Pᵦ)>", "sig":"" }

    B) Policy record (Bob → Alice) — as §3.3 plus envelope { "policy": { …canonical policy object per §3.3… }, "hash":"", "record_type":"policy_record", "prev_hash":"<hex|"">", "seq":, "created_at":"", "sig_key":"<hex serP(Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    C) Invoice record (Alice → Bob) — as §3.4 plus envelope { "invoice": { …canonical invoice object per §3.4… }, "invoice_hash":"<hex Hᴵ>", "record_type":"invoice_record", "prev_hash":"", "seq":, "created_at":"", "sig_key":"<hex serP(Pₐ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    D) Reservation table (payer, deterministic R) — summary plus per-note entries { "invoice_hash":"<hex Hᴵ>", "record_type":"reservations", "entries":[ { "i":, "note_id":"<hex NoteIDᵢ>", "inputs":[{"txid":"","vout":,"value":}], "sum_inputs":, "feerate_used":, "created_at":"" }, … ], "prev_hash":"", "seq":, "sig_key":"<hex serP(Pₐ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    E) NoteMeta (per note; extends §8.3 with lifecycle) { "i":, "note_id":"", "invoice_hash":"<hex Hᴵ>", "addr":"<base58 Addrᴮ,ᵢ>", "amount":, "txid":"<hex|"">", "change_addr":"<base58 Addrᴬ,ᵢ|"">", "change_amount":, "size_bytes":, "fee":, "feerate_used":, "inputs": [ {"txid":"","vout":,"value":,"scriptPubKey":""} ], "outputs": [ {"addr":"","value":}, {"addr":"","value":}? ], "sig_alg": "secp256k1-sha256", "created_at": "", "updated_at": "", "prev_hash":"", "seq":, "sig_key":"<hex serP(Pₐ or Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    F) Receipt manifest (Merkle root M) — see §10; repeated here with envelope { "invoice_hash":"<hex Hᴵ>", "merkle_root":"", "count":, "entries":[{"i":,"txid":""}…], "record_type":"receipt_manifest", "prev_hash":"", "seq":, "created_at":"", "sig_key":"<hex serP(Pᵦ)>", "sig_alg":"secp256k1-sha256", "sig":"" }

    G) Event records (reissue / cancel / conflict / orphan) — see §11.6; all include {invoice_hash, i, note_id, prev_hash, seq, created_at, sig_key, sig_alg, sig}.

    13.7 Transcript chaining (tamper evidence) Each persisted record Rₖ includes "prev_hash" = H(canonical_bytes(Rₖ₋₁ without its signature triplet)) and "seq" = seqₖ₋₁ + 1. A daily (or per-invoice) journal root J := MerkleRoot( H(canonical_bytes(Rₖ)) for all k in window ) MAY be published or anchored externally to provide a timestamped, tamper-evident commitment to the log without revealing contents.

    13.8 Retention and export • Retain logs and manifests for the statutory/accounting horizon; redact only where policy permits. • Export is the ordered canonical JSON stream with signatures; verification replays the hash-chain and signatures, recomputes R, NoteMeta, and M, and checks that exactly one final transaction per i reached "confirmed".

    13.9 Conformance (must-pass checks) • Identity/anchor separation enforced at API boundaries (no cross-domain signing). • Hᴵ uniqueness per invoice; refusal to load or write logs if an Hᴵ collision is detected. • All signatures verify over canonical bytes; any failure halts processing. • Hash-chain continuity: each "prev_hash" matches the prior record; gaps or forks are rejected unless explicitly marked as a rotated journal with a signed boundary record.

    This section specifies the mandatory operational controls for key isolation and the precise, signed, append-only logging required to reconstruct, verify, and audit every invoice, note, and receipt without exposing identity keys on-chain.

    1. Minimal message frames (UTF-8 JSON; canonical where hashed)

    14.1 Policy (Bob → Alice)

    Wire frame (compact):

    {"pk_anchor":"", "vmin":, "vmax":, "feerate_floor":, "expiry":"", "sig":""}

    Canonical field order (for signature preimage): expiry, feerate_floor, pk_anchor, vmax, vmin (“sig” is excluded from the preimage)

    Signature input (bytes to sign): canonical_json({pk_anchor, vmin, vmax, feerate_floor, expiry}) → SHA-256 → ECDSA sign with K_B.

    Verification rules (normative): • pk_anchor is 33-byte SEC1 compressed hex (0x02/0x03 + 32-byte x), on-curve. • vmin ≥ 1, vmax ≥ vmin, feerate_floor ≥ 1; expiry is future UTC. • Verify sig with P_B over SHA-256(canonical_json(policy_without_sig)). • H_policy := SHA-256(canonical_json(policy_with_sig)) is the policy hash used by the invoice. • Canonical JSON per §2 (UTF-8, NFC strings, sorted keys, no extra whitespace).

    14.2 Invoice (Alice → Bob)

    Wire frame (compact):

    {"invoice_number":"", "terms":"", "unit":"", "total":, "policy_hash":"<hex 32-byte H_policy>", "expiry":"", "sig":""}

    Canonical field order (for signature preimage): expiry, invoice_number, policy_hash, terms, total, unit (“sig” is excluded from the preimage)

    Signature input (bytes to sign): canonical_json({invoice_number, terms, unit, total, policy_hash, expiry}) → SHA-256 → ECDSA sign with K_A.

    Verification rules (normative): • total ≥ 1; policy_hash equals H_policy from the accepted policy (14.1). • Verify sig with P_A over SHA-256(canonical_json(invoice_without_sig)). • H_I := SHA-256(canonical_json(invoice_with_sig)) is the invoice fingerprint for all derivations. • If expiry is present, it MUST be future UTC at acceptance.

    14.3 NoteMeta (optional to exchange; log/audit)

    Wire frame (compact):

    {"i":"", "addr":"", "amount":"", "invoice_hash":"<hex 32-byte H_I>", "txid":"<hex 32-byte>"}

    Canonical field order (when hashing/recording): addr, amount, i, invoice_hash, txid

    Verification rules (normative): • i ∈ [0, 2³²−1]; amount ≥ 1. • addr decodes to version 0x00 and a 20-byte payload. • txid is 32-byte hex (big-endian textual form). • invoice_hash equals H_I for this invoice. • addr must equal Addr_B,i derived from {Z, H_I, i, B} (sender/recipient can recompute). • Optional signatures over NoteMeta (if used) are made with the actor’s identity key over SHA-256(canonical_json(NoteMeta_without_sig)).

    14.4 Canonical JSON recap (applies wherever “canonical_json” is referenced)

    UTF-8 encoding; no BOM; all strings NFC-normalised. • Keys sorted lexicographically by Unicode code point. • No insignificant whitespace (compact objects/arrays). • Integers in base-10 without leading zeros (except “0”). • Hex fields are lowercase, no “0x”. • Timestamps are ISO-8601 with “Z”.

    14.5 Cross-checks (receiver MUST perform)

    Policy:

    1. Parse and validate fields; verify ECDSA(sig, SHA-256(canonical_json(policy_without_sig)), P_B).

    2. Compute H_policy = SHA-256(canonical_json(policy_with_sig)).

    Invoice:

    1. Verify policy_hash = H_policy.

    2. Verify ECDSA(sig, SHA-256(canonical_json(invoice_without_sig)), P_A).

    3. Compute H_I = SHA-256(canonical_json(invoice_with_sig)) and cache {Z, H_I} for derivations.

    NoteMeta (if exchanged):

    1. Verify invoice_hash = H_I.

    2. Recompute Addr_B,i; check equality.

    3. Optionally verify txid exists or matches a provided raw transaction.

    All frames are minimal by design; anything not explicitly listed is out of scope and MUST be omitted.

    1. Reference pseudocode

    Per-note recipient key (sender view)

    Z := ECDH(k_A, K_B) # 32-byte x-coordinate H_I := SHA256(canonical_json(invoice)) # invoice fingerprint

    t_i := int( SHA256( Z ∥ H_I ∥ "recv" ∥ LE32(i) ) ) mod n if t_i = 0: ctr := 1 repeat: t_i := int( SHA256( Z ∥ H_I ∥ "recv" ∥ LE32(i) ∥ LE32(ctr) ) ) mod n ctr := ctr + 1 until t_i ≠ 0

    P_Bi := point_add( B, scalar_mul(t_i, G) ) addrB_i := Base58Check( 0x00 ∥ RIPEMD160( SHA256( serP(P_Bi) ) ) )

    Per-note sender change (payer view)

    s_i := int( SHA256( Z ∥ H_I ∥ "snd" ∥ LE32(i) ) ) mod n if s_i = 0: ctr := 1 repeat: s_i := int( SHA256( Z ∥ H_I ∥ "snd" ∥ LE32(i) ∥ LE32(ctr) ) ) mod n ctr := ctr + 1 until s_i ≠ 0

    P_Ai := point_add( A, scalar_mul(s_i, G) ) addrA_i := Base58Check( 0x00 ∥ RIPEMD160( SHA256( serP(P_Ai) ) ) )

    Bounded split (exact sum)

    S := SHA256( Z ∥ H_I ∥ "split" ) S_perm := SHA256( S ∥ "permute" )

    function next_u64(seed, ctr): R := SHA256( seed ∥ LE32(ctr) ) ctr := ctr + 1 return (first 8 bytes of R as uint64), ctr

    function draw_uniform(seed, ctr, range): # unbiased draw in [0, range−1] M := 2^64 lim := (M ÷ range) × range loop: (u, ctr) := next_u64(seed, ctr) if u < lim: return (u mod range), ctr

    Nmin := ceil(T ÷ v_max) Nmax := floor(T ÷ v_min) N := choose_count(S, Nmin, Nmax) # deterministic, interior-biased

    rem := T ctr := 0 for i in 0 … N−2: slots := N−1−i low := max( v_min, rem − v_max × slots ) high := min( v_max, rem − v_min × slots ) (r, ctr) := draw_uniform(S, ctr, high − low + 1) a[i] := low + r rem := rem − a[i] a[N−1] := rem

    Fisher–Yates permutation to decorrelate indices from sizes

    ctrp := 0 for j in (N−1) down to 1: (r, ctrp) := draw_uniform(S_perm, ctrp, j + 1) swap a[j] ↔ a[r]

    Coin selection with reservation

    U := snapshot_available_utxos() payer-owned, spendable, filtered R := {} reservation table: i ↦ S_i

    for i in note_indices_in_fixed_order(): e.g., by descending a[i], then i target := a[i] (S_i, fee, change) := select_inputs_disjoint(U, target, feerate_floor, dust) R[i] := S_i U := U \ S_i remove reserved inputs (strict non-overlap)

    Change arithmetic and size estimate

    m inputs, n outputs

    (n ∈ {1,2}); P2PKH sizes size_bytes(m, n) := 10 + 148×m + 34×n fee(m, n) := ceil( feerate_floor × size_bytes(m, n) )

    sum_in := Σ value(input ∈ S_i) target := a[i]

    Try no-change first

    fee1 := fee(m=|S_i|, n=1) if sum_in = target + fee1: outputs := [ (addrB_i, target) ] # exact match, n = 1 else: fee2 := fee(m=|S_i|, n=2) change := sum_in − target − fee2 if change ≥ dust: outputs := [ (addrB_i, target), (addrA_i, change) ] # n = 2 elif 0 < change < dust: reseat_inputs() # add/select different inputs; recompute else: # change ≤ 0 reseat_inputs() # underfunded; add/select different inputs

    1. Worked-through flow (illustrative only)

    Step 0 — Preconditions • Alice (payer): identity K_A = (k_A, P_A); sender anchor A = a·G. • Bob (payee): identity K_B = (k_B, P_B); recipient anchor B = b·G. • All amounts are in the smallest settlement unit. This slice uses N = 7 notes for readability; amounts remain symbolic (a₀…a₆) and are illustrative only.

    Step 1 — Policy exchange (Bob → Alice) Bob sends a canonical Policy JSON; Alice verifies signature and computes H_policy. Example (placeholders only):

    {"pk_anchor":"<hex serP(B)>", "vmin":<v_min>, "vmax":<v_max>, "feerate_floor":, "expiry":"", "sig":""}

    Alice verifies pk_anchor structure, bounds, feerate_floor, expiry, and sig(K_B).

    Step 2 — Invoice issuance (Alice → Bob) Alice issues a canonical Invoice JSON referencing H_policy; Bob verifies and computes H_I:

    {"invoice_number":"", "terms":"", "unit":"", "total":, "policy_hash":"", "expiry":"", "sig":""}

    Both parties compute the per-invoice scope: • Z := ECDH(k_A, K_B) = ECDH(k_B, K_A) (32-byte x-coordinate). • H_I := SHA-256(canonical_json(invoice)). All subsequent derivations are functions of {Z, H_I}.

    Step 3 — Bounded split (deterministic; exact sum) Seed S := SHA-256( Z ∥ H_I ∥ "split" ). Compute N_min := ⌈T ÷ v_max⌉, N_max := ⌊T ÷ v_min⌋; choose N ∈ [N_min, N_max] deterministically (interior-biased). For this slice, N = 7. Compute a vector a = (a₀, a₁, …, a₆) with v_min ≤ aᵢ ≤ v_max and Σ aᵢ = T using prefix clamping; then apply a seeded Fisher–Yates permutation with S_perm := H(S ∥ "permute"). Both parties obtain identical (N, a) without exchanging per-note amounts.

    Step 4 — Reservation build (disjoint funding) Alice snapshots her UTXO pool U₀ and constructs a reservation table R with pairwise disjoint input sets Sᵢ. Deterministic ordering: fund larger aᵢ first; UTXOs iterated in fixed (value↑, txid↑, vout↑) order. For illustration: • S₀ = {u_3, u_9} • S₁ = {u_1} • S₂ = {u_5, u_7, u_12} • S₃ = {u_8} • S₄ = {u_2, u_10} • S₅ = {u_4} • S₆ = {u_6, u_11} with Sᵢ ∩ Sⱼ = ∅ for all i ≠ j. Exact members and values are determined by the bounded-knapsack policy (§6). Size/fee are computed at feerate_floor; candidates producing dust change are rejected or reseated.

    Step 5 — Per-note addresses (recipient and change) For each index i = 0…6:

    Recipient (sender view): • tᵢ := int( SHA-256( Z ∥ H_I ∥ "recv" ∥ LE32(i) ) ) mod n; if tᵢ = 0, bump ctr deterministically until non-zero. • P_B,i := B + tᵢ·G; Addr_B,i := Base58Check( 0x00 ∥ H160( serP(P_B,i) ) ).

    Sender change (payer view): • sᵢ := int( SHA-256( Z ∥ H_I ∥ "snd" ∥ LE32(i) ) ) mod n; if sᵢ = 0, bump ctr deterministically until non-zero. • P_A,i := A + sᵢ·G; Addr_A,i := Base58Check( 0x00 ∥ H160( serP(P_A,i) ) ).

    All Addr_B,i are unique per note; all Addr_A,i are unique per note; identity keys never appear on-chain.

    Step 6 — Transaction construction (one per note) For each i:

    Inputs: Sᵢ (reserved). Let m = |Sᵢ|, sum_in = Σ value(Sᵢ). Outputs: primary (Addr_B,i, aᵢ); optional change (Addr_A,i, changeᵢ).

    Fee/change arithmetic (deterministic at floor): • size1 ≈ 10 + 148·m + 34; fee1 := ceil(floor × size1). If sum_in = aᵢ + fee1 → 1-output note (no change). • Else size2 ≈ 10 + 148·m + 68; fee2 := ceil(floor × size2). changeᵢ := sum_in − aᵢ − fee2; require changeᵢ = 0 or changeᵢ ≥ dust. If 0 < changeᵢ < dust or changeᵢ ≤ 0 → reseat inputs.

    Build legacy P2PKH transaction Tᵢ with deterministic input order; sign every input under SIGHASH_ALL. Compute txidᵢ = dSHA256(serialisation). Record NoteMetaᵢ := {"i": i, "note_id": H(H_I ∥ LE32(i)), "invoice_hash": H_I, "addr": Addr_B,i, "amount": aᵢ, "txid": txidᵢ, …}.

    Result: seven independent, fully valid transactions {T₀…T₆}, each paying aᵢ to Addr_B,i and (if present) change to Addr_A,i; no input overlaps; no change overlaps within the invoice.

    Step 7 — Either-side broadcast and pacing Broadcast authority is “either”. Seed S_pace := H( Z ∥ H_I ∥ "pace" ); compute a paced schedule within policy bounds (min/max spacing or bursts). Either party may submit any subset in any order; duplicate submission of identical bytes is benign. Confirmation depth d from policy defines settlement for each note independently.

    Step 8 — Receipts and commitment (Merkle root) For i = 0…6, construct leaves: • preimageᵢ := "leaf" ∥ LE32(i) ∥ txidᵢ (32 bytes) ∥ amountᵢ (8-byte LE) ∥ addr_payloadᵢ (0x00 ∥ 20-byte H160). • Lᵢ := SHA-256(preimageᵢ). Compute M := MerkleRoot([L₀, L₁, …, L₆]) with Bitcoin-style odd-leaf duplication. Persist a manifest:

    {"invoice_hash":"", "merkle_root":"", "count":7, "entries":[ {"i":0,"txid":""}, {"i":1,"txid":""}, {"i":2,"txid":""}, {"i":3,"txid":""}, {"i":4,"txid":""}, {"i":5,"txid":""}, {"i":6,"txid":""} ]}

    Selective proof example (index 3 only; placeholders):

    {"invoice_hash":"", "merkle_root":"", "leaf":{"i":3, "txid":"", "amount":<a_3>, "addr_payload":"00<20-byte-h160-hex>"}, "path":[ {"pos":"L","hash":""}, {"pos":"R","hash":""}, {"pos":"R","hash":""} ]}

    A verifier recomputes L₃ and folds the path to M; no information about i ≠ 3 is revealed.

    Step 9 — Reissue before broadcast (fee update example) Suppose, prior to any broadcast, a higher effective fee is desired for i = 5. Procedure:

    1. Release reservation S₅; select a new disjoint S₅′; recompute fee at the new rate (≥ floor) (preserve Addr_B,5, Addr_A,5).

    2. Build and sign T₅′; compute txid₅′.

    3. Update NoteMeta₅:

    {"i":5, "note_id":"", "invoice_hash":"", "version":2, "supersedes":"", "txid":"", "status":"signed"}

    Only the latest version is eligible for broadcast; older txid₅ is not propagated.

    Step 10 — Settlement and closure As notes are announced (by either party) and reach ≥ d confirmations to their respective Addr_B,i, statuses become “confirmed”. Orphaned confirmations (reorg) trigger rebroadcast of the same raw bytes until reconfirmed. When all seven notes are confirmed (or when the invoice expires, cancelling any remaining queued notes), the invoice is closed. The audit trail consists of: the signed Policy and Invoice, H_I, the deterministic split a[·], the reservation table R, per-note NoteMeta with txidᵢ, the Merkle root M and manifest, and any reissue/cancel records. Every note in the slice has a disjoint input set Sᵢ, a unique recipient address Addr_B,i, and—where applicable—a unique sender change address Addr_A,i.

    1. Testing and verification

    17.1 Scope Verify correctness, determinism, and auditability for a complete invoice lifecycle. All tests operate on canonical UTF-8 JSON, secp256k1 over compressed keys, and the invoice scope {Z, Hᴵ}.

    17.2 Required fixtures (deterministic) • Keys – Identity: Kₐ = (kₐ, Pₐ), Kᵦ = (kᵦ, Pᵦ). – Anchors: A = a·G, B = b·G (a ≠ kₐ, b ≠ kᵦ). • Policy (canonical JSON) with fields per §3.3 and valid ECDSA by kᵦ. • Invoice (canonical JSON) referencing H_policy, valid ECDSA by kₐ; compute Hᴵ := H(canonical_json(invoice)). • UTXO snapshots U₀ covering edge cases: – exact-match inputs; – “just-over” inputs that yield valid ≥ dust change; – coarse inputs forcing fan-out; – conflicting external spend (simulated) on a reserved outpoint on a reserved outpoint. • Parameters: v_min, v_max, fee_rate_floor, dust, expiry, d (confirm depth). • Golden PRNG seeds are implicit: derived from {Z, Hᴵ} per spec; no external RNG.

    17.3 Property tests (must hold)

    P1 — Sums and bounds (split). For hundreds of randomly chosen feasible triples (T, v_min, v_max): • Compute N_min := ⌈T/v_max⌉, N_max := ⌊T/v_min⌋; run the split (§5). • Assert: N_min ≤ N ≤ N_max; ∑ᵢ a[i] = T; ∀i: v_min ≤ a[i] ≤ v_max. • Re-run: identical a (before permutation) and identical permuted a.

    P2 — Address agreement (recipient). For i = 0…N−1: • Sender computes Pᴮ,ᵢ, Addrᴮ,ᵢ from {Z, Hᴵ, B, i}. • Recipient computes kᴮ,ᵢ := (b + tᵢ) mod n; check kᴮ,ᵢ·G = Pᴮ,ᵢ. • Assert identical Addrᴮ,ᵢ at both ends.

    P3 — Disjoint reservations. Build R from U₀ and a[·] (§6). • Assert Sᵢ ∩ Sⱼ = ∅ for all i ≠ j; • Assert every input used appears in exactly one Sᵢ; • Assert deterministic reproducibility: rebuild(R) equals prior R byte-for-byte.

    P4 — Non-overlapping change. For all notes that produce change: • Derive Addrᴬ,ᵢ (§7); assert Addrᴬ,ᵢ ≠ Addrᴬ,ⱼ for i ≠ j; • Assert no change UTXO from note i is admitted to the funding pool while invoice open. • Assert transactions meet dust and fee-floor rules; otherwise reseat inputs.

    P5 — Reissue invariants. For a pre-broadcast fee update on index i: • Build Tᵢ, then reissue Tᵢ′ at higher fee. • Assert: i unchanged; NoteIDᵢ unchanged; Addrᴮ,ᵢ unchanged; Addrᴬ,ᵢ unchanged; txidᵢ ≠ txidᵢ′; prior bytes flagged superseded and never broadcast.

    P6 — Receipts. Construct leaves Lᵢ and root M (§10). • For random S ⊂ {0…N−1}, produce single-leaf proofs and verify to M. • If multi-proof implemented, verify shared-sibling structure; otherwise independent proofs suffice. • Manifest { (i, txidᵢ) } + M must match recomputation.

    P7 — Rebuild from logs. Given only signed logs (policy, invoice, reservations, NoteMeta, receipt manifest): • Verify signatures, canonical JSON, and hash-chain “prev_hash”. • Recompute H_policy, Hᴵ, Z. • Recompute a[·], Addrᴮ,ᵢ, Addrᴬ,ᵢ; rebuild R from the logged U₀ snapshot and parameters; • Reconstruct or fetch raw Tᵢ, recompute txid_i. • Check lifecycle: supersedes chain, statuses, timers consistent with §9–§11. All asserts must pass without external oracles.

    17.4 Negative / failure tests (must reject)

    N1 — Infeasible invoice. Choose T, v_min, v_max with ⌈T/v_max⌉ > ⌊T/v_min⌋ → split must fail early.

    N2 — Canonicalisation break. Permute JSON key order or add whitespace → signatures fail; H_policy/Hᴵ differ; reject.

    N3 — Scope misuse. Attempt derivation without {Z, Hᴵ} or with wrong domain label (“recv” vs “snd”) → derived addresses mismatch; reject.

    N4 — Zero-scalar forcing. Artificially search i such that tᵢ = 0 or sᵢ = 0; verify deterministic counter-bump produces non-zero and stable i mapping; log counter used.

    N5 — Reservation overlap. Mutate R to place same outpoint in two Sᵢ → builder must detect and fail.

    N6 — Dust/fee violations. Construct candidates with change ∈ (0, dust) or fee < fee_floor × size → must reseat or fail.

    N7 — Conflicting external spend. Mark a reserved input as spent elsewhere → builder must abort and rebuild R (§11).

    N8 — Expiry and stale notes. Advance clock beyond invoice/policy expiry → queued notes become “cancelled”; no new broadcasts permitted.

    17.5 Rebuild procedure from logs (normative)

    Inputs: append-only, signed, canonical JSON records per §13 (policy_record, invoice_record, reservations, NoteMeta*, receipt_manifest, event records).

    Procedure:

    1. Verify hash-chain: for each record R_k, check prev_hash = H(bytes(R_{k−1} \ sigtriplet)).

    2. Verify signatures by the stated sig_key over canonical bytes (without sigtriplet).

    3. Extract policy → compute H_policy; extract invoice → verify policy_hash and compute H_I.

    4. Recompute Z from K_A, K_B.

    17.6 Golden vectors and cross-impl determinism Publish at least two golden invoices (small and large N) with: policy, invoice, H_policy, H_I, Z (hex), a[·], R (outpoints), (Addr_B,i, Addr_A,i), txidᵢ, M, and selective proofs. Independent implementations must reproduce these byte-for-byte.

    17.7 Fuzzing and coverage (recommended) • Fuzz (T, v_min, v_max) under feasibility; run P1–P6. • Fuzz U₀ distributions (heavy-tail, uniform, clustered). • Randomly trigger reissue, conflict, expiry. • Target ≥ 95 % branch coverage across split, reservation, fee/change, and receipt code paths.

    17.8 CI gating (pass/fail) A build is releasable only if: P1–P7 pass; N1–N8 reject as specified; golden vectors match; rebuild-from-logs produces identical outputs including R, addresses, txids, and M.

    "feerate_floor": integer — minimum fee-rate in units-per-byte (smallest unit per virtual byte), feerate_floor ≥ 1.

  • "expiry": string — ISO-8601 UTC, e.g., "2025-08-26T00:00:00Z".

  • "sig_key": string — hex(serP(Pᵦ)), Bob’s identity public key in compressed SEC1 hex.

  • "sig_alg": string — "secp256k1-sha256".

  • "sig": string — hex(ECDSAₖᵦ(SHA-256(canonical_json(policy_without_sig_fields)))).

  • "policy_hash": string — hex(H_policy) computed from the accepted policy in §3.3.

  • "expiry": string — ISO-8601 UTC, optional but recommended; if present, MUST be in the future.

  • "sig_key": string — hex(serP(Pₐ)), Alice’s identity public key in compressed SEC1 hex.

  • "sig_alg": string — "secp256k1-sha256".

  • "sig": string — hex(ECDSAₖₐ(SHA-256(canonical_json(invoice_without_sig_fields)))).

  • Both compute Z := ECDH(kₐ, Pᵦ) = ECDH(kᵦ, Pₐ). The tuple {Z, Hᴵ} is recorded as the sole cryptographic scope for this invoice. Any per-note recipient key, sender change key, amount split, label, reservation lock, or receipt root that does not include {Z, Hᴵ} in its preimage MUST be rejected.

  • Output (Pᴮ,ᵢ, addrᴮ,ᵢ) for index i.

  • Stage D — fewest-inputs minimal-overshoot Increase m from 2 to M_max (M_max default 6). For each m, run a greedy bounded-knapsack over U₀ \ Used (largest-first or meet-in-the-middle for m≤4) to find C with Σ value(C) ≥ target + fee_m₂ where fee_m₂ := feerate_floor × (10 + 148·m + 34·2). Among feasible C, minimise overshoot := Σ value(C) − (target + fee_m₂) subject to overshoot = 0 or overshoot ≥ δ_dust. Choose the C with smallest m then smallest overshoot. Set best := C if found.

  • Commit if best = ⊥: goto FailureForI m := |best| n := 1 if Σ value(best) = target + feerate_floor×(10 + 148·m + 34·1) else 2 fee := feerate_floor × (10 + 148·m + 34·n) sum_in := Σ value(best) if n = 1: change := 0 else: change := sum_in − target − fee if change < δ_dust: // attempt to repair by adding one more input once pick the smallest u′ ∈ U₀ \ Used \ best if u′ exists: recompute m, n=2, fee, change; if change ≥ δ_dust accept; else discard u′ and continue Stage D if no repair possible: goto FailureForI R[i] := best mark all u ∈ best as reserved(i); Used := Used ∪ best continue with next i

  • Fee and dust validation. Verify the size estimate and fee satisfy the fee-rate floor; verify no output < δ_dust (§7).

  • Signing scope. For each input j = 0…m−1, construct the legacy SIGHASH preimage for SIGHASH_ALL: – Start from the transaction template with all scriptSig empty. – Replace the scriptSig of input j with the exact previous locking script (the P2PKH scriptPubKey of the UTXO referenced by Sᵢ[j]). – Append the 4-byte SIGHASH type 0x00000001 (little-endian). – Double-hash with SHA-256 to obtain zⱼ. – Produce a deterministic ECDSA signature σⱼ over zⱼ using the private key that controls Sᵢ[j], with low-s normalisation; append one-byte hash type 0x01 to σⱼ. – Set scriptSigⱼ := <PUSH σⱼ> <PUSH serP(Pⱼ)>, where Pⱼ is the corresponding public key.

  • Final serialisation and txid. Serialise the fully signed transaction using Bitcoin legacy (non-SegWit) encoding. Define txidᵢ := SHA-256(SHA-256(serialised_bytes)), expressed as 32-byte hash (displayed big-endian; stored and relayed as little-endian in prevouts). The note transaction Tᵢ is now complete and valid in isolation.

  • Deterministic labelling. Compute NoteIDᵢ := H(Hᴵ ∥ LE32(i)). Associate NoteIDᵢ with Tᵢ in logs and manifests.

  • Update NoteMeta[i] with fields: "supersedes": "", "version": <prev_version + 1>, "txid": "", "status": "signed".

  • Update the old raw bytes as voided_offchain = true and "status": "reissued".

  • Persist an append-only audit record of the transition.

  • Amount and bounds leakage. Possible: When many notes are broadcast close in time, an observer may infer that outputs lie in [v_min, v_max] and approximate N by histogramming. Limit: Exact partition a[·] remains hidden off-chain; permutation decouples indices from sizes; paced broadcast blurs simultaneity.

  • Timing linkage. Possible: If all notes are broadcast at once from a single IP, a₁/a₂ can cluster them temporally and by origin peer. Mitigation below: either-side broadcast; paced or bursty schedules; diverse first-announcers.

  • Recompute split a[·] from {Z, H_I, v_min, v_max} (and permutation).

  • Rebuild R deterministically from logged U₀ snapshot and parameters; compare to logged reservations.

  • For each i: a. Derive Addr_B,i and Addr_A,i; compare to NoteMeta (if present). b. Reconstruct tx template from NoteMeta.inputs/outputs or fetch raw tx; recompute txid_i. c. Check lifecycle: supersedes chain, statuses, timers consistent with §9–§11.

  • Recompute leaves L_i and Merkle root M; match receipt_manifest.merkle_root.

  • Emit a verification report listing all assertions; fail on first discrepancy.

  • Unified, Vendor-Neutral, Unchanging, and Open BSV Blockchain Standard Wallet-to-Application Interface

    • Ty Everett ([email protected])

    • Tone Engel ([email protected])

    • Brayden Langley ([email protected])

    Abstract

    We define the BSV Blockchain's standard wallet-to-application interface. This interface defines a robust and secure communication protocol between BSV wallets and applications. This protocol, built on the MetaNet architectural principles, aims to standardize the interaction between wallets and decentralized applications in the BSV ecosystem. The interface is designed to be vendor-neutral, supporting a wide range of implementations, ensuring interoperability, and promoting openness across different wallet and app vendors.

    Motivation

    Computing has long been subject to shortfalls in the areas of information centralization and architectural cross-compatibility. Users on the internet struggle with complex and insecure authentication systems which leave them vulnerable and leak their data. Websites rely on advertising to monetize their offerings, but ads warp the incentives of platforms and creators in ways that ultimately harm everyone involved. By defining a standard interface by which users can identify themselves, protect their data and engage in e-commerce with Bitcoin, this standard offers a solution to problems that have long plagued the existing model.

    Primary Objectives

    1. Standardization: The interface provides a consistent and standardized API that ensures that any application can integrate with any compliant wallet without needing custom adaptations.

    2. Vendor-Neutrality: The interface abstracts the underlying wallet implementation, allowing applications to work seamlessly with wallets from different vendors.

    3. Open Specification: The interface is openly documented, encouraging community adoption, and providing a bedrock foundation atop which anyone can build with confidence, knowing the interface will remain constant.

    Foundational Requirements

    SECTION TL;DR: We use the BSV Blockchain. We use the secp256k1 elliptic curve. We use compressed, DER-formatted public keys. We use BKDS key derivation. We use for security levels, protocol IDs, key IDs, and counterparties (with protocols reserved for internal wallet use). We subscribe to the idea that "Outputs are tokens". We use output baskets for tracking tokens. For categorization and filtering purposes, we allow transactions to be given a set of labels, and outputs to be given a set of tags. We utilize the rules for SPV validation. We use the BEEF standard outlined in for representing transactions. For encryption and decryption, we use the methods described in . For creating digital signatures, we use the methods described in . For HMACs , we derive symmetric keys as in , but then use them for HMAC operations instead of AES-GCM encryption. For the digital certificate structure and field encryption scheme, we use . For internalizing payment outputs that increase the user's wallet balance, we employ the key derivation protocol described within . For revealing key linkages, we employ the two methods described within , and we protect this information as described in . We incorporate for defining flexible proof-type fields to support emerging zero-knowledge proof (ZKP) schemes in specific key linkage revelations. We reserve specific protocol identifiers as described in to ensure forward compatibility with future permissioned protocols. Similarly, we reserve basket identifiers as outlined in to accommodate evolving wallet-managed asset permission schemes. These foundational prerequisites allow us to fully define and specify the behavior and functionality of the digital wallet system, ensuring future extensibility and compatibility across the BSV ecosystem.

    Section Overview

    The Wallet Interface is built upon a set of essential foundational standards and protocols that define the underlying architecture, cryptographic operations, and key management systems required for a robust and coherent wallet-to-application interface within the BSV ecosystem. This section thoroughly explains these foundational requirements, incorporating relevant content from the preceding BRCs to provide a holistic understanding of the interface's structure.

    1. Key Derivation using BKDS with BRC-42

    At the heart of the Wallet Interface lies the : BSV Key Derivation Scheme. This scheme defines how keys are derived between two interacting parties. BKDS leverages the secp256k1 elliptic curve and enables participants to derive multiple unique public-private key pairs from a shared master key. All cryptographic operations, including key derivation and identity handling, adhere to the BKDS as defined in . This specification does not support legacy key derivation schemes like BIP32 due to the foundational nature of BKDS in ensuring compatibility, privacy, and security across the BSV ecosystem. Wallets implementing this interface must migrate to BKDS and cannot rely on older derivation schemes.

    Identity Keys:

    • Each wallet has an everyday master private key and a corresponding master public key derived from the secp256k1 elliptic curve. The public key is known as the "identity key".

    • Additionally, there's a whole secondary "privileged mode" keyring for sensitive operations, allowing these privileged keys to be treated with higher security than the user's everyday keyring.

    Key Derivation Process:

    • When deriving a key for a payment or exchange, the sender computes an elliptic curve Diffie-Hellman (ECDH) shared secret using their private key and the recipient's public key.

    • The shared secret is then used to generate a scalar through HMAC and convert it to a point on the elliptic curve.

    • This point is combined with the recipient's master public key to produce a child public key.

    Key Privacy:

    • No information about the derived private key is exposed until actually used. This ensures that only the recipient can derive the private key corresponding to the public key provided by the sender.

    Expanding Key Universes:

    • With BKDS, wallets can create a virtually unlimited number of unique key pairs through simple modifications of the derivation inputs (e.g., invoice numbers). This open-ended invoice numbering scheme is baked into the Wallet Interface, facilitating custom, flexible key derivation for transactions, signatures, and encryption.

    2. Security Levels and Protocol IDs with BRC-43

    plays a vital role in organizing how keys are used and accessed in the wallet. This standard introduces Security Levels, Protocol IDs, Key IDs, and Counterparties rules that govern key derivation, permissions, and data access within standard wallets.

    Security Levels:

    • Security levels determine the required user permissions and access controls for a derived key:

      • Level 0: No restrictions, open access.

      • Level 1: Requires a level of user authorization that applies across all counterparties who use the same protocol.

      • Level 2: Restricts key usage to specific counterparties and requires individual permission for each.

    Protocol IDs & Key IDs:

    • Protocol IDs further define the usage context for a derived key, such as "Document Signing" or "Encryption".

    • A Key ID is a unique identifier that differentiates specific keys under the same Protocol ID, allowing numerous derived keys under the same context but with different purposes.

    Counterparties:

    • Counterparties are entities with whom keys are shared (sender, receiver, etc.). For instance, the interface allows single-party self-derivations where a sender and receiver are the same (useful for internal key operations) and anyone-derivations denoted by the private key 1 (for public operations).

    Permission System:

    • Permission grants are managed transparently by the wallet and include expiration times, user notifications, and granularity based on the security level. This ensures that applications receive only the delineated keys they need and no more.

    3. Reserved Internal Protocols with BRC-44

    discusses Admin-reserved and Prohibited Key Derivation Protocols that are exclusive to administrative use by the wallet. These reserved protocols prevent application access to key derivation operations that are inherently internal and crucial to wallet security and integrity.

    Internal Protocol Guidelines:

    • Any protocol ID that begins with admin is off-limits for external applications.

    • The Wallet Interface requires that this reserved protocol space is never exposed to or invoked by third-party applications, maintaining the separation between user-facing operations and internal wallet functionalities.

    4. Tokenization of UTXOs with BRC-45

    defines UTXOs as Tokens, asserting that Unspent Transaction Outputs (UTXOs) are the base units of tokenization within Bitcoin. This principle is integral to the interface, where UTXOs serve as tokens that can be managed within wallets using custom baskets, as discussed below.

    Transaction Outputs as Tokens:

    • UTXOs represent discrete token units that can be transferred directly from sender to recipient. Their validity and legitimacy can be independently verified by anyone receiving the transaction.

    • The Wallet Interface relies on the UTXO model to enhance scalability, ensure decentralization, and promote trustlessness by enabling transparent and verifiable transactions without reliance on intermediaries.

    Simplified Payment Verification (SPV):

    • The wallet interface integrates transaction validation protocols that follow 's SPV method. By validating UTXOs through matching txid and proof inclusion within the blockchain, wallets can quickly confirm that tokens are genuine without needing the entire chain. This eliminates the reliance on tracing tokens back to their genesis, addressing the Back To Genesis (BTG) problem. Instead, the Wallet Interface ensures validity and provenance by leveraging SPV proofs and state-based validation, allowing efficient token verification while maintaining scalability, reducing computational overhead, and preserving user privacy. As a result, tokens can be securely and rapidly transacted without the inefficiencies and complexities historically associated with the BTG issue.

    5. Tracking and Managing Outputs with BRC-46

    To facilitate complex tracking and interaction with UTXOs, establishes Wallet Transaction Output Tracking (Output Baskets) within the interface.

    Baskets:

    • Baskets are conceptual containers for grouping UTXOs, creating an easy-to-manage structure for tracking specific outputs used across applications or protocols.

    • A wallet must support basket management, including returning transaction outputs from a given basket, customizing outputs with relevant instructions, and spending or relinquishing them.

    Permissions:

    • Like with key derivation, permissioning is enforced for applications executing operations involving baskets. The security model here follows from , ensuring consistency across the system.

    • Wallets must ensure that users have given consent before listing the outputs from a given basket, creating transactions that insert outputs into a basket, or internalizing transactions that facilitate output insertion into baskets.

    6. Transaction Verification with BRC-67 and BRC-62

    Authenticated transaction verification is critical in wallet operations, and this builds, in part, on : Simplified Payment Verification and : Background Evaluation Extended Format (BEEF) Transactions.

    BEEF Data Structure:

    • The BEEF format specified in is optimized for SPV and designed for efficient data transmission, focusing on economy of information while retaining verification integrity.

    • Wallets should utilize BEEF when constructing, communicating, and validating transactions. BEEF supports streaming validation, enabling the wallet to initiate transaction verification as soon as it starts receiving the data.

    Verification Steps:

    • outlines the steps to be undertaken for verifying a transaction, including script validation, fee checking, sequence, and locktime examination. These checks ensure that transactions processed through the wallet interface are legitimate and contextually accurate.

    SPV Empowerment:

    • The SPV model allows lightweight wallet clients to verify the chain, making them resistant to fraud while not requiring them to store or access all blockchain data.

    7. Data Security with BRC-2 for Encryption and Decryption

    Security is paramount in the Wallet Interface, and defines Encryption and Decryption operations encapsulated within the interface's cryptographic functionality.

    AES-256-GCM Encryption:

    • Wallets employ AES-256-GCM for symmetric encryption, where the derived shared secret between the sender's and recipient's child keys becomes the basis for the encryption key.

    Encryption & Decryption Process:

    • Wallets use their private keys and their counterparty's public keys (derived through BKDS) to encrypt data under a given protocol ID and key ID. Similarly, upon receipt, the recipient decrypts the data using their private key combined with the sender's public key.

    Confidentiality Assurance:

    • Encryption through this interface ensures the confidentiality of transmitted data and can be applied for user-specific actions like private document exchange (shielded with encryption keys derived from BKDS).

    8. Authorized Digital Signatures with BRC-3

    The Wallet Interface supports digital signing functionalities defined in : Digital Signature Creation and Verification.

    Digital Signature Process:

    • mandates use of ECDSA over secp256k1 keys.

    • Derived child keys (from BKDS) are used to sign data based on the security levels, protocol IDs, and key IDs defined in .

    Private & Public Signatures:

    • Wallets can create private digital signatures intended for a specified receiver, by naming them as a counterparty.

    • It's also possible to create publicly verifiable signatures, simply by naming anyone as the counterparty.

    Verification:

    • The signature is verifiable by the recipient using derived public keys. The recipient uses mechanics to derive the corresponding public key and validates the signature using this key over the provided data.

    9. Identity Certificates and Selective Revelation with BRC-52

    defines Identity Certificates, which incorporate selective revelation protocols that wallets must support.

    Certificate Structure:

    • Identity certificates encapsulate a subject's identity information, certified by a trusted entity, with fields selectively encryptable to preserve user privacy.

    Selective Revelation:

    • Wallets must facilitate keyring management for applications to reveal or withhold certificate fields selectively. The wallet keeps a copy of the master keyring, transmitting only the necessary revelation keys to authorized parties in an encrypted form.

    Revocation Mechanism:

    • Identity certificate revocation is implemented via UTXO tracking. If the UTXO tied to a revocation outpoint is spent, everyone considers the certificate invalid—this adds an additional layer of trust and decentralized authority, depending on the constraints placed upon the UTXO.

    10. Payment Internalization with BRC-29

    The Wallet Interface incorporates support for : Simple Authenticated BSV P2PKH Payment Protocol, which standardizes how payments are derived, handled, and internalized within the wallet.

    Payment Key Derivation:

    • BKDS Integration: Payments utilize keys derived through BKDS. They are based on a combination of transaction-specific data (such as a unique derivation prefix) and counterparty public keys. The derived keys are used to generate P2PKH scripts, ensuring that only the intended recipient can derive the corresponding private keys for spending.

    Internalization Process:

    • Decoding and Deriving Keys: Upon receiving a payment message, the wallet decodes the message, derives the necessary private keys using the provided derivationPrefix and derivationSuffix, checks the scripts match, and processes the UTXOs.

    • Baskets and Custom Instructions: Non-P2PKH outputs with custom scripts can be directed into specific baskets, enabling organized tracking within the wallet. Custom instructions attached to UTXOs are also stored and can be used by applications for token history tracking or future spending.

    • SPV Verification: Regardless of whether a payment increments a user's wallet balance via

    Flexible Payment Handling:

    • Multiple Outputs and Transactions: supports handling multiple outputs and even transactions within a single "payment." Each transaction output can be individually indexed with a unique derivation suffix, allowing the wallet to differentiate and manage multiple outputs efficiently, while all outputs within one given payment share a common derivation prefix.

    11. Auditability and Key Linkage Revelations with BRC-69 and BRC-72

    The Wallet Interface incorporates methods to enhance transparency and auditability through : Revealing Key Linkages, while ensuring the protection of sensitive data during transit with : Protecting BRC-69 Key Linkage Information in Transit.

    Key Linkage Revelations:

    • BKDS Based Key Linkage: outlines two methods for revealing key linkages from BKDS derived keys. The first method allows wallets to reveal a root ECDH shared secret between a user's identity key and another counterparty's key, enabling anyone to link all interactions between them. The second method reveals the specific key offset for individual derived child keys, enabling audit trails while preserving privacy in other contexts.

    Protection of Linkage Information:

    • BRC-72 Integration: Protecting sensitive linkage data is paramount. specifies mechanisms for encrypting key linkage revelations when they are in transit. This encryption is done using the AES-256-GCM method, ensuring that only authorized verifiers (recipients) can decrypt and access the linkage data. This preserves privacy and security, even when key linkages must be revealed for audit or verification purposes.

    • Additionally, proofs help overcome the limitations described in . allows for future zero-knowledge proof types to be used in the context of specific key linkage revelation as technology develops.

    The foundational BRCs integrated into this Wallet Interface ensure security, scalability, and flexibility across operations performed within the BSV ecosystem. These frameworks from key derivation, rigorous cryptographic principles, selective identity verification, tokenization, secure payments, and audit trails through linkage revelations all combine to form a robust and future-proof digital wallet architecture. The next section defines the high-level structure of the wallet interface.

    Interface Structure

    The interface comprises numerous methods that cater to different functional areas related to wallet operations and application needs. The methods are grouped for easier understanding:

    Transaction Operations:

    • Creation: The createAction method creates a new Action, which is effectively a Bitcoin transaction augmented with descriptive metadata and optional categorization (labels). This method can either fully construct and sign a transaction or return a "signableTransaction" reference if some inputs must be signed or processed later. The method always requires at least one input or one output to produce a valid transaction; otherwise, it must return an error. The minimum requirements is that at least one input or one output must be specified. If only description is provided and no inputs and no outputs are given, the wallet must return an error, since a transaction cannot be constructed. If inputs are provided, the wallet requires inputBEEF to supply context and validation data for these inputs. If both inputBEEF and a fully prepared set of inputs are provided, inputBEEF should provide SPV and contextual information about these inputs. The two are complementary:

    Public Key Management:

    • Key Retrieval: getPublicKey facilitates the retrieval of public keys, be they derived keys based on protocols or the user's main identity keys.

    • Key Linkage: Methods revealCounterpartyKeyLinkage and revealSpecificKeyLinkage disclose key relationships, as specified in , with additional support for future zero-knowledge proof schemes outlined in . These are essential for identity verification and the auditing of interactions between parties.

    Cryptography Operations:

    • Encryption/Decryption: encrypt and decrypt methods implement secure encryption and decryption of data using derived keys and consistent protocol definitions, enabling private exchanges of information between counterparties.

    • HMAC Operations: createHmac and verifyHmac allow for the creation and verification of Hash-based Message Authentication Codes (HMAC) to ensure data integrity.

    Identity and Certificate Management:

    • Certificate Acquisition: acquireCertificate allows the wallet to obtain identity certificates, either by directly saving them or through a standardized issuance protocol. Conversely, relinquishCertificate allows an old certificate to be removed.

    • Certificate Listing and Discovery: listCertificates, discoverByIdentityKey, and discoverByAttributes enable querying of identity certificates owned by the user or others based on identity keys or specific attributes.

    Blockchain and Network Data:

    • Blockchain Height: getHeight retrieves the current height of the blockchain.

    • Merkle Root Retrieval: getMerkleRootForHeight retrieves the Merkle root at a specific block height.

    • Network and Version Information: getNetwork and getVersion

    Authentication:

    • User Authentication: isAuthenticated checks the user's authentication status, ensuring they've set up their wallet before operations are attempted.

    • Authentication Wait: waitForAuthentication waits for the user to complete authentication and returns once the wallet has been fully set up.

    Data Types and Constraints

    To ensure consistency and prevent errors, the interface defines various data types and associated constraints. A few key examples include:

    Boolean Types:

    • BooleanDefaultFalse: Defaults to false if not provided.

    • BooleanDefaultTrue: Defaults to true if not provided.

    Integer Types:

    • Byte: An integer between 0 and 255.

    • PositiveIntegerOrZero: A non-negative integer with an upper bound of 2^32 - 1.

    • PositiveIntegerMax10: A positive integer between 1 and 10.

    String Types:

    • ISOTimestampString: Represents an ISO 8601 format timestamp.

    • HexString: A string containing hexadecimal characters.

    • Base64String: A string in standard base64 encoded format.

    Error Handling and Validation

    Errors are raised using a uniform structure containing:

    • status: Denotes the presence of a failure (always "error").

    • code: A short machine-readable string representing the specific error or fault.

    • description: A human-readable explanation of the error.

    When errors occur, they must be communicated and thrown such that they preserve these structural elements. Specific instantiations or realizations of this interface, comprising APIs or transport mechanisms for messages between wallets and applications, must specify how these errors are communicated.

    Recommended Validation Steps:

    Wallets must apply all specified rules and logical validation procedures to all methods within the specification. For example, in the case of createAction, wallets should:

    • Verify that the required fields (description plus at least one input or one output) are present.

    • Check that if inputs are provided, the inputDescription field is also provided for each input.

    • Validate that if inputBEEF is provided, it corresponds logically to the inputs

    Parameter Errors:

    If parameters are missing, malformed, or conflict with each other, the wallet should return an error with an appropriate error code and a human-readable description. For instance:

    • Missing required fields: Return an error code like ERR_MISSING_PARAMETER and a description stating which parameter is missing.

    • Invalid numeric ranges or string lengths: Return ERR_INVALID_PARAMETER_VALUE.

    • Conflicts between inputs and inputBEEF: Return ERR_CONFLICTING_PARAMETERS

    These are examples; wallets and implementations are free to use their own naming conventions for error codes as long as they provide a clear description field.

    Usage and Best Practices

    • Interoperability: Since the interface is vendor-neutral, developers should ensure they comply fully with the defined types, constraints, and method contracts, allowing their wallets and applications to interface smoothly with others.

    • Use of Privileged Mode: Methods related to the use of keys include options that allow an alternative "privileged access" mode to be used. When implemented, a secondary and more secure set of keys is used instead of the primary ones. This should only be invoked when necessary, and requires proper justification to be provided.

    • Request Originators and Permissions: The interface ensures that operations like key derivation, signing, encryption, certificate field revelation, and transaction creation are conducted with proper authorization by incorporating the request's originator. The wallet can then authenticate the originator and seek user permission if necessary.

    Restrictions on Protocol and Basket Namespaces

    Protocol IDs and basket names are used to control access to data and assets, respectively. In order to ensure that consistent rules apply across wallet implementations, and to ensure that appropriate reservations are made for future permissions architectures (see and ), we specify the rules that apply to these namespaces here:

    Rules for Protocol Names

    Protocol IDs:

    • Must be at least 5 characters.

    • Generally must not exceed 400 characters (except for the specific linkage revelation protocol, which is allowed to be up to 430 characters, since it's the only protocol that encapsulates anotherr full protocol name within itself).

    • Must not contain multiple consecutive spaces (e.g., " ").

    • Must only contain lowercase letters, numbers, and spaces.

    Key IDs:

    • Must be at least one byte in length.

    • Must not exceed 800 bytes in length.

    Rules for Basket Names

    Basket names:

    • Must be at least 5 characters.

    • Must be no more than 400 characters.

    • Must only contain lowercase letters, numbers, and spaces.

    • Must not end with basket (this is redundant).

    The Wallet Interface

    This interface is specified in TypeScript as follows:

    ABI Specification

    This section defines the Application Binary Interface (ABI) specification for the Wallet Interface, detailing the binary communication protocol used between applications and wallets over a Wallet Wire. It provides a comprehensive description of how method calls are structured, how data is serialized and deserialized, and how errors and origins are handled within the protocol. This specification ensures that all implementations conform to a standardized binary protocol, enabling interoperability across different platforms and vendors.

    Overview

    The Wallet ABI defines a binary protocol for communication between an application and the user's digital wallet. Each message transmitted over the Wallet Wire consists of a structured binary frame that includes the method call code, originator information, parameters, and return values. The protocol is designed to be efficient, minimizing the data transmitted while ensuring all necessary information is accurately conveyed.

    Message Structure

    Every message sent to the wallet follows this general structure:

    • Call Code (1 byte): An unsigned integer representing the method being invoked.

    • Originator Length (1 byte): The length of the originator domain name in bytes.

    • Originator (variable length): The UTF-8 encoded fully qualified domain name (FQDN) of the application originating the request.

    • Parameters (variable length): Method-specific parameters serialized according to the rules defined in this specification.

    Responses from the wallet consist of:

    • Error Code (1 byte): A byte indicating success (0) or an error code (1-255).

    • Response Data (variable length): If Error Code is 0, this contains the serialized return values. If an error occurred, it contains the serialized error message and optional stack trace.

    Call Codes

    Each method in the Wallet Interface is assigned a unique call code. The call codes are defined as follows:

    Call Code
    Method Name

    Originator Handling

    The originator is the fully qualified domain name (FQDN) of the application making the request. It is included in each message to allow the wallet to:

    • Identify the requesting application.

    • Apply appropriate permissions and access controls.

    • Record audit logs for security and compliance.

    The originator is serialized as follows:

    • Originator Length (1 byte): The length of the originator string in bytes.

    • Originator (variable length): UTF-8 encoded bytes representing the originator's FQDN.

    Error Handling

    Errors are communicated using a structured format, ensuring consistent and detailed information about any issues that occur during method execution. This format enables precise error reporting, seamless debugging, and interoperability across implementations:

    • Error Code (1 byte):

      • 0: Indicates success; the method executed without errors.

      • 1-255: Indicates an error occurred; the specific code may correspond to predefined error types or be used for custom error categorization.

    If an error occurs (Error Code is non-zero), the following fields are included in the response:

    • Error Message Length (VarInt): The length of the error message in bytes.

    • Error Message (variable length): UTF-8 encoded string describing the error.

    • Stack Trace Length (VarInt): The length of the stack trace in bytes (optional, -1 if absent).

    Data Types and Serialization

    The following data types are used in the binary protocol:

    • Byte: An unsigned 8-bit integer (0 to 255).

    • Int8: A signed 8-bit integer (-128 to 127).

    • UInt8: An unsigned 8-bit integer (0

    VarInt Encoding

    Variable-length integers (VarInt) are used to efficiently represent integer values. The encoding follows the Bitcoin protocol's VarInt format:

    • For values from 0 to 0xFC (inclusive), a single byte represents the value.

    • For larger values, a marker byte indicates the length:

      • 0xFD: Next two bytes are the value as a little-endian unsigned integer.

    Method Calls Specification

    Each method call has specific parameter and return value formats. The following sections detail the serialization and deserialization process for each method.

    1. createAction

    • Call Code: 1

    Parameters

    Field
    Type
    Description

    Inputs Array:

    For each input:

    Field
    Type
    Description

    Outputs Array:

    For each output:

    Field
    Type
    Description
    • For each tag:

      • UTF-8 String

    Options Struct:

    Field
    Type
    Description
    • For each TXID:

      • Byte Array (32 bytes)

    • For each outpoint:

      • Byte Array (32 bytes + VarInt)

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data:

    Depending on the outcome, the response may include:

    Field
    Type
    Description
    • For each outpoint:

      • Byte Array (32 bytes + VarInt)

    • For each sendWithResults entry:

    Signable Transaction Struct:

    Field
    Type
    Description

    2. signAction

    • Call Code: 2

    Parameters

    Field
    Type
    Description
    • For each spend:

      • inputIndex: VarInt

      • unlockingScript: VarInt Length + Byte Array

    Options Struct:

    Same as in the createAction method, but only applicable fields:

    Field
    Type
    Description
    • For each TXID:

      • Byte Array (32 bytes)

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data:

    Field
    Type
    Description

    3. abortAction

    • Call Code: 3

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data: None.

    4. listActions

    • Call Code: 4

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data:

    Field
    Type
    Description

    Action Object:

    For each action:

    Field
    Type
    Description

    Status Codes:

    • 1: 'completed'

    • 2: 'unprocessed'

    • 3: 'sending'

    Input Object:

    For each input:

    Field
    Type
    Description

    Output Object:

    For each output:

    Field
    Type
    Description

    5. internalizeAction

    • Call Code: 5

    Parameters

    Field
    Type
    Description

    Output Object:

    For each output:

    Field
    Type
    Description

    Payment Remittance Struct:

    Field
    Type
    Description

    Insertion Remittance Struct:

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data: None.

    6. listOutputs

    • Call Code: 6

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data:

    Field
    Type
    Description

    Output Object:

    For each output:

    Field
    Type
    Description

    7. relinquishOutput

    • Call Code: 7

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data: None.

    8. getPublicKey

    • Call Code: 8

    Parameters

    Field
    Type
    Description

    Protocol ID Struct:

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data:

    Field
    Type
    Description

    9. revealCounterpartyKeyLinkage

    • Call Code: 9

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    10. revealSpecificKeyLinkage

    • Call Code: 10

    Parameters

    Field
    Type
    Description

    Key-Related Parameters:

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    11. encrypt

    • Call Code: 11

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    12. decrypt

    • Call Code: 12

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    13. createHmac

    • Call Code: 13

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    14. verifyHmac

    • Call Code: 14

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 if the HMAC is valid, non-zero error code otherwise.

    • Response Data: Nothing extra on successful verification.

    15. createSignature

    • Call Code: 15

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    16. verifySignature

    • Call Code: 16

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 if the signature is valid, non-zero error code otherwise.

    • Response Data: Nothing extra if successfully verified.

    17. acquireCertificate

    • Call Code: 17

    Parameters

    Field
    Type
    Description

    Depending on acquisitionProtocol, include additional fields:

    If acquisitionProtocol is 'direct' (1):

    Field
    Type
    Description

    If acquisitionProtocol is 'issuance' (2):

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    18. listCertificates

    • Call Code: 18

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    Each certificate in the certificates array is serialized as:

    • VarInt Length + Byte Array representing the certificate binary data (the certificate binary format as described in proveCertificate method).

    19. proveCertificate

    • Call Code: 19

    Parameters

    Field
    Type
    Description

    Certificate Struct:

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    Field
    Type
    Description

    20. relinquishCertificate

    • Call Code: 20

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data: None.

    21. discoverByIdentityKey

    • Call Code: 21

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success, non-zero error code otherwise.

    • Response Data (on success):

    This method returns a list of certificates with additional certifier information and decrypted fields.

    Field
    Type
    Description

    Each certificate includes:

    • Certificate Binary Data: Serialized certificate as in proveCertificate method.

    • Certifier Info Struct: Contains the following fields:

      Field
      Type
      Description

    22. discoverByAttributes

    • Call Code: 22

    Parameters

    Field
    Type
    Description

    Return Values

    Same as discoverByIdentityKey method.

    23. isAuthenticated

    • Call Code: 23

    Parameters

    None.

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data (on success):

    Field
    Type
    Description

    24. waitForAuthentication

    • Call Code: 24

    Parameters

    None.

    Return Values

    • Error Code (1 byte): 0 once the user is authenticated.

    • Response Data: None.

    25. getHeight

    • Call Code: 25

    Parameters

    None.

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data (on success):

    Field
    Type
    Description

    26. getHeaderForHeight

    • Call Code: 26

    Parameters

    Field
    Type
    Description

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data (on success):

    Field
    Type
    Description

    27. getNetwork

    • Call Code: 27

    Parameters

    None.

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data (on success):

    Field
    Type
    Description

    28. getVersion

    • Call Code: 28

    Parameters

    None.

    Return Values

    • Error Code (1 byte): 0 on success.

    • Response Data (on success):

    Field
    Type
    Description

    General Notes

    • Absence of Optional Fields: Optional fields are often indicated by a special value (e.g., -1 as a VarInt for length fields). Implementations should handle these values appropriately to determine the presence or absence of data.

    • Encoding of Strings: All strings are UTF-8 encoded and prefixed with their length as a VarInt. The -1 value indicates absence, notably different from 0 which indicates an empty string ("").

    This ABI specification provides a complete and detailed description of the binary protocol used for communication between wallets and applications. By adhering to this specification, developers can ensure compatibility and interoperability across different implementations, enabling a robust and secure ecosystem for wallet interactions within the BSV blockchain ecosystem.

    Implementers should carefully follow the serialization and deserialization rules outlined for each method to ensure correct functionality.

    Glossary of Terms

    AbortAction: A method in the Wallet Interface that allows the cancellation of a transaction that is in progress and has not yet been finalized or sent to the network.

    Action: An Action is a Bitcoin transaction plus metadata. It is a foundational concept that aligns with "Action Oriented Programming" (see: https://projectbabbage.com/docs/babbage-sdk/concepts/actions-aop).

    Actions: In the context of this specification, an Action is a Bitcoin transaction (as defined within the BSV blockchain context) that is enriched with additional metadata such as descriptions, labels, and other optional data. This concept follows the "Action Oriented Programming" paradigm, where each Action represents a business-level event or operation captured as a blockchain transaction. Actions are created using the createAction method, managed and categorized using labels, and can incorporate outputs tagged for easier retrieval.

    AES-256-GCM: Advanced Encryption Standard (AES) cipher with a 256-bit key size using Galois/Counter Mode (GCM); used for symmetric encryption and decryption operations within the Wallet Interface (as per ). By convention, 32-byte initialization vectors are prepended to the beginning of the ciphertext.

    Application Binary Interface (ABI): A specification detailing the binary communication protocol between applications and wallets over a Wallet Wire, ensuring consistent method call structures, data serialization, and error handling as defined in the Wallet Interface.

    Background Evaluation Extended Format (BEEF): A compact data format specified in for representing Bitcoin transactions optimized for Simplified Payment Verification (SPV) and efficient data transmission within the Wallet Interface.

    Baskets: Conceptual containers within a wallet used to group and manage specific Unspent Transaction Outputs (UTXOs) as per , enabling organized tracking and handling across applications or protocols.

    Bitcoin Request for Comment (BRC): An informal proposal or standard within the BSV ecosystem that outlines protocols, methods, or guidelines for functionalities such as transactions, key derivation, network architecture, and wallet interfaces.

    BKDS (BSV Key Derivation Scheme): A key derivation scheme defined in that allows wallets to derive multiple unique public-private key pairs from a shared master key using the secp256k1 elliptic curve and a counterparty.

    Blockchain Height: The number of blocks in the longest valid chain of the blockchain, representing the latest block's height within the BSV network.

    BooleanDefaultFalse: A data type representing an optional boolean parameter that defaults to false if not provided in method arguments.

    BooleanDefaultTrue: A data type representing an optional boolean parameter that defaults to true if not provided in method arguments.

    BSV Blockchain: A network emphasizing stability, scalability, and adherence to Satoshi Nakamoto's original vision for Bitcoin as a token system, a micropayment system, and a peer-to-peer electronic cash system.

    Call Code: An unsigned integer used in the ABI specification to represent the method being invoked over the Wallet Wire.

    Certificate: In the context of , a digital identity document that encapsulates a subject's identity information, certified by a trusted entity, with support for selective field encryption.

    Certificate Field Name: The name of a specific attribute or piece of data within an identity certificate, used for identification and selective revelation.

    Certificate Revocation: The process by which an identity certificate is invalidated, often implemented via spending a specific UTXO tied to a revocation outpoint; used to indicate the certificate is no longer valid.

    Compressed DER-formatted Public Key: A public key formatted according to the Distinguished Encoding Rules (DER), compressed to represent a point on the secp256k1 elliptic curve using 33 bytes (66 hexadecimal characters). The first byte denotes whether Y is odd, and the remaining 32 bytes comprise the X coordinate on the curve.

    Counterparty: An entity (e.g., sender, receiver, verifier) involved in a transaction or key derivation process, identified by their public key; used in BKDS and defined in .

    createAction: A method that constructs a new transaction based on provided inputs, outputs, and options. It can return a completed transaction, or a signableTransaction if the transaction is not finalized.

    Custom Instructions: Data attached to UTXOs that provide contextual information or necessary unlocking context within application logic, represented as a string in the Wallet Interface.

    Derivation Prefix/Suffix: Values used during the internalization of payment outputs, as described within to generate different key pairs for each output across the same payment.

    DescriptionString5to50Characters: A string data type used for descriptions within the Wallet Interface, constrained to a length between 5 and 50 characters.

    Digital Signature: A cryptographic value generated using a private key that verifies the authenticity and integrity of data, as outlined in with ECDSA.

    ECDH (Elliptic Curve Diffie-Hellman): A key agreement protocol using elliptic curve cryptography that allows two parties to establish a shared secret over an insecure channel.

    ECDSA (Elliptic Curve Digital Signature Algorithm): A cryptographic algorithm used for creating digital signatures using elliptic curve cryptography, specifically over the secp256k1 curve.

    Encryption/Decryption: The processes of scrambling data to prevent unauthorized access (encryption) and restoring it to its original form (decryption), as specified in with AES-256-GCM and used within the Wallet Interface.

    Entity Icon URL: A URL pointing to an icon representing a trusted entity or certifier in identity certificates, used for display and identification purposes.

    Entity Name: The name of a trusted entity or certifier associated with an identity certificate, providing a human-readable identifier for the certifier.

    Error Handling: The standardized method by which errors are communicated within the Wallet Interface, using structures containing status, code, description, and optional context.

    ErrorCodeString10To40Characters: A data type representing a machine-readable error code string with a length between 10 and 40 characters, used in error responses.

    ErrorDescriptionString20To200Characters: A data type representing a human-readable error description string with a length between 20 and 200 characters, providing details about an error.

    Fully Qualified Domain Name (FQDN): The complete domain name of a specific computer or host on the internet, used as the OriginatorDomainNameString to identify the originator of a request in the Wallet Interface.

    HMAC (Hash-based Message Authentication Code): A specific type of message authentication code involving a cryptographic hash function and a secret key, used for data integrity checks within the Wallet Interface.

    Identity Key: The master public key of a wallet derived from the master private key using the secp256k1 elliptic curve; used to identify the wallet owner and derive child keys.

    Input (Transaction Input): A reference in a transaction to a previous UTXO that is being spent, containing details such as the outpoint and unlocking script.

    Key Derivation: The process of generating child keys from a master key using a specified algorithm like BKDS, providing unique keys for different purposes or interactions.

    Key ID: A unique identifier differentiating specific keys under the same Protocol ID, allowing for multiple derived keys with different purposes within the same context as defined in .

    Key Linkage: Information that reveals the relationship between derived keys, used for transparency, auditability, and verification, particularly as per and protected during transit by .

    Labels (Transaction Labels): Strings used to categorize transactions within a wallet for organizational and filtering purposes.

    Locking Script: A script associated with a transaction output that specifies the conditions under which the output can later be spent (also known as an output script or scriptPubKey, though scriptPubKey should no longer be used).

    Lock Time: A parameter in a Bitcoin transaction that specifies the earliest time or block height at which the transaction can be included in the blockchain.

    Master Private Key: The primary private key of a wallet from which other keys are derived, forming the root of the wallet's key structure.

    Merkle Root: The root hash of a Merkle tree, summarizing all transactions in a block; used in SPV to verify transaction inclusion without downloading the entire block.

    Originator Domain Name String: The fully qualified domain name (FQDN) of the application that originated the request, used to authenticate and authorize requests in the Wallet Interface.

    Outpoint: A reference to a specific output in a previous transaction, identified by the transaction ID (txid) and output index (vout), used when spending UTXOs.

    Output (Transaction Output): A component of a transaction that specifies the recipient of funds or data, including the amount (in satoshis) and a locking script.

    Output Tags: Strings assigned to outputs within wallets to categorize or indicate attributes, facilitating searching, sorting, and filtering of UTXOs.

    Payment Internalization: The process by which a wallet accepts and manages incoming transactions by parsing, tagging, and organizing outputs, as per .

    Privileged Mode: A mode of operation within the wallet where sensitive or high-security operations are performed using a secondary, more secure set of keys; requires additional authorization.

    Private Digital Signature: A signature intended for a specified receiver, created using a private key derived via BKDS, ensuring that only the intended recipient can verify it using the corresponding public key.

    Proof-Type: A one-byte unsigned integer (0-255) defined in to specify the type of proof included in specific key linkage revelations. Proof Type 0 indicates no proof is provided, while Proof Types 1-255 are reserved for various zero-knowledge proof (ZKP) schemes, such as STARKs, Bulletproofs or SNARKs. This extensible format supports future advancements in ZKP technologies, enabling flexible and verifiable interactions while maintaining backward compatibility.

    Protocol ID: An identifier used in to define the context or usage of a derived key, combining a security level and a protocol string (e.g., [1, "document signing"]).

    PubKeyHex: A hexadecimal string representing a compressed DER-formatted secp256k1 public key, 66 characters long (33 bytes).

    Satoshi: The smallest unit of Bitcoin, equal to 0.00000001; used as the unit for transaction amounts within the Wallet Interface.

    Script Validation: The process of evaluating and verifying the correctness of scripts (locking and unlocking scripts) within transactions, ensuring they adhere to Bitcoin's scripting rules.

    Security Level: In , a classification that determines the required permissions and access controls for using a derived key (Level 0: open access, Level 1: requires cross-counterparty authorization, Level 2: requires individual permission for each counterparty).

    Shared Secret: In ECDH key exchange, a secret value derived by both parties using their own private key and the other party’s public key, used as the basis for deriving child keys or symmetric encryption keys.

    Signable Transaction: A Bitcoin transaction that has been created but is not yet fully signed or finalized. This transaction is in a preparatory state where it requires one or more digital signatures before it can be considered complete and potentially broadcast to the Bitcoin network. Returned from createAction as a partially constructed transaction in BEEF (Background Evaluation Extended Format), which includes a reference number for later signing or aborting. This appears when an input does not have its unlocking script yet. The transaction is partially constructed and returned with a reference. The caller can use this reference with signAction to supply the necessary unlocking scripts later. This mechanism decouples the initial transaction construction from the final signing steps.

    signAction: A method that signs a previously created transaction (a Signable Action) using the unlocking scripts provided, allowing it to be finalized and potentially broadcast.

    Signature: Data that proves the authenticity and integrity of a message or transaction, created using a private key and verifiable with the corresponding public key.

    Simplified Payment Verification (SPV): A method for verifying that a transaction is included in the blockchain without downloading the entire chain, by verifying the transaction's inclusion in a block (or its ancestors), checking the scripts that transfer coins, and validating that block via its Merkle root and proof-of-work.

    TXID (Transaction ID): A unique identifier for a transaction, calculated as a double SHA-256 hash of the transaction data.

    TagQueryMode: A parameter determining how tags are matched when listing outputs within a wallet; can be 'any' (matches if any tag matches) or 'all' (matches only if all queried tags are present).

    Transaction: An instruction sent to the Bitcoin network to transfer Bitcoin from one or more inputs to one or more outputs; forms the fundamental operation within the blockchain. Also referred to as Actions when used within applications.

    Unlocking Script: A script that satisfies the conditions specified by the locking script of an output, allowing the output to be spent (also known as an input script or scriptSig, though scriptSig should no longer be used).

    Unspent Transaction Output (UTXO): An output from a prior transaction that has not yet been spent; represents an amount of Bitcoin controlled by a script that can be used as an input in a new transaction.

    Vendor Neutrality: A design principle ensuring that an interface or protocol can be implemented by any vendor without proprietary constraints, promoting interoperability and standardization.

    VersionString7To30Characters: A data type representing a version string of the wallet, constrained to be between 7 and 30 characters, in the format [vendor]-[major].[minor].[patch].

    Wallet Interface: The standardized set of methods and protocols defined in for communication between wallets and applications in the BSV ecosystem, designed to be unified, vendor-neutral, and open.

    Wallet Wire: The communication channel or protocol over which applications and wallets exchange messages using the defined ABI specification.

    Conclusion

    This specification provides a comprehensive and standardized framework for Wallet-to-Application interactions within the BSV ecosystem. By defining a clear and secure ABI, it fosters interoperability, scalability, and vendor-neutral implementation. The type constraints, structured error handling, and robust serialization methods enable developers to build reliable and secure applications across diverse environments.

    Through its open and stable design, this specification ensures that wallets and applications can interoperate seamlessly, driving innovation while preserving stability. The reserved ranges for future call codes and adherence to backward compatibility principles also ensure long-term adaptability to new use cases and evolving technologies.

    Developers and implementers are encouraged to align with this standard to enable a unified ecosystem, empowering applications and wallets to interact efficiently and securely, ultimately advancing the adoption and utility of the BSV blockchain.

    At long last.

    Security and Privacy: Emphasizing secure handling of keys, transactions, and data through the use of secure cryptographic protocols and minimal exposure of sensitive information.
  • Comprehensive Functionality: The interface covers a broad range of functionalities, from transaction creation, signing, and broadcasting, to identity management, encryption, and digital signatures.

  • , inserts outputs into custom baskets with tags and custom instructions, or both, the wallet always employs
    to confirm the transaction's validity according to the rules of SPV.
    inputs
    define the UTXOs being consumed, and
    inputBEEF
    provides the transaction inclusion proofs or data needed for validation. Both must not conflict. If a conflict is detected, the wallet should return an error. Every input requires an
    inputDescription
    . This string documents why a particular UTXO was chosen or what it represents. This field is required to ensure proper user-level record-keeping and transparency. If
    basket
    is not provided for an output, that output is considered untracked by the wallet. It will not appear in
    listOutputs
    , and the wallet does not maintain any metadata about it. Baskets are used for grouping UTXOs for later retrieval, filtering, and permissioned operations.
  • Signing: signAction allows for signing and processing previously created transactions from the createAction method.

  • Aborting: abortAction facilitates the cancellation of transactions that have not yet been completed.

  • Internalization: internalizeAction enables wallets to accept and manage incoming transactions by parsing, tagging, and organizing outputs.

  • Listing: listActions and listOutputs allow querying transactions and outputs based on specific criteria like labels, baskets, and tags. Labels can be attached to transactions to facilitate discovery via listActions and tags can be attached to outputs to similarly facilitate discovery via listOutputs. They are purely organizational tools and cannot be used as triggers or conditional hooks for other wallet operations. They serve only for later searching and categorizing actions.

  • Relinquishment: relinquishOutput releases an output from a basket tracked by the wallet, even if it has yet to be spent.

  • Pre-Built Transactions: If you already have a fully constructed transaction in BEEF format and simply need to internalize it into the wallet, internalizeAction is the appropriate method. createAction is meant for constructing new transactions within the wallet, not for just adding an existing transaction.

  • Tags vs. Labels: Transaction-level labels categorize entire transactions (Actions) and are used with listActions. Output-level tags categorize individual outputs and are used with listOutputs. Both are organizational metadata fields and do not trigger special wallet logic or external processes. They exist solely for searching, filtering, and organizing data.

  • Signatures: createSignature and verifySignature enable the creation and verification of digital signatures, both public and private, essential for validating the authenticity of transactions, documents, and data.

    Proving Identity Certificates: proveCertificate leverages selective revelation protocols defined in BRC-52 while integrating future-proof proof schemes from BRC-97. This provides enhanced flexibility and enables users to securely prove their identity or certified attributes to third parties when required.

    retrieve information about the network (mainnet or testnet) and the wallet's version.
    PositiveIntegerDefault10Max10000: A positive integer that defaults to 10, and has an upper bound of 10000.
  • SatoshiValue: Represents a value in Satoshis, ranging between 1 and 2.1 * 10^15.

  • Specialized Strings: Defined for specific fields, including transactions, descriptions, version strings, certificate field names, etc.
    context: (Optional) Additional contextual data relevant to the error---often binary or debug information.
    .
  • Ensure that labels, tags, and basket names comply with the defined format and size constraints.

  • If any constraints are not met, or if conflicting parameters are detected (e.g., invalid noSendChange usage), the wallet should return a structured error as previously defined.

  • .
  • Must not end with protocol (this is redundant).

  • Must not start with p (allows for future "specially permissioned" protocols). Specified in BRC-98.

  • Must not contain consecutive spaces.

  • Must not start with admin (allows the wallet to manage assets internal to its operations).

  • Must not be default (some wallets have historically used this for internal operations).

  • Must not start with p (allows for future "specially permissioned" baskets). Specified in BRC-99.

  • 7

    relinquishOutput

    8

    getPublicKey

    9

    revealCounterpartyKeyLinkage

    10

    revealSpecificKeyLinkage

    11

    encrypt

    12

    decrypt

    13

    createHmac

    14

    verifyHmac

    15

    createSignature

    16

    verifySignature

    17

    acquireCertificate

    18

    listCertificates

    19

    proveCertificate

    20

    relinquishCertificate

    21

    discoverByIdentityKey

    22

    discoverByAttributes

    23

    isAuthenticated

    24

    waitForAuthentication

    25

    getHeight

    26

    getHeaderForHeight

    27

    getNetwork

    28

    getVersion

    Stack Trace (variable length): UTF-8 encoded string containing the stack trace (optional).
    to
    255
    ).
  • VarInt: A variable-length integer used for lengths and counts.

  • UTF-8 String: A string prefixed with its length (as a VarInt), followed by UTF-8 encoded bytes.

  • Byte Array: A sequence of bytes prefixed with its length (as a VarInt).

  • 0xFE: Next four bytes are the value as a little-endian unsigned integer.

  • 0xFF: Next eight bytes are the value as a little-endian unsigned integer.

  • lockTime

    VarInt

    Transaction lock time (optional). Use -1 to indicate absence.

    version

    VarInt

    Transaction version (optional). Use -1 to indicate absence.

    labels

    VarInt Length + Array

    An array of labels (optional). Use VarInt -1 if absent.

    options

    Int8 Flag + Options Struct

    Options object (optional). If present, 1; else, 0.

    sequenceNumber

    VarInt

    Sequence number (optional). Use -1 to indicate absence.

    customInstructions

    UTF-8 String

    Custom instructions (optional). If absent, VarInt -1.

    tags

    VarInt Length + Array

    Array of tags (optional). If absent, VarInt -1.

    returnTXIDOnly

    Int8

    1 for true, 0 for false, -1 if not provided.

    noSend

    Int8

    1 for true, 0 for false, -1 if not provided.

    noSendChange

    VarInt Length + Array

    Array of outpoints (optional). If absent, VarInt -1.

    sendWith

    VarInt Length + Array

    Array of TXIDs (optional). If absent, VarInt -1.

    randomizeOutputs

    Int8

    1 for true, 0 for false, -1 if not provided.

    signableTransaction

    Int8 Flag + Struct

    If present, 1 followed by signable transaction data. Else, 0.

    txid: Byte Array (32 bytes)
  • status: Int8 (1 for 'unproven', 2 for 'sending', 3 for 'failed')

  • sequenceNumber: VarInt (optional). Use -1 to indicate absence.

    includeInputSourceLockingScripts

    Int8

    Same as above.

    includeInputUnlockingScripts

    Int8

    Same as above.

    includeOutputs

    Int8

    Same as above.

    includeOutputLockingScripts

    Int8

    Same as above.

    limit

    VarInt

    Maximum number of actions to return. Use -1 if not provided.

    offset

    VarInt

    Number of actions to skip. Use -1 if not provided.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    description

    UTF-8 String

    Description of the action.

    labels

    VarInt Length + Array

    Array of labels (if includeLabels is true, zero-length otherwise).

    version

    VarInt

    Transaction version.

    lockTime

    VarInt

    Transaction lock time.

    inputs

    VarInt Length + Array

    Array of input objects (if includeInputs is true, zero-length otherwise).

    outputs

    VarInt Length + Array

    Array of output objects (if includeOutputs is true, zero-length otherwise).

    4: 'unproven'

  • 5: 'unsigned'

  • 6: 'nosend'

  • 7: 'nonfinal'

  • inputDescription

    UTF-8 String

    Description of the input.

    sequenceNumber

    VarInt

    Sequence number.

    outputDescription

    UTF-8 String

    Description of the output.

    basket

    UTF-8 String

    Basket name (if present, else -1).

    tags

    VarInt Length + Array

    Array of tags (if present, else -1).

    customInstructions

    UTF-8 String

    Custom instructions (if present, else -1).

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    includeCustomInstructions

    Int8

    1 for true, 0 for false, -1 if not provided.

    includeTags

    Int8

    Same as above.

    includeLabels

    Int8

    Same as above.

    limit

    VarInt

    Maximum number of outputs to return. Use -1 if not provided.

    offset

    VarInt

    Number of outputs to skip. Use -1 if not provided.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    spendable

    Int8

    Always 1 (indicates the output is spendable).

    customInstructions

    UTF-8 String

    Custom instructions (if included).

    tags

    VarInt Length + Array

    Array of tags (if included).

    labels

    VarInt Length + Array

    Array of labels (if included).

    privileged

    Int8

    1 for true, 0 for false, -1 if not provided.

    privilegedReason

    Int8 Length + UTF-8 String

    Reason for privileged access (optional).

    forSelf

    Int8

    1 for true, 0 for false, -1 if not provided.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    encryptedLinkage

    VarInt Length + Byte Array

    The encrypted linkage data.

    encryptedLinkageProof

    VarInt Length + Byte Array

    The encrypted linkage proof data.

    privilegedReason

    UTF-8 String

    The privileged reason string (Optional).

    keyID

    UTF-8 String

    The key ID used for key derivation.

    encryptedLinkage

    VarInt Length + Byte Array

    The encrypted linkage data.

    encryptedLinkageProof

    VarInt Length + Byte Array

    The encrypted linkage proof data.

    proofType

    UInt8 Number

    The type of proof generated

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    data

    VarInt Length + Byte Array

    The data over which the signature was computed (if dataTypeFlag is 1).

    hashToDirectlyVerify

    Byte Array (32 bytes)

    The hash over which the signature was computed (if dataTypeFlag is 2).

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    privilegedReason

    Int8 Length + UTF-8 String

    The reason for the privileged request (Optional).

    acquisitionProtocol

    UInt8

    1 for 'direct', 2 for 'issuance'.

    keyringForSubject

    VarInt number of entries + Map

    Map of fieldName to keyring values.

    privileged

    Int8

    1 for true, 0 for false, -1 if not provided.

    privilegedReason

    Int8 Length + UTF-8 String

    The privileged reason string (Optional)

    privilegedReason

    Int8 Length + UTF-8 String

    The privileged reason (Optional).

    revocationOutpoint

    Byte Array

    Revocation outpoint (TXID + output index).

    signature

    VarInt Length + Byte Array

    Certificate signature.

    fields

    VarInt Length + Map

    Map of fieldName to encrypted fieldValue.

    Certifier's name.

    iconUrl

    UTF-8 String

    Certifier's icon URL.

    description

    UTF-8 String

    Certifier's description.

    trust

    UInt8

    User trust level of this certifier (1-10).

  • Publicly Revealed Keyring: Map of fieldName to keyring values.

  • Decrypted Fields: Map of fieldName to decrypted fieldValue strings (UTF-8).

  • Error Codes: While only 0 (success) and 1 (generic error) are defined here, implementations may use additional error codes for error classification as needed.

  • Serialization of Nested Structures: Arrays and maps are prefixed with their lengths as VarInts. Nested fields must follow the same serialization rules as their top-level counterparts.

  • 1

    createAction

    2

    signAction

    3

    abortAction

    4

    listActions

    5

    internalizeAction

    6

    listOutputs

    description

    UTF-8 String

    A human-readable description of the action represented by this transaction.

    inputBEEF

    VarInt Length + Byte Array

    BEEF data associated with inputs (optional). Use VarInt -1 if absent.

    inputs

    VarInt Length + Array

    An array of input objects (optional). Use VarInt -1 if absent.

    outputs

    VarInt Length + Array

    An array of output objects (optional). Use VarInt -1 if absent.

    outpoint

    Byte Array (32 bytes + VarInt)

    32-byte TXID followed by VarInt output index.

    unlockingScript

    VarInt Length + Byte Array

    Unlocking script (optional). If present, provide length and data. If absent, use VarInt -1 and then provide unlockingScriptLength (VarInt).

    unlockingScriptLength

    VarInt

    Length of the unlocking script if unlockingScript is absent, VarInt -1 otherwise.

    inputDescription

    UTF-8 String

    Description of this input.

    lockingScript

    VarInt Length + Byte Array

    Locking script.

    satoshis

    VarInt

    Amount in satoshis.

    outputDescription

    UTF-8 String

    Description of this output.

    basket

    UTF-8 String

    Basket name (optional). If absent, VarInt -1.

    signAndProcess

    Int8

    1 for true, 0 for false, -1 if not provided.

    acceptDelayedBroadcast

    Int8

    1 for true, 0 for false, -1 if not provided.

    trustSelf

    Int8

    1 if 'known', -1 if not provided.

    knownTxids

    VarInt Length + Array

    Array of TXIDs (optional). If absent, VarInt -1.

    txid

    Int8 Flag + Byte Array (32 bytes)

    If present, 1 followed by 32-byte TXID. Else, 0.

    tx

    Int8 Flag + VarInt Length + Byte Array

    If present, 1 followed by transaction data (AtomicBEEF). Else, 0.

    noSendChange

    VarInt Length + Array

    Array of outpoints (optional). If absent, VarInt -1.

    sendWithResults

    VarInt Length + Array

    Array of structures containing txid and status. If absent, VarInt -1.

    tx

    VarInt Length + Byte Array

    Transaction data in AtomicBEEF format.

    reference

    VarInt Length + Byte Array

    Reference identifier as a Base64-encoded string.

    spends

    VarInt Count + Map

    Map of input indexes to spend information.

    reference

    VarInt Length + Byte Array

    Reference number as a Base64-encoded string.

    options

    Int8 Flag + Options Struct

    Options object (optional). If present, 1; else, 0.

    acceptDelayedBroadcast

    Int8

    1 for true, 0 for false, -1 if not provided.

    returnTXIDOnly

    Int8

    1 for true, 0 for false, -1 if not provided.

    noSend

    Int8

    1 for true, 0 for false, -1 if not provided.

    sendWith

    VarInt Length + Array

    Array of TXIDs (optional). If absent, VarInt -1.

    txid

    Int8 Flag + Byte Array (32 bytes)

    If present, 1 followed by 32-byte TXID. Else, 0.

    tx

    Int8 Flag + VarInt Length + Byte Array

    If present, 1 followed by transaction data (AtomicBEEF). Else, 0.

    noSendChange

    VarInt Length + Array

    Array of outpoints (optional). If absent, VarInt -1.

    sendWithResults

    VarInt Length + Array

    Array of structures containing txid and status. If absent, VarInt -1.

    reference

    VarInt Length + Byte Array

    Reference identifier (Base64-encoded).

    labels

    VarInt number + Array

    Array of labels to filter actions.

    labelQueryMode

    Int8

    1 for 'any', 2 for 'all', -1 if not provided.

    includeLabels

    Int8

    1 for true, 0 for false, -1 if not provided.

    includeInputs

    Int8

    Same as above.

    totalActions

    VarInt

    Total number of actions matching the query.

    actions

    Array

    Serialized array of action objects (details follow).

    txid

    Byte Array (32 bytes)

    Transaction ID.

    satoshis

    VarInt

    Amount in satoshis.

    status

    Int8

    Status code (see below).

    isOutgoing

    Int8

    1 for true, 0 for false.

    sourceOutpoint

    Byte Array

    Outpoint (TXID + output index).

    sourceSatoshis

    VarInt

    Amount in satoshis of the source output.

    sourceLockingScript

    VarInt Length + Byte Array

    Locking script of the source output (if included).

    unlockingScript

    VarInt Length + Byte Array

    Unlocking script (if included).

    outputIndex

    VarInt

    Index of the output within the transaction.

    satoshis

    VarInt

    Amount in satoshis.

    lockingScript

    VarInt Length + Byte Array

    Locking script (if included).

    spendable

    Int8

    1 for true, 0 for false.

    tx

    VarInt Length + Byte Array

    BEEF-formatted transaction.

    outputs

    VarInt Length + Array

    Array of output objects to internalize.

    labels

    VarInt Length + Array

    Array of labels (optional). If absent, -1.

    description

    UTF-8 String

    Description of the action.

    outputIndex

    VarInt

    Index of the output within the transaction.

    protocol

    Int8

    1 for 'wallet payment', 2 for 'basket insertion'.

    paymentRemittance

    Struct

    Remittance data for payments (if protocol is 1).

    insertionRemittance

    Struct

    Remittance data for insertions (if protocol is 2).

    senderIdentityKey

    Byte Array (33 bytes)

    Sender's compressed public key.

    derivationPrefix

    VarInt Length + Byte Array

    Base64-encoded derivation prefix.

    derivationSuffix

    VarInt Length + Byte Array

    Base64-encoded derivation suffix.

    basket

    UTF-8 String

    Basket name.

    customInstructions

    UTF-8 String

    Custom instructions (optional). If absent, -1.

    tags

    VarInt Length + Array

    Array of tags. If absent, length 0.

    basket

    UTF-8 String

    Basket name.

    tags

    VarInt Length + Array

    Array of tags to filter by (optional). If absent, length 0.

    tagQueryMode

    Int8

    1 for 'all', 2 for 'any', -1 if not provided.

    include

    Int8

    1 for 'locking scripts', 2 for 'entire transactions', -1 if not provided.

    totalOutputs

    VarInt

    Total number of outputs matching the query.

    outputs

    Array

    Serialized array of output objects (details follow).

    outpoint

    Byte Array

    Outpoint (TXID + output index).

    satoshis

    VarInt

    Amount in satoshis.

    lockingScript

    VarInt Length + Byte Array

    Locking script (if included).

    tx

    VarInt Length + Byte Array

    Transaction data (if included).

    basket

    UTF-8 String

    Basket name.

    output

    Byte Array

    Outpoint (TXID + output index) to relinquish.

    identityKey

    UInt8

    1 to retrieve the identity key, 0 otherwise.

    protocolID

    Struct

    Protocol ID (if identityKey is 0).

    keyID

    UTF-8 String

    Key ID (if identityKey is 0).

    counterparty

    Byte Array or UInt8

    Counterparty public key, or 11 for 'self', 12 for 'anyone'.

    securityLevel

    UInt8

    Security level (0, 1, or 2).

    protocolString

    UTF-8 String

    Protocol identifier string.

    publicKey

    Byte Array (33 bytes)

    Compressed DER-formatted public key.

    privileged

    Int8

    1 for true, 0 for false, -1 if not provided.

    privilegedReason

    UTF-8 String

    The privileged reason string (Optional).

    counterparty

    Byte Array (33 bytes)

    The counterparty's compressed secp256k1 public key.

    verifier

    Byte Array (33 bytes)

    The verifier's compressed secp256k1 public key.

    prover

    Byte Array (33 bytes)

    The prover's (user's) compressed public key.

    verifier

    Byte Array (33 bytes)

    The verifier's compressed public key.

    counterparty

    Byte Array (33 bytes)

    The counterparty's compressed public key.

    revelationTime

    UTF-8 String

    ISO 8601 timestamp string indicating the time of revelation.

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    verifier

    Byte Array (33 bytes)

    The verifier's compressed public key.

    protocolID

    Protocol ID Struct

    Security level and protocol string (see Protocol ID Struct from call code 8).

    keyID

    UTF-8 String

    Key ID used for key derivation.

    counterparty

    Byte Array (33 bytes) or UInt8

    Counterparty's compressed public key, 11 for 'self', 12 for 'anyone', or 0 if not provided.

    privileged

    Int8

    1 for true, 0 for false, -1 if not provided.

    prover

    Byte Array (33 bytes)

    The prover's compressed public key.

    verifier

    Byte Array (33 bytes)

    The verifier's compressed public key.

    counterparty

    Byte Array (33 bytes)

    The counterparty's compressed public key.

    protocolID

    Protocol ID Struct

    The security level and protocol string used for key derivation, first described in call code 8).

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    plaintext

    VarInt Length + Byte Array

    The plaintext data to be encrypted.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    ciphertext

    Byte Array

    The encrypted data (AES-256-GCM).

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    ciphertext

    VarInt Length + Byte Array

    The ciphertext data to be decrypted.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    plaintext

    Byte Array

    The decrypted data.

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    data

    VarInt Length + Byte Array

    The data over which to compute the HMAC.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    hmac

    Byte Array

    The computed HMAC value.

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    hmac

    Byte Array

    The HMAC value to verify.

    data

    VarInt Length + Byte Array

    The data over which the HMAC was computed.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    dataTypeFlag

    UInt8

    1 if signing data, 2 if signing hashToDirectlySign.

    data

    VarInt Length + Byte Array

    The data to be signed (if dataTypeFlag is 1).

    hashToDirectlySign

    Byte Array (32 bytes)

    The hash to directly sign (if dataTypeFlag is 2).

    signature

    Byte Array

    The DER-encoded ECDSA signature.

    Key-Related Parameters

    See Key-Related Parameters as defined in call code 10.

    forSelf

    Int8

    1 for verifying own signature, 0 otherwise, -1 if not provided.

    signature

    VarInt Length + Byte Array

    The DER-encoded ECDSA signature to verify.

    dataTypeFlag

    UInt8

    1 if verifying over data, 2 if over hashToDirectlyVerify.

    type

    Byte Array (Base64 encoded)

    The certificate type identifier.

    certifier

    Byte Array (33 bytes)

    The certifier's compressed public key.

    fields

    VarInt number + Map

    Map of fieldName to fieldValue (both UTF-8 strings).

    privileged

    Int8

    1 for true, 0 for false, -1 if not provided.

    serialNumber

    Byte Array (Base64 encoded)

    The certificate serial number.

    revocationOutpoint

    Byte Array (32 bytes) + VarInt

    The revocation outpoint (TXID + output index).

    signature

    VarInt Length + Byte Array

    The certifier's signature over the certificate data.

    keyringRevealer

    Byte Array (33 bytes) or UInt8

    The revealer's compressed public key, or 11 for 'certifier'.

    certifierUrl

    UTF-8 String

    The certifier's URL for issuance.

    certificate

    Byte Array

    The serialized certificate binary data (format described in call code 19).

    certifiers

    VarInt Length + Array

    Array of certifier public keys (each 33 bytes).

    types

    VarInt Length + Array

    Array of certificate types (where each entry is a byte array of 32 bytes).

    limit

    VarInt

    Maximum number of certificates to return, -1 if not provided.

    offset

    VarInt

    Number of certificates to skip, -1 if not provided.

    totalCertificates

    VarInt

    Total number of certificates matching the criteria.

    certificates

    Array

    Array of certificate binary data (see below).

    certificate

    Certificate Struct

    The certificate data (see Certificate Struct below).

    fieldsToReveal

    VarInt Length + Array

    Array of fieldName strings (UTF-8) to reveal.

    verifier

    Byte Array (33 bytes)

    The verifier's compressed public key.

    privileged

    Int8

    1 for true, 0 for false, -1 if not provided.

    type

    Byte Array (Base64 encoded)

    Certificate type identifier.

    subject

    Byte Array (33 bytes)

    Subject's compressed public key.

    serialNumber

    Byte Array (Base64 encoded)

    Certificate serial number.

    certifier

    Byte Array (33 bytes)

    Certifier's compressed public key.

    keyringForVerifier

    VarInt number of fields + Map

    Map of fieldName to keyring values.

    type

    Byte Array (Base64 encoded)

    Certificate type identifier.

    serialNumber

    Byte Array (Base64 encoded)

    Certificate serial number.

    certifier

    Byte Array (33 bytes)

    Certifier's compressed public key.

    identityKey

    Byte Array (33 bytes)

    The identity key to search for certificates.

    limit

    VarInt

    Maximum number of certificates to return, -1 if not provided.

    offset

    VarInt

    Number of certificates to skip, -1 if not provided.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    totalCertificates

    VarInt

    Total certificates matching the identity key.

    certificates

    Array

    Array of extended certificate structs (see below).

    name

    attributes

    VarInt Length + Map

    Map of fieldName to fieldValue strings (UTF-8).

    limit

    VarInt

    Maximum number of certificates to return, -1 if not provided.

    offset

    VarInt

    Number of certificates to skip, -1 if not provided.

    seekPermission

    Int8

    1 for true (default), 0 for false, -1 if not provided.

    authenticated

    UInt8

    1 if authenticated, 0 otherwise.

    height

    VarInt

    Current block height.

    height

    VarInt

    The block height for which to retrieve the header.

    header

    Byte Array (80 bytes)

    The serialized block header (80 bytes).

    network

    UInt8

    0 for 'mainnet', 1 for 'testnet'.

    version

    UTF-8 String

    The wallet's version string (e.g., vendor-1.0.0).

    BRC-43
    BRC-44
    BRC-45
    BRC-46
    BRC-67
    BRC-62
    BRC-2
    BRC-3
    BRC-56
    BRC-2
    BRC-52
    BRC-29
    BRC-69
    BRC-72
    BRC-97
    BRC-98
    BRC-99
    BRC-42
    BRC-42
    BRC-43
    BRC-44
    BRC-45
    BRC-67
    BRC-46
    BRC-43
    BRC-67
    BRC-62
    BRC-62
    BRC-67
    BRC-2
    BRC-3
    BRC-3
    BRC-43
    BRC-43
    BRC-52
    BRC-29
    BRC-29
    BRC-29
    BRC-69
    BRC-72
    BRC-69
    BRC-72
    BRC-2
    BRC-94
    BRC-93
    BRC-97
    BRC-69
    BRC-97
    BRC-98
    BRC-99
    BRC-2
    BRC-62
    BRC-46
    BRC-42
    BRC-52
    BRC-43
    BRC-29
    BRC-3
    BRC-2
    BRC-43
    BRC-69
    BRC-72
    BRC-29
    BRC-97
    BRC-43
    BRC-43
    BRC-100

    UTF-8 String

    BRC-67
    /**
     * @typedef {boolean} BooleanDefaultFalse
     * Represents an optional boolean parameter, which defaults to `false` if not provided.
     * @remarks
     * Default values are not enforced at the type level. Ensure that implementations explicitly assign the default value.
    
     */
    export type BooleanDefaultFalse = boolean
    
    /**
     * @typedef {boolean} BooleanDefaultTrue
     * Represents an optional boolean parameter, which defaults to `true` if not provided.
     * @remarks
     * Default values are not enforced at the type level. Ensure that implementations explicitly assign the default value.
     */
    export type BooleanDefaultTrue = boolean
    
    /**
     * @typedef {number} Byte
     * Represents an integer from 0 to 255 (inclusive).
     * @minimum 0
     * @maximum 255
     */
    export type Byte = number
    
    /**
     * @typedef {number} PositiveIntegerOrZero
     * A positive integer, includes zero and has an upper bound of `2^32 - 1`.
     * @minimum 0
     * @maximum 4294967295
     * @remarks
     * TypeScript cannot enforce numeric ranges. Validate at runtime if the value is within the specified range.
     */
    export type PositiveIntegerOrZero = number
    
    /**
     * @typedef {number} PositiveInteger
     * A positive integer that excludes zero, and has an upper bound of `2^32 - 1`.
     * @minimum 1
     * @maximum 4294967295
     * @remarks
     * TypeScript cannot enforce numeric ranges. Validate at runtime if the value is within the specified range.
     */
    export type PositiveInteger = number
    
    /**
     * @typedef {number} PositiveIntegerMax10
     * A positive integer that excludes zero, and has an upper bound of 10.
     * @minimum 1
     * @maximum 10
     * @remarks
     * TypeScript cannot enforce numeric ranges. Validate at runtime if the value is within the specified range.
     */
    export type PositiveIntegerMax10 = number
    
    /**
     * @typedef {number} PositiveIntegerDefault10Max10000
     * A positive integer that defaults to 10, and has an upper bound of 10000.
     * @minimum 1
     * @default 10
     * @maximum 10000
     * @remarks
     * Default values are not enforced at the type level. Validate at runtime if the value is within the specified range and assign the default if omitted.
     */
    export type PositiveIntegerDefault10Max10000 = number
    
    /**
     * @typedef {number} SatoshiValue
     * Represents a value in Satoshis, constrained by the max supply of Bitcoin (2.1 * 10^15 Satoshis).
     * @minimum 1
     * @maximum 2100000000000000
     * @remarks
     * TypeScript cannot enforce numeric ranges. Validate at runtime if the value is within the specified range.
     */
    export type SatoshiValue = number
    
    /**
     * @typedef {string} ISOTimestampString
     * Represents an ISO timestamp string.
     * @remarks
     * Ensure runtime validation to confirm the string adheres to the ISO 8601 standard.
     */
    export type ISOTimestampString = string
    
    /**
     * @typedef {string} HexString
     * A string containing only hexadecimal characters (0-9, a-f).
     * @remarks
     * TypeScript does not enforce format or case. Validate at runtime to ensure the string is properly formatted.
     */
    export type HexString = string
    
    /**
     * @typedef {HexString} TXIDHexString
     * Represents a transaction ID, enforced to be exactly 64 characters in length and in hexadecimal format.
     * @length 64
     * @remarks
     * TypeScript cannot enforce string length. Validate at runtime for length and format compliance.
     */
    export type TXIDHexString = HexString
    
    /**
     * @typedef {string} OutpointString
     * Represents a transaction ID and output index pair. The TXID is given as a hex string followed by a period "." and then the output index is given as a decimal integer.
     * @remarks
     * Validate at runtime to ensure the correct format: `<TXID>.<index>`.
     */
    export type OutpointString = string
    
    /**
     * @typedef {HexString} PubKeyHex
     * Represents a compressed DER secp256k1 public key, exactly 66 hex characters (33 bytes) in length.
     * @length 66
     * @remarks
     * TypeScript does not enforce length or format. Validate at runtime to ensure the string is 66 characters long and valid hexadecimal.
     */
    export type PubKeyHex = HexString
    
    /**
     * @typedef {string} Base64String
     * A standard base64 encoded string.
     * @remarks
     * Validate at runtime to ensure the string adheres to the Base64 format.
     */
    export type Base64String = string
    
    /**
     * @typedef {string} OriginatorDomainNameString
     * Represents the fully qualified domain name (FQDN) of the application that originates the request.
     * @remarks
     * Validate at runtime to ensure the string conforms to FQDN formatting rules.
     */
    export type OriginatorDomainNameString = string
    
    /**
     * @typedef {string & { minLength: 5, maxLength: 50 }} DescriptionString5to50Characters
     * A string used for descriptions, with a length between 5 and 50 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type DescriptionString5to50Characters = string
    
    /**
     * @typedef {string & { maxLength: 300 }} BasketStringUnder300Characters
     * A string for naming baskets, with a maximum length of 300 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type BasketStringUnder300Characters = string
    
    /**
     * @typedef {string & { maxLength: 300 }} OutputTagStringUnder300Characters
     * A string for tagging outputs, with a maximum length of 300 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type OutputTagStringUnder300Characters = string
    
    /**
     * @typedef {string & { maxLength: 300 }} LabelStringUnder300Characters
     * A string for labeling transactions, with a maximum length of 300 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type LabelStringUnder300Characters = string
    
    /**
     * @typedef {Byte[]} BEEF
     * An array of integers, each ranging from 0 to 255, indicating transaction data in BEEF(BRC-62) format.
     * @remarks
     * Validate at runtime to ensure each element is within the specified range.
     */
    export type BEEF = Byte[]
    
    /**
     * @typedef {Byte[]} AtomicBEEF
     * An array of integers, each ranging from 0 to 255, indicating transaction data in Atomic BEEF(BRC-95) format.
     * @remarks
     * Validate at runtime to ensure each element is within the specified range.
     */
    export type AtomicBEEF = Byte[]
    
    /**
     * @typedef {string & { minLength: 5, maxLength: 400 }} ProtocolString5To400Characters
     * A protocol identifier with a length between 5 and 400 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type ProtocolString5To400Characters = string
    
    /**
     * @typedef {string & { maxLength: 800 }} KeyIDStringUnder800Characters
     * Represents a key identifier string, with a maximum length of 800 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type KeyIDStringUnder800Characters = string
    
    /**
     * @typedef {string & { maxLength: 50 }} CertificateFieldNameUnder50Characters
     * Represents a certificate field name with a maximum length of 50 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type CertificateFieldNameUnder50Characters = string
    
    /**
     * @typedef {string & { maxLength: 100 }} EntityNameStringMax100Characters
     * Represents a trusted entity name with a maximum length of 100 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type EntityNameStringMax100Characters = string
    
    /**
     * @typedef {string & { maxLength: 500 }} EntityIconURLStringMax500Characters
     * Represents a trusted entity icon URL with a maximum length of 500 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type EntityIconURLStringMax500Characters = string
    
    /**
     * @typedef {string & { minLength: 7, maxLength: 30 }} VersionString7To30Characters
     * Represents a version string, with a length between 7 and 30 characters.
     *
     * The format is [vendor]-[major].[minor].[patch]
     * @remarks
     * Validate at runtime for format and length compliance.
     */
    export type VersionString7To30Characters = string
    
    /**
     * @typedef {string & { minLength: 10, maxLength: 40 }} ErrorCodeString10To40Characters
     * Represents a machine-readable error code string, with a length between 10 and 40 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type ErrorCodeString10To40Characters = string
    
    /**
     * @typedef {string & { minLength: 20, maxLength: 200 }} ErrorDescriptionString20To200Characters
     * Represents a human-readable error description string, with a length between 20 and 200 characters.
     * @remarks
     * TypeScript cannot enforce length constraints. Validate at runtime for length compliance.
     */
    export type ErrorDescriptionString20To200Characters = string
    
    /**
     * The Wallet interface defines a wallet capable of various tasks including transaction creation and signing,
     * encryption, decryption, identity certificate management, identity verification, and communication
     * with applications as per the BRC standards. This interface allows applications to interact with
     * the wallet for a range of functionalities aligned with the Babbage architectural principles.
     */
    export interface Wallet {
      /**
       * Creates a new Bitcoin transaction based on the provided inputs, outputs, labels, locks, and other options.
       *
       * @param {Object} args - The arguments required to create the transaction.
       * @param {DescriptionString5to50Characters} args.description - A human-readable description of the action represented by this transaction.
       * @param {BEEF} [args.inputBEEF] - BEEF data associated with the set of input transactions from which UTXOs will be consumed.
       * @param {Array<Object>} [args.inputs] - An optional array of input objects used in the transaction.
       * @param {OutpointString} args.inputs[].outpoint - The outpoint being consumed.
       * @param {HexString} args.inputs[].unlockingScript - The unlocking script needed to release the specified UTXO.
       * @param {DescriptionString5to50Characters} args.inputs[].inputDescription - A description of this input for contextual understanding of what it consumes.
       * @param {PositiveIntegerOrZero} [args.inputs[].sequenceNumber] - An optional sequence number applied to the input.
       * @param {PositiveInteger} [args.inputs[].unlockingScriptLength] - Length of the unlocking script, in case it will be provided later using `signAction`.
       * @param {Array<Object>} [args.outputs] - An optional array of output objects for the transaction.
       * @param {HexString} args.outputs[].lockingScript - The locking script that dictates how the output can later be spent.
       * @param {SatoshiValue} args.outputs[].satoshis - Number of Satoshis that constitute this output.
       * @param {DescriptionString5to50Characters} args.outputs[].outputDescription - Description of what this output represents.
       * @param {BasketStringUnder300Characters} [args.outputs[].basket] - Name of the basket where this UTXO will be held, if tracking is desired.
       * @param {string} [args.outputs[].customInstructions] - Custom instructions attached onto this UTXO, often utilized within application logic to provide necessary unlocking context or track token histories.
       * @param {OutputTagStringUnder300Characters[]} [args.outputs[].tags] - Tags assigned to the output for sorting or filtering.
       * @param {PositiveIntegerOrZero} [args.lockTime] - Optional lock time for the transaction.
       * @param {PositiveInteger} [args.version] - Optional transaction version specifier.
       * @param {LabelStringUnder300Characters[]} [args.labels] - Optional labels providing additional categorization for the transaction.
       * @param {Object} [args.options] - Optional settings modifying transaction processing behavior.
       * @param {BooleanDefaultTrue} [args.options.signAndProcess] - Optional. If true and all inputs have unlockingScripts, the new transaction will be signed and handed off for processing by the network; result `txid` and `tx` are valid and `signableTransaciton` is undefined. If false or an input has an unlockingScriptLength, result `txid` and `tx` are undefined and `signableTransaction` is valid.
       * @param {BooleanDefaultTrue} [args.options.acceptDelayedBroadcast] - Optional. If true, the transaction will be sent to the network by a background process; use `noSend` and `sendWith` options to batch chained transactions. If false, the transaction will be broadcast to the network and any errors returned in result; note that rapidly sent chained transactions may still fail due to network propagation delays.
       * @param {'known'} [args.options.trustSelf] - Optional. If `known`, input transactions may omit supporting validity proof data for TXIDs known to this wallet or included in `knownTxids`.
       * @param {TXIDHexString[]} [args.options.knownTxids] - Optional. When working with large chained transactions using `noSend` and `sendWith` options, include TXIDs of inputs that may be assumed to be valid even if not already known by this wallet.
       * @param {BooleanDefaultFalse} [args.options.returnTXIDOnly] - Optional. If true, only a TXID will be returned instead of a transaction.
       * @param {BooleanDefaultFalse} [args.options.noSend] - Optional. If true, the transaction will be constructed but not sent to the network. Supports the creation of chained batches of transactions using the `sendWith` option.
       * @param {Array<OutPoint>} [args.options.noSendChange] - Optional. Valid when `noSend` is true. May contain `noSendChange` outpoints previously returned by prior `noSend` actions in the same batch of chained actions.
       * @param {Array<TXIDHexString>} [args.options.sendWith] - Optional. Sends a batch of actions previously created as `noSend` actions to the network; either synchronously if `acceptDelayedBroadcast` is true or by a background process.
       * @param {BooleanDefaultTrue} [args.options.randomizeOutputs] — optional. When set to false, the wallet will avoid randomizing the order of outputs within the transaction.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise returns different structures based on the outcome: error response, response with TXID, response with transaction, or info about signable transaction (partial BEEF and reference number).
       */
      createAction: (
        args: {
          description: DescriptionString5to50Characters
          inputBEEF?: BEEF
          inputs?: Array<{
            outpoint: OutpointString
            unlockingScript?: HexString
            unlockingScriptLength?: PositiveInteger
            inputDescription: DescriptionString5to50Characters
            sequenceNumber?: PositiveIntegerOrZero
          }>
          outputs?: Array<{
            lockingScript: HexString
            satoshis: SatoshiValue
            outputDescription: DescriptionString5to50Characters
            basket?: BasketStringUnder300Characters
            customInstructions?: string
            tags?: OutputTagStringUnder300Characters[]
          }>
          lockTime?: PositiveIntegerOrZero
          version?: PositiveIntegerOrZero
          labels?: LabelStringUnder300Characters[]
          options?: {
            signAndProcess?: BooleanDefaultTrue
            acceptDelayedBroadcast?: BooleanDefaultTrue
            trustSelf?: 'known'
            knownTxids?: TXIDHexString[]
            returnTXIDOnly?: BooleanDefaultFalse
            noSend?: BooleanDefaultFalse
            noSendChange?: OutpointString[]
            sendWith?: TXIDHexString[]
            randomizeOutputs?: BooleanDefaultTrue
          }
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        txid?: TXIDHexString
        tx?: AtomicBEEF
        noSendChange?: OutpointString[]
        sendWithResults?: Array<{
          txid: TXIDHexString
          status: 'unproven' | 'sending' | 'failed'
        }>
        signableTransaction?: {
          tx: AtomicBEEF
          reference: Base64String
        }
      }>
    
      /**
       * Signs a transaction previously created using `createAction`.
       *
       * @param {Object} args - Arguments to sign the transaction.
       * @param {Record<PositiveIntegerOrZero, Object>} args.spends - Map of input indexes to the corresponding unlocking script and optional sequence number.
       * @param {HexString} args.spends[].unlockingScript - The unlocking script for the corresponding input.
       * @param {PositiveIntegerOrZero} [args.spends[].sequenceNumber] - The sequence number of the input.
       * @param {Base64String} args.reference - Reference number returned from the call to `createAction`.
       * @param {Object} [args.options] - Optional settings modifying transaction processing behavior.
       * @param {BooleanDefaultTrue} [args.options.acceptDelayedBroadcast] - Optional. If true, transaction will be sent to the network by a background process; use `noSend` and `sendWith` options to batch chained transactions. If false, transaction will be broadcast to the network and any errors returned in result; note that rapidly sent chained transactions may still fail due to network propagation delays.
       * @param {'known'} [args.options.trustSelf] - Optional. If `known`, input transactions may omit supporting validity proof data for TXIDs known to this wallet or included in `knownTxids`.
       * @param {TXIDHexString[]} [args.options.knownTxids] - Optional. When working with large chained transactions using `noSend` and `sendWith` options, include TXIDs of inputs that may be assumed to be valid even if not already known by this wallet.
       * @param {BooleanDefaultFalse} [args.options.returnTXIDOnly] - Optional. If true, only a TXID will be returned instead of a transaction.
       * @param {BooleanDefaultFalse} [args.options.noSend] - Optional. If true, the transaction will be constructed but not sent to the network. Supports the creation of chained batches of transactions using the `sendWith` option.
       * @param {Array<TXIDHexString>} [args.options.sendWith] - Optional. Sends a batch of actions previously created as `noSend` actions to the network; either synchronously if `acceptDelayedBroadcast` is true or by a background process.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise returns an error response or a response with either the completed transaction or TXID.
       */
      signAction: (
        args: {
          spends: Record<
            PositiveIntegerOrZero,
            {
              unlockingScript: HexString
              sequenceNumber?: PositiveIntegerOrZero
            }
          >
          reference: Base64String
          options?: {
            acceptDelayedBroadcast?: BooleanDefaultTrue
            returnTXIDOnly?: BooleanDefaultFalse
            noSend?: BooleanDefaultFalse
            sendWith?: TXIDHexString[]
          }
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        txid?: TXIDHexString
        tx?: AtomicBEEF
        sendWithResults?: Array<{
          txid: TXIDHexString
          status: 'unproven' | 'sending' | 'failed'
        }>
      }>
    
      /**
       * Aborts a transaction that is in progress and has not yet been finalized or sent to the network.
       *
       * @param {Object} args - Arguments to identify the transaction that needs to be aborted.
       * @param {Base64String} args.reference - Reference number for the transaction to abort.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object indicating the abortion result (either success or error).
       */
      abortAction: (
        args: {
          reference: Base64String
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ aborted: true }>
    
      /**
       * Lists all transactions matching the specified labels.
       *
       * @param {Object} args - Arguments to specify how to filter or retrieve transactions.
       * @param {LabelStringUnder300Characters[]} args.labels - An array of labels used to filter actions.
       * @param {'any' | 'all'} [args.labelQueryMode] - Specifies how to match labels (default is any which matches any of the labels).
       * @param {BooleanDefaultFalse} [args.includeLabels] - Whether to include transaction labels in the result set.
       * @param {boolean} [args.includeInputs] - Whether to include input details in the result set.
       * @param {boolean} [args.includeInputSourceLockingScripts] - Whether to include input source locking scripts in the result set.
       * @param {boolean} [args.includeInputUnlockingScripts] - Whether to include input unlocking scripts in the result set.
       * @param {boolean} [args.includeOutputs] - Whether to include output details in the result set.
       * @param {boolean} [args.includeOutputLockingScripts] - Whether to include output locking scripts in the result set.
       * @param {PositiveIntegerDefault10Max10000} [args.limit] - The maximum number of transactions to retrieve.
       * @param {PositiveIntegerOrZero} [args.offset] - Number of transactions to skip before starting to return the results.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object containing actions, their metadata, inputs, and outputs if applicable, or an error object.
       */
      listActions: (
        args: {
          labels: LabelStringUnder300Characters[]
          labelQueryMode?: 'any' | 'all'
          includeLabels?: BooleanDefaultFalse
          includeInputs?: BooleanDefaultFalse
          includeInputSourceLockingScripts?: BooleanDefaultFalse
          includeInputUnlockingScripts?: BooleanDefaultFalse
          includeOutputs?: BooleanDefaultFalse
          includeOutputLockingScripts?: BooleanDefaultFalse
          limit?: PositiveIntegerDefault10Max10000
          offset?: PositiveIntegerOrZero
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        totalActions: PositiveIntegerOrZero
        actions: Array<{
          txid: TXIDHexString
          satoshis: SatoshiValue
          status:
            | 'completed'
            | 'unprocessed'
            | 'sending'
            | 'unproven'
            | 'unsigned'
            | 'nosend'
            | 'nonfinal'
          isOutgoing: boolean
          description: DescriptionString5to50Characters
          labels?: LabelStringUnder300Characters[]
          version: PositiveIntegerOrZero
          lockTime: PositiveIntegerOrZero
          inputs?: Array<{
            sourceOutpoint: OutpointString
            sourceSatoshis: SatoshiValue
            sourceLockingScript?: HexString
            unlockingScript?: HexString
            inputDescription: DescriptionString5to50Characters
            sequenceNumber: PositiveIntegerOrZero
          }>
          outputs?: Array<{
            outputIndex: PositiveIntegerOrZero
            satoshis: SatoshiValue
            lockingScript?: HexString
            spendable: boolean
            outputDescription: DescriptionString5to50Characters
            basket: BasketStringUnder300Characters
            tags: OutputTagStringUnder300Characters[]
            customInstructions?: string
          }>
        }>
      }>
    
      /**
       * Submits a transaction to be internalized and optionally labeled, outputs paid to the wallet balance, inserted into baskets, and/or tagged.
       *
       * @param {Object} args - Arguments required to internalize the transaction.
       * @param {BEEF} args.tx - Atomic BEEF-formatted transaction to internalize.
       * @param {Array<Object>} args.outputs - Metadata about outputs, processed differently based on payment or insertion types.
       * @param {PositiveIntegerOrZero} args.outputs[].outputIndex - Index of the output within the transaction.
       * @param {'payment' | 'insert'} args.outputs[].protocol - Specifies whether the output is a payment (to be received into the wallet balance) or an insert operation (into a particular basket).
       * @param {Object} [args.outputs[].paymentRemittance] - Remittance data, structured accordingly for the payment operation.
       * @param {Base64String} args.outputs[].paymentRemittance.derivationPrefix - Payment-level derivation prefix used by the sender for key derivation (for payments).
       * @param {Base64String} args.outputs[].paymentRemittance.derivationSuffix - Specific output-level derivation suffix used by the sender for key derivation (for payments).
       * @param {PubKeyHex} args.outputs[].paymentRemittance.senderIdentityKey - Public identity key of the sender (for payments).
       * @param {Object} [args.outputs[].insertionRemittance] - Remittance data, structured accordingly for the insertion operation.
       * @param {BasketStringUnder300Characters} args.outputs[].insertionRemittance.basket - Basket in which to place the output (for insertions).
       * @param {string} [args.outputs[].insertionRemittance.customInstructions] - Optionally provided custom instructions attached to the output (for insertions).
       * @param {OutputTagStringUnder300Characters[]} [args.outputs[].insertionRemittance.tags] - Tags attached to the output (for insertions).
       * @param {DescriptionString5to50Characters} args.description - Human-readable description of the transaction being internalized.
       * @param {LabelStringUnder300Characters[]} [args.labels] - Optional labels associated with this transaction.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object indicating the success of the operation or an error object.
       */
      internalizeAction: (
        args: {
          tx: AtomicBEEF
          outputs: Array<{
            outputIndex: PositiveIntegerOrZero
            protocol: 'wallet payment' | 'basket insertion'
            paymentRemittance?: {
              derivationPrefix: Base64String
              derivationSuffix: Base64String
              senderIdentityKey: PubKeyHex
            }
            insertionRemittance?: {
              basket: BasketStringUnder300Characters
              customInstructions?: string
              tags?: OutputTagStringUnder300Characters[]
            }
          }>
          description: DescriptionString5to50Characters
          labels?: LabelStringUnder300Characters[]
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ accepted: true }>
    
      /**
       * Lists the spendable outputs kept within a specific basket, optionally tagged with specific labels.
       *
       * @param {Object} args - Arguments detailing the query for listing spendable outputs.
       * @param {BasketStringUnder300Characters} args.basket - The associated basket name whose outputs should be listed.
       * @param {OutputTagStringUnder300Characters[]} [args.tags] - Filter outputs based on these tags.
       * @param {'all' | 'any'} [args.tagQueryMode] - Filter mode, defining whether all or any of the tags must match. By default, any tag can match.
       * @param {'locking scripts' | 'entire transactions'} [args.include] - Whether to include locking scripts (with each output) or entire transactions (as aggregated BEEF, at the top level) in the result. By default, unless specified, neither are returned.
       * @param {BooleanDefaultFalse} [args.includeEntireTransactions] - Whether to include the entire transaction(s) in the result.
       * @param {BooleanDefaultFalse} [args.includeCustomInstructions] - Whether custom instructions should be returned in the result.
       * @param {BooleanDefaultFalse} [args.includeTags] - Whether the tags associated with the output should be returned.
       * @param {BooleanDefaultFalse} [args.includeLabels] - Whether the labels associated with the transaction containing the output should be returned.
       * @param {PositiveIntegerDefault10Max10000} [args.limit] - Optional limit on the number of outputs to return.
       * @param {PositiveIntegerOrZero} [args.offset] - Number of outputs to skip before starting to return results.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @returns {Promise<Object>} The promise returns an output listing or an error object.
       */
      listOutputs: (
        args: {
          basket: BasketStringUnder300Characters
          tags?: OutputTagStringUnder300Characters[]
          tagQueryMode?: 'all' | 'any'
          include?: 'locking scripts' | 'entire transactions'
          includeCustomInstructions?: BooleanDefaultFalse
          includeTags?: BooleanDefaultFalse
          includeLabels?: BooleanDefaultFalse
          limit?: PositiveIntegerDefault10Max10000
          offset?: PositiveIntegerOrZero
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        totalOutputs: PositiveIntegerOrZero
        BEEF?: BEEF
        outputs: Array<{
          outpoint: OutpointString
          satoshis: SatoshiValue
          lockingScript?: HexString
          spendable: true
          customInstructions?: string
          tags?: OutputTagStringUnder300Characters[]
          labels?: LabelStringUnder300Characters[]
        }>
      }>
    
      /**
       * Relinquish an output out of a basket, removing it from tracking without spending it.
       *
       * @param {Object} args - Arguments identifying the output in the basket.
       * @param {BasketStringUnder300Characters} args.basket - The associated basket name where the output should be removed.
       * @param {OutpointString} args.outpoint - The output that should be removed from the basket.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise returns an indication of successful removal or an error object.
       */
      relinquishOutput: (
        args: {
          basket: BasketStringUnder300Characters
          output: OutpointString
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ relinquished: true }>
    
      /**
       * Retrieves a derived or identity public key based on the requested protocol, key ID, counterparty, and other factors.
       *
       * @param {Object} args - Arguments to specify which public key to retrieve.
       * @param {BooleanDefaultFalse|true} [args.identityKey] - Use true to retrieve the current user's own identity key, overriding any protocol ID, key ID, or counterparty specified.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - The security level and protocol string used for key derivation.
       * @param {KeyIDStringUnder800Characters} args.keyID - The key ID used for key derivation.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - The public key of the counterparty involved in the key derivation process.
       * @param {BooleanDefaultFalse} [args.forSelf] - Whether to return the public key derived from the current user's own identity (as opposed to the counterparty's identity).
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to an object containing the public key, or an error response.
       */
      getPublicKey: (
        args: {
          identityKey?: true
          protocolID?: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID?: KeyIDStringUnder800Characters
          privileged?: BooleanDefaultFalse
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          forSelf?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ publicKey: PubKeyHex }>
    
      /**
       * Reveals the key linkage between ourselves and a counterparty, to a particular verifier, across all interactions with the counterparty.
       *
       * @param {Object} args - Contains information about counterparty, verifier, and whether the operation is privileged.
       * @param {PubKeyHex} args.counterparty - The public key of the counterparty involved in the linkage.
       * @param {PubKeyHex} args.verifier - The public key of the verifier requesting the linkage information.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to the key linkage, or an error response.
       */
      revealCounterpartyKeyLinkage: (
        args: {
          counterparty: PubKeyHex
          verifier: PubKeyHex
          privilegedReason?: DescriptionString5to50Characters
          privileged?: BooleanDefaultFalse
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        prover: PubKeyHex
        verifier: PubKeyHex
        counterparty: PubKeyHex
        revelationTime: ISOTimestampString
        encryptedLinkage: Byte[]
        encryptedLinkageProof: Byte[]
      }>
    
      /**
       * Reveals the key linkage between ourselves and a counterparty, to a particular verifier, with respect to a specific interaction.
       *
       * @param {Object} args - The object defining the counterparty, verifier, protocol, and keyID for which linkage should be revealed.
       * @param {PubKeyHex} args.counterparty - The public key of the counterparty involved in the linkage.
       * @param {PubKeyHex} args.verifier - The public key of the verifier requesting the linkage information.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - The security level and protocol string associated with the linkage information to reveal.
       * @param {KeyIDStringUnder800Characters} args.keyID - The key ID associated with the linkage information to reveal.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise returns the requested linkage information, or an error object.
       */
      revealSpecificKeyLinkage: (
        args: {
          counterparty: PubKeyHex
          verifier: PubKeyHex
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          privileged?: BooleanDefaultFalse
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        prover: PubKeyHex
        verifier: PubKeyHex
        counterparty: PubKeyHex
        protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
        keyID: KeyIDStringUnder800Characters
        encryptedLinkage: Byte[]
        encryptedLinkageProof: Byte[]
        proofType: Byte
      }>
    
      /**
       * Encrypts the provided plaintext data using derived keys, based on the protocol ID, key ID, counterparty, and other factors.
       *
       * @param {Object} args - Information needed for encryption, including the plaintext, protocol ID, and key ID.
       * @param {Byte[]} args.plaintext - Array of bytes constituting the plaintext data to be encrypted.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - The security level and protocol string under which the data should be encrypted.
       * @param {KeyIDStringUnder800Characters} args.keyID - Key ID under which the encryption will be performed.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - Public key of the counterparty (if two-party encryption is desired).
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to the encrypted ciphertext bytes or an error if encryption fails.
       */
      encrypt: (
        args: {
          plaintext: Byte[]
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          privileged?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ ciphertext: Byte[] }>
    
      /**
       * Decrypts the provided ciphertext using derived keys, based on the protocol ID, key ID, counterparty, and other factors.
       *
       * @param {Object} args - Contains the ciphertext, protocol ID, and key ID required to decrypt the data.
       * @param {Byte[]} args.ciphertext - Encrypted bytes, including the initialization vector, for decryption.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - Security level and protocol string that were used during the encryption of the ciphertext.
       * @param {KeyIDStringUnder800Characters} args.keyID - Key ID used during the encryption of the ciphertext.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - Public identity key of the counterparty for the encryption operation.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to the decryption result, containing the plaintext data or an error.
       */
      decrypt: (
        args: {
          ciphertext: Byte[]
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          privileged?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ plaintext: Byte[] }>
    
      /**
       * Creates an HMAC (Hash-based Message Authentication Code) based on the provided data, protocol, key ID, counterparty, and other factors.
       *
       * @param {Object} args - Arguments containing the data, protocol ID, and key ID to generate the HMAC from.
       * @param {Byte[]} args.data - Input data (in bytes) for which the HMAC needs to be created.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - Security level and protocol string to be used during the HMAC operation.
       * @param {KeyIDStringUnder800Characters} args.keyID - Key ID to be used in the HMAC operation.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - Public identity key of the counterparty if the operation encompasses a two-party interaction.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to an object containing the generated HMAC bytes, or an error if the creation fails.
       */
      createHmac: (
        args: {
          data: Byte[]
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          privileged?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ hmac: Byte[] }>
    
      /**
       * Verifies an HMAC (Hash-based Message Authentication Code) based on the provided data, protocol, key ID, counterparty, and other factors.
       *
       * @param {Object} args - Arguments containing the HMAC data, protocol ID, and key ID needed for verification.
       * @param {Byte[]} args.data - The input data whose HMAC is to be verified.
       * @param {Byte[]} args.hmac - Byte array representing the HMAC value to be verified.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - Security level and protocol string to be used during the HMAC operation.
       * @param {KeyIDStringUnder800Characters} args.keyID - Key ID to be used during the HMAC operation.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - Public identity key of the counterparty if the operation encompasses a two-party interaction.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to an object confirming whether the HMAC was valid or an error.
       */
      verifyHmac: (
        args: {
          data: Byte[]
          hmac: Byte[]
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          privileged?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ valid: true }>
    
      /**
       * Creates a digital signature for the provided data or hash using a specific protocol, key, and optionally considering privilege and counterparty.
       *
       * @param {Object} args - Arguments to specify data, protocol, key ID, and privilege for creating the signature.
       * @param {Byte[]} [args.data] - Data to be signed using the derived private key with ECDSA. Required unless directly signing a hash.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - Security level and protocol string to be used during the signing operation.
       * @param {KeyIDStringUnder800Characters} args.keyID - Key ID to be used during the signing operation.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - Public identity key of the counterparty if the operation encompasses a two-party interaction.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {Byte[]} [args.hashToDirectlySign] - Sign a pre-hashed value in situations where data can't or shouldn't be revealed, whether due to its size or for privacy.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise will resolve to an object containing the DER-encoded ECDSA signature, or an error on failure.
       */
      createSignature: (
        args: {
          data?: Byte[]
          hashToDirectlySign?: Byte[]
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          privileged?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ signature: Byte[] }>
    
      /**
       * Verifies a digital signature for the provided data or hash using a specific protocol, key, and optionally considering privilege and counterparty.
       *
       * @param {Object} args - Arguments specifying the data, signature, protocol, and key ID.
       * @param {Byte[]} [args.data] - The data originally signed, which is required for verification unless directly verifying a hash.
       * @param {Byte[]} args.signature - The DER-encoded ECDSA signature to validate.
       * @param {[0 | 1 | 2, ProtocolString5To400Characters]} args.protocolID - Security level and protocol string to be used during signature verification.
       * @param {KeyIDStringUnder800Characters} args.keyID - Key ID to be used during signature verification.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {PubKeyHex | 'self' | 'anyone'} [args.counterparty] - Public identity key of the counterparty if the operation encompasses a two-party interaction.
       * @param {BooleanDefaultFalse} [args.forSelf] - Whether the signature to be verified was created by this user rather than the counterparty.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {Byte[]} [args.hashToDirectlyVerify] - Optional field to verify the signature against a precomputed hash instead of data.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to a boolean object indicating whether the signature was valid or an error message.
       */
      verifySignature: (
        args: {
          data?: Byte[]
          hashToDirectlyVerify?: Byte[]
          signature: Byte[]
          protocolID: [0 | 1 | 2, ProtocolString5To400Characters]
          keyID: KeyIDStringUnder800Characters
          privilegedReason?: DescriptionString5to50Characters
          counterparty?: PubKeyHex | 'self' | 'anyone'
          forSelf?: BooleanDefaultFalse
          privileged?: BooleanDefaultFalse
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ valid: true }>
    
      /**
       * Acquires an identity certificate, whether by acquiring one from the certifier or by directly receiving it.
       *
       * @param {Object} args - Contains the type of certificate, certifier information, and fields of the certificate to be provided, among other details.
       * @param {Base64String} args.type - Type identifier for the certificate.
       * @param {PubKeyHex} args.certifier - The public identity key of the certifier.
       * @param {'issuance' | 'direct'} args.acquisitionProtocol - Specifies the acquisition process, set to either 'issuance' or 'direct'.
       * * @param {Record<CertificateFieldNameUnder50Characters, string>} args.fields - The fields included within the certificate.
       * @param {Base64String} [args.serialNumber] - Serial number of the certificate to acquire (required when the acquisition protocol is direct).
       * @param {string} [args.revocationOutpoint] - Reference for an outpoint comprising a Bitcoin token that, if ever spent, marks the certificate as invalid (required when the acquisition protocol is direct).
       * @param {HexString} [args.signature] - Signature over the certificate (required when the acquisition protocol is direct).
       * @param {string} [args.certifierUrl] - URL of the certifier where certificate acquisition requests will be sent (required when the acquisition protocol is issuance).
       * @param {PubKeyHex | 'certifier'} [args.keyringRevealer] - The public identity key of the entity revealing the keyring to the user, if different from the certifier (required when the acquisition protocol is direct).
       * @param {Record<CertificateFieldNameUnder50Characters, Base64String>} [args.keyringForSubject] - Keyring revealing all certificate fields to the subject (required when the acquisition protocol is direct).
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object containing the acquired certificate, or an error object.
       */
      acquireCertificate: (
        args: {
          type: Base64String
          certifier: PubKeyHex
          acquisitionProtocol: 'direct' | 'issuance'
          fields: Record<CertificateFieldNameUnder50Characters, string>
          serialNumber?: Base64String
          revocationOutpoint?: OutpointString
          signature?: HexString
          certifierUrl?: string
          keyringRevealer?: PubKeyHex | 'certifier'
          keyringForSubject?: Record<
            CertificateFieldNameUnder50Characters,
            Base64String
          >
          privileged?: BooleanDefaultFalse
          privilegedReason?: DescriptionString5to50Characters
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        type: Base64String
        subject: PubKeyHex
        serialNumber: Base64String
        certifier: PubKeyHex
        revocationOutpoint: OutpointString
        signature: HexString
        fields: Record<CertificateFieldNameUnder50Characters, string>
      }>
    
      /**
       * Lists identity certificates belonging to the user, filtered by certifier(s) and type(s).
       *
       * @param {Object} args - Arguments used to filter or limit the list of certificates returned by the request.
       * @param {PubKeyHex[]} args.certifiers - An array of public keys for specific certifiers (filters by these certifiers).
       * @param {Base64String[]} args.types - An array of certificate types issued by any of the specified certifiers, which should be returned.
       * @param {PositiveIntegerDefault10Max10000} [args.limit] - Maximum number of certificates to return.
       * @param {PositiveIntegerOrZero} [args.offset] - Number of records to skip before starting to return results.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object containing certificates or an error response.
       */
      listCertificates: (
        args: {
          certifiers: PubKeyHex[]
          types: Base64String[]
          limit?: PositiveIntegerDefault10Max10000
          offset?: PositiveIntegerOrZero
          privileged?: BooleanDefaultFalse
          privilegedReason?: DescriptionString5to50Characters
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        totalCertificates: PositiveIntegerOrZero
        certificates: Array<{
          type: Base64String
          subject: PubKeyHex
          serialNumber: Base64String
          certifier: PubKeyHex
          revocationOutpoint: OutpointString
          signature: HexString
          fields: Record<CertificateFieldNameUnder50Characters, string>
        }>
      }>
    
      /**
       * Proves select fields of an identity certificate, as specified, when requested by a verifier.
       *
       * @param {Object} args - Arguments including the certificate, fields to reveal, and verifier's public key.
       * @param {Object} args.certificate - The specific identity certificate being proven.
       * @param {Base64String} args.certificate.type - The type of the certificate to be proven.
       * @param {PubKeyHex} args.certificate.subject - Public key belonging to the certificate's subject.
       * @param {Base64String} args.certificate.serialNumber - Unique serial number of the certificate.
       * @param {PubKeyHex} args.certificate.certifier - Public key of the certifier who issued the certificate.
       * @param {OutpointString} args.certificate.revocationOutpoint - The outpoint used to confirm that the certificate has not been revoked.
       * @param {HexString} args.certificate.signature - Certificate signature by the certifier's private key.
       * @param {Record<CertificateFieldNameUnder50Characters, string>} args.certificate.fields - All the encrypted fields present in the certificate.
       * @param {CertificateFieldNameUnder50Characters[]} args.fieldsToReveal - Array of field names that need to be revealed to the verifier.
       * @param {PubKeyHex} args.verifier - Public key of the verifier, to whom the key revelations will be made.
       * @param {BooleanDefaultFalse} [args.privileged] - Whether this is a privileged request.
       * @param {DescriptionString5to50Characters} [args.privilegedReason] - Reason provided for privileged access, required if this is a privileged operation.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to a keyring for the verifier or an error object.
       */
      proveCertificate: (
        args: {
          certificate: {
            type: Base64String
            subject: PubKeyHex
            serialNumber: Base64String
            certifier: PubKeyHex
            revocationOutpoint: OutpointString
            signature: HexString
            fields: Record<CertificateFieldNameUnder50Characters, string>
          }
          fieldsToReveal: CertificateFieldNameUnder50Characters[]
          verifier: PubKeyHex
          privileged?: BooleanDefaultFalse
          privilegedReason?: DescriptionString5to50Characters
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        keyringForVerifier: Record<
          CertificateFieldNameUnder50Characters,
          Base64String
        >
      }>
    
      /**
       * Relinquishes an identity certificate, removing it from the wallet regardless of whether the revocation outpoint has become spent.
       *
       * @param {Object} args - Contains the type of certificate, certifier, and serial number for relinquishment.
       * @param {Base64String} args.type - Type identifier for the certificate.
       * @param {PubKeyHex} args.certifier - The public identity key of the certifier.
       * @param {Base64String} args.serialNumber - Serial number of the certificate to relinquish.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an indication of successful relinquishment or an error object.
       */
      relinquishCertificate: (
        args: {
          type: Base64String
          serialNumber: Base64String
          certifier: PubKeyHex
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{ relinquished: true }>
    
      /**
       * Discovers identity certificates, issued to a given identity key by a trusted entity.
       *
       * @param {Object} args - Arguments for requesting the discovery based on the identity key.
       * @param {PubKeyHex} args.identityKey - Identity key used to filter and discover certificates.
       * @param {PositiveIntegerDefault10Max10000} [args.limit] - Maximum number of certificates to return in the response.
       * @param {PositiveIntegerOrZero} [args.offset] - Skip this number of records before starting to provide results.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to the list of certificates discovered or an error object.
       */
      discoverByIdentityKey: (
        args: {
          identityKey: PubKeyHex
          limit?: PositiveIntegerDefault10Max10000
          offset?: PositiveIntegerOrZero
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        totalCertificates: PositiveIntegerOrZero
        certificates: Array<{
          type: Base64String
          subject: PubKeyHex
          serialNumber: Base64String
          certifier: PubKeyHex
          revocationOutpoint: OutpointString
          signature: HexString
          fields: Record<CertificateFieldNameUnder50Characters, Base64String>
          certifierInfo: {
            name: EntityNameStringMax100Characters
            iconUrl: EntityIconURLStringMax500Characters
            description: DescriptionString5to50Characters
            trust: PositiveIntegerMax10
          }
          publiclyRevealedKeyring: Record<
            CertificateFieldNameUnder50Characters,
            Base64String
          >
          decryptedFields: Record<CertificateFieldNameUnder50Characters, string>
        }>
      }>
    
      /**
       * Discovers identity certificates belonging to other users, where the documents contain specific attributes, issued by a trusted entity.
       *
       * @param {Object} args - Attributes and optional parameters used to discover certificates.
       * @param {Record<CertificateFieldNameUnder50Characters, string>} args.attributes - The attributes used to discover the certificates.
       * @param {PositiveIntegerDefault10Max10000} [args.limit] - Optional limit on the number of results returned.
       * @param {PositiveIntegerOrZero} [args.offset] - Starts retrieval of results after the specified number of records.
       * @param {BooleanDefaultTrue} [args.seekPermission] — Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to a list of matching certificates or an error object.
       */
      discoverByAttributes: (
        args: {
          attributes: Record<CertificateFieldNameUnder50Characters, string>
          limit?: PositiveIntegerDefault10Max10000
          offset?: PositiveIntegerOrZero
          seekPermission?: BooleanDefaultTrue
        },
        originator?: OriginatorDomainNameString
      ) => Promise<{
        totalCertificates: PositiveIntegerOrZero
        certificates: Array<{
          type: Base64String
          subject: PubKeyHex
          serialNumber: Base64String
          certifier: PubKeyHex
          revocationOutpoint: OutpointString
          signature: HexString
          fields: Record<CertificateFieldNameUnder50Characters, Base64String>
          certifierInfo: {
            name: EntityNameStringMax100Characters
            iconUrl: EntityIconURLStringMax500Characters
            description: DescriptionString5to50Characters
            trust: PositiveIntegerMax10
          }
          publiclyRevealedKeyring: Record<
            CertificateFieldNameUnder50Characters,
            Base64String
          >
          decryptedFields: Record<CertificateFieldNameUnder50Characters, string>
        }>
      }>
    
      /**
       * Checks the authentication status of the user.
       *
       * @param {Object} args - Empty object, as no parameters are needed.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object indicating whether the user is authenticated or an error response.
       */
      isAuthenticated: (
        args: {},
        originator?: OriginatorDomainNameString
      ) => Promise<{ authenticated: boolean }>
    
      /**
       * Continuously waits until the user is authenticated, returning the result once confirmed.
       *
       * @param {Object} args - Not used, pass an empty object.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The final result indicating that the user is authenticated or an error object.
       */
      waitForAuthentication: (
        args: {},
        originator?: OriginatorDomainNameString
      ) => Promise<{ authenticated: true }>
    
      /**
       * Retrieves the current height of the blockchain.
       *
       * @param {Object} args - Empty object as no other parameters are necessary.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to an object indicating the current height or an error on failure.
       */
      getHeight: (
        args: {},
        originator?: OriginatorDomainNameString
      ) => Promise<{ height: PositiveInteger }>
    
      /**
       * Retrieves the block header of a block at a specified height.
       *
       * @param {Object} args - Contains the height parameter needed to retrieve the block header.
       * @param {PositiveInteger} args.height - Specifies the height at which the block header needs to be retrieved.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an 80-byte block header or an error if it cannot be retrieved.
       */
      getHeaderForHeight: (
        args: { height: PositiveInteger },
        originator?: OriginatorDomainNameString
      ) => Promise<{ header: HexString }>
    
      /**
       * Retrieves the Bitcoin network the client is using (mainnet or testnet).
       *
       * @param {Object} args - No arguments required, pass an empty object.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} The promise resolves to an object indicating whether the client is using the mainnet or testnet.
       */
      getNetwork: (
        args: {},
        originator?: OriginatorDomainNameString
      ) => Promise<{ network: 'mainnet' | 'testnet' }>
    
      /**
       * Retrieves the current version string of the wallet.
       *
       * @param {Object} args - Empty argument object.
       * @param {OriginatorDomainNameString} [originator] - Fully-qualified domain name (FQDN) of the application that originated the request.
       * @returns {Promise<Object>} Resolves to an object containing the version string of the wallet, or an error.
       */
      getVersion: (
        args: {},
        originator?: OriginatorDomainNameString
      ) => Promise<{ version: VersionString7To30Characters }>
    }