Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Ty Everett (ty@projectbabbage.com)
We define a mechanism for requesting and receiving digital signatures over the abstract communications channel first described by BRC-1. We rely on the BRC-43 invoice numbering and permission scheme on top of BRC-42 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 BRC-42 shared secret, no third parties can discover the correct child public key, making then unable to validate the signature.
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.
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 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.
The signature creation request is a message sent by the BRC-43 application to the client. It contains a header with the following information:
protocolID
keyID
counterparty
The message payload comprises the data to sign.
The response message comprises the ECDSA digital signature in DER format.
The signature verification request is a message sent by the application to the client. It contains a header with the following information:
protocolID
keyID
counterparty
signature
The DER-formatted signature for verification
The message payload comprises the data to verify.
The response message comprises a JSON payload containing the following fields:
result
The value is true
if the signature is valid, otherwise it is false
.
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:
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:
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:
This digital signature capability is incorporated into the Babbage SDK
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.
To participate in discussions about existing proposals, simply open an issue and link back to the BRC file in question.
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.
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.
Ty Everett (ty@projectbabbage.com)
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 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.
Here is an example of a Transaction Creation Request object that contains an input:
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.
The key ID
The counterparty, anyone
or self
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.
The key ID
The counterparty, self
or anyone
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.
Read more about areas of interest on
Refer to the for a fun example template you can copy when proposing your own standards.
Everything in this repository is subject to the .
We define a mechanism by which applications can denote UTXOs to be unlocked and redeemed by wallets as part of new Bitcoin transactions. We extend the message format defined by 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.
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.
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.
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.
This functionality has been implemented as part of the , in the createAction
function.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(unused, will assign next BRC to this number)
36
37
38
User Wallet Data Format
39
User Wallet Data Format Encryption Extension
40
User Wallet Data Synchronization
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
Jane Doe (jane.doe@example.com)
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.
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.
Wallets must be embedded within a real banana fruit, using cutting-edge bio-organic engineering techniques.
Web-based applications must communicate with the banana-embedded wallet using a Banana Communication Protocol (BCP)1 involving a series of gentle squeezes.
Squeezes will be translated into binary code, with a short squeeze representing '0' and a long squeeze representing '1'.
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.
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.
Wallet developers must carefully select the finest bananas available, ensuring they are both ripe and durable.
A custom JavaScript library, BananaJS, must be developed for web-based applications to interact with the wallet using the BCP.
Wallet applications must include a sophisticated squeeze detection system to ensure accurate communication.
Wallet developers must implement a "peel screech" alarm system for added security.
Web-based applications must visually display the connection and energy status of each banana wallet.
The Implementations section should contain information about places where the standard is implemented, or examples of its implementation.
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.
Brayden Langley (brayden@projectbabbage.com)
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 BRC-9. The required message structure and fields are defined below in the Payment Submission Message section, and the expected response to provide is defined in the Payment Acknowledgment Message 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.
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.
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.
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.
protocol
(string, required)
transaction
(object, required)
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
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.
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:
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:
If an error occurs during submission, an internal error should be thrown which can be caught and handled by the application code.
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.
Ty Everett (ty@projectbabbage.com)
We define an extension to BRC-1 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 BRC-43 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 BRC-1 transaction creation requests.
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.
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:
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:
basket
yes
The basket from which outputs should be returned
includeEnvelope
no
limit
no
The maximum number of outputs to return
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
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.
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:
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
envelope
Here is an example of a simple Transaction Outputs Response:
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:
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:
This functionality is implemented as part of the Babbage SDK, via the getTransactionOutputs
function.
Ty Everett (ty@projectbabbage.com)
We define methods for an application to request that a wallet create and prove BRC-52 identity certificates. We define a set of additional messages that extend the BRC-1 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.
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.
We define two new sets of messages to be sent over the abstract BRC-1 messaging layer:
An application may request a wallet to create a BRC-52 certificate by providing the following parameters:
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:
Initialize a BRC-53 client with the primary identity key of the wallet.
Generate a client nonce.
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.
Validate the received serialNumber
and validationKey
using the client and server nonces.
Encrypt the fields of the fieldObject
using BRC-2 encryption and store the concealed fields and encrypted field revelation keys in the fields and keyring objects, respectively.
Create a Certificate Signing Request (CSR) containing the certificate type, nonces, validation key, serial number, fields, and keyring.
Send the CSR to the certifier's /signCertificate
endpoint via an HTTP POST request.
Receive and verify the signed certificate's authenticity.
Store the signed certificate in the wallet's data store (how the wallet stores its data is beyond the scope of this specification).
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.
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:
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:
An application may request a wallet to prove a BRC-52 certificate by providing the following parameters:
certificate
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:
Verify the authenticity of the provided certificate.
Ensure that the application and the verifier have been granted access to the requested certificate fields (optional permissions checks).
Decrypt the encrypted field revelation keys using the wallet's primary identity key.
Encrypt the decrypted field revelation keys for the verifier using the verifierPublicIdentityKey
.
Add the encrypted field revelation keys to the certificate field revelation keyring (as defined in BRC-52) object.
Attach the field revelation keyring to the certificate.
Return the certificate with the attached field revelation keyring for presentation to the verifier for field examination.
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.
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:
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:
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.
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.
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 BRC-52 certificate, if the signing process is successful.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
Wallets that meet these pre-requisites will be able to fulfill the requirements of this specification.
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, BRC-4. We have also chosen to exclude transaction output tracking from the base specification, moving it to BRC-46.
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 BRC-1 protocol, as opposed to some other protocol.
For example, if the underlying communications method was HTTP (BRC-5), 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 BRC-1 protocol. Specific communication mechanisms that facilitate this are defined by other standards such as BRC-5, BRC-6 and BRC-7.
We specify that the first message exchanged under this BRC-1 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:
description
A present-tense, human-readable description of the action being performed or represented by this transaction.
outputs
An array of Output Objects.
Output Objects are JSON objects that have the following fields:
script
satoshis
The number of satoshis that are to be in the output, given as a positive integer.
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 (BRC-16) 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.
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 BRC-8 Transaction Envelope and returns it to the user. We specify that, in addition to the required BRC-8 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 BRC-8 Transaction Envelope fields with our additional txid
field:
rawTx
inputs
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
txid
The Bitcoin TXID associated with this transaction
Here is an example of a simple Transaction Creation Response:
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:
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.
One example of a Transaction Creation Error is given below:
This specification has been implemented into various wallets and applications:
The Babbage MetaNet Client implements BRC-5, 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.
1: Transaction responses are BRC-8 Transaction Envelopes
Brayden Langley (brayden@projectbabbage.com)
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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
We define standardized HTTP requests that applications can use to communicate with wallets for performing various tasks.
POST
createAction
No Params
JSON
JSON
POST
encrypt
Binary or String
Binary
POST
decrypt
Binary or String
Binary
POST
createSignature
No Params
JSON
Binary
POST
verifySignature
Binary or String
JSON
POST
createCertificate
No Params
JSON
JSON
POST
proveCertificate
No Params
JSON
JSON
POST
createHmac
Binary or String
Binary
POST
verifyHmac
Binary or String
Boolean
GET
getPublicKey
None
JSON
POST
findCertificates
No Params
JSON
JSON
GET
getVersion
No Params
None
String
POST
getNetwork
No Params
None
String
GET
isAuthenticated
No Params
None
JSON
POST
waitForAuthentication
No Params
JSON
JSON
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.
Brayden Langley (brayden@projectbabbage.com)
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.
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.
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.
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:
window.CWI.createAction()
window.CWI.encrypt()
window.CWI.decrypt()
window.CWI.createSignature()
window.CWI.verifySignature()
window.CWI.createCertificate()
window.CWI.proveCertificate()
window.CWI.createHmac()
window.CWI.verifyHmac()
window.CWI.getPublicKey()
window.CWI.findCertificates
window.CWI.getVersion()
window.CWI.getNetwork()
window.CWI.isAuthenticated()
window.CWI.waitForAuthentication()
This will allow applications to call functions with the following syntax:
We specify that all required parameters are provided in an object to the CWI functions.
Example Identity Key Request
Example Encrypt Function
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
There are four primary permission types that apps can be granted by users, each with its significance, function, and associated specifications:
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).
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.
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.
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.
Applications initiate the permission request process via a new requestGroupPermission
function, which is added to the BRC-56 suite.
Wallets determine the group permissions from the application's manifest.json
file. Alternatively, the groupPermissions
object can be provided by the application to the requestGroupPermission
function.
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.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
key holds four subsequent keys representing the categories of permissions: protocolPermissions
, spendingAuthorization
, basketAccess
, and certificateAccess
.
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
.
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).
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
.
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
.
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
.
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.
protocolPermissions Example:
spendingAuthorization Example:
basketAccess Example:
certificateAccess Example:
Full manifest.json 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.
Ty Everett (ty@projectbabbage.com)
When an application sends a message to a client requesting that data be encrypted, the message comprises:
The data to encrypt
We stipulate the following process for encryption:
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
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 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
The message payload comprises the data to encrypt.
The response message comprises a payload containing the encrypted ciphertext, prepended with the 32-byte initialization vector.
The decryption request is a message sent by the application to the client. It contains a header with the following information:
The message payload comprises the data to decrypt, prepended with the 32-byte initialization vector.
The response message comprises a payload containing the decrypted plaintext.
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:
One example of a Cryptography Error is given below:
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:
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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.
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:
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 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.
This field denotes that the JSON object comprises a payment message according to the given protocol (such as 3241645161d8
for ).
The transaction envelope to submit, including key derivation information (the "Outputs Extension" as defined in )
Whether transaction envelopes are requested for the outputs
If envelopes were requested, the Transaction Envelope for this transaction
The certificate to be proven.
A hex-formatted Bitcoin output script, as defined in .
The transaction in hex format
An object whose keys are the TXIDs of all inputs to this transaction and whose values are envelopes for the respective transactions (the child envelopes are not required to contain the extra txid
field), (required unless proof
is provided)
A merkle proof for the transaction in JSON format (required unless inputs
and mapiResponses
are given)
Transaction Creation
Encryption
defined
Decryption
defined
Signature Creation
Signature Verification
defined
Certificate Creation
Certificate Verification
HMAC Creation
defined
HMAC Verification
defined
Public Key Derivation
defined
Certificate List
Version Request
Network Request
Authentication Request
Async Auth Request
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.
The Bitcoin ecosystem has demonstrated a clear desire for wallets to support data encryption between parties. 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 applications. 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 key derivation. The standard aims to fill this gap and provide a secure and standardized framework for encryption and decryption within the Bitcoin ecosystem.
We start with the same constructs defined in : users with clients, protocols and applications. We stipulate the use of invoice numbers in the context of key derivation, and we build on top of the permissions architecture defined by .
The security level, protocol ID, key ID and counterparty to facilitate key derivation and permissioning
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
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.
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
We build upon the abstract messaging layer first described in . Specifically, we define five new 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.
The encryption request is a message sent by the application to the client. It contains a header with the following information:
This encryption capability is incorporated into the
1:
2:
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
Contains Certificate Field Access Grant requests.
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
Justification for the request, less than 50 characters.
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
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.
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).
Ty Everett (ty@projectbabbage.com)
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.
The motivation for this proposal is to future-proof the BRC-46 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.
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 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.
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.
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.
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.
This specification allows future permission schemes to extend beyond current BRC-46 models (e.g. BRC-73 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.
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.
Ty Everett (ty@projectbabbage.com)
The BRC-43 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.
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.
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 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.
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.
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.
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.
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.
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.
Tone Engel (tone@kizmet.org), TonesNotes
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": TSC Merkle proof standardised format
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."
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.
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
:
Block Hash
existing
0
'hash' (default)
32 bytes
64 hex chars
Block Header
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
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.
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.
The "Spec": TSC Merkle proof standardised format
Ty Everett (ty@projectbabbage.com)
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 BRC-9, by providing a standardized methodology for exchanging merkle proofs and input transactions.
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.
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 BRC-10 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 BRC-10 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.
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.
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.
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.
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.
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.
This BRC is licensed under the Open BSV license.
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.
Current Transaction format:
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
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
The Extended Format adds a marker to the transaction format:
Version no
currently 2
4 bytes
EF marker
marker for extended format
0000000000EF
In-counter
positive integer VI = [[VarInt]]
1 - 9 bytes
list of inputs
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
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:
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
Txin-script / scriptSig
Script
-many bytes
Sequence_no
Used to iterate inputs inside a payment channel. Input is final when nSequence = 0xFFFFFFFF
4 bytes
In the Extended Format, we extend the input structure to include the previous locking script and satoshi outputs:
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
Txin-script / scriptSig
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
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.
The Extended Format has been implemented in go-bt and a standalone JavaScript library bitcoin-ef.
Ty Everett (ty@projectbabbage.com)
Brayden Langley (brayden@projectbabbage.com)
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.
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.
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:
BRC-1: We incorporate by reference the message types relating to Bitcoin transaction creation as specified by BRC-1. 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.
BRC-3: We incorporate by reference the message types relating to digital signatures as specified by BRC-3. 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.
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.
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 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 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.
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 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 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
The HMAC Creation Request is a message sent by the BRC-43 application to the client. It contains a header with the following information:
protocolID
keyID
counterparty
The message payload comprises the data to HMAC.
The response message comprises a payload containing the computed HMAC value.
The HMAC Verification Request is a message sent by the application to the client. It contains a header with the following information:
protocolID
keyID
counterparty
hmac
This is the HMAC value that is to be verified, for the provided message
The message payload comprises the data to verify against the HMAC provided in the header.
The response message comprises a payload containing a boolean that indicates whether the HMAC was successfully verified.
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:
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 an HMAC Error is given below:
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. BRC-43 is used for defining the protocolID and keyID formats, and BRC-52 defines the format of certificates requested.
To request a public key, we define the following standard request fields:
protocolID
keyID
counterparty
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
.
When the wallet receives this request from the application, after obtaining requisite permission from the user, we stipulate the following process for key derivation:
If identityKey
is true, the wallet returns its root public identity key to the application without proceeding to the other steps.
The wallet checks the BRC-43 invoice number based on the security level, protocol ID, and key ID
If forSelf
is false
, the wallet uses BRC-42 key derivation with the computed invoice number to derive a child public key for the counterparty, returning the public key.
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.
The response message comprises a 33-byte, DER-encoded public key X coordinate value.
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:
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 Public Key Error is given below:
To request a list of BRC-52 identity certificates belonging to the user, we define these standard request fields:
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.
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.
The response from the wallet to the application comprises an array of BRC-52 identity certificates, which may be empty.
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:
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 List Error is given below:
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.
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.
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
.
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.
The asynchronous authentication request requires no parameters and waits until the user is authenticated before returning a response of true.
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:
BRC-5, for operating a wallet over HTTP on a local machine, enabling applications on that machine to interact with the running wallet.
BRC-6, for cross-document messaging between a parent page which runs a wallet and a set of child pages which run various applications.
BRC-7, 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 Babbage SDK.
Ty Everett (ty@projectbabbage.com)
_unwriter
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).
The TXO format represents a Bitcoin transaction as a JSON object with the following high-level structure:
At the top level, the TXO format includes two objects: tx and blk.
tx
(transaction): contains:
h
(transaction hash)
r
(raw transaction)
blk
(block): contains:
i
(block index)
h
(block hash)
t
(block time)
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.
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.
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.
To implement the TXO format, follow these steps:
Deserialize the raw Bitcoin transaction into its input and output scripts.
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.
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).
Ensure compatibility with the TXO format by including all specified fields and adhering to the defined structure.
Deggen (deggen@kschw.com)
We propose a binary format for a Single Merkle Path optimized for storage in a key value database.
This BRC is licensed under the Open BSV license.
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.
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
Deggen (deggen@kschw.com) Damian Orzepowski (damian.orzepowski@4chain.studio)
We propose a binary format for Compound Merkle Paths (CMP hereon) optimized for minimal data bandwidth during transmission.
This BRC is licensed under the Open BSV license.
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.
For each level of the merkle path the opposite hash from the one which can be calculated is provided.
Formatting Syntax
offset
andleaf
are repeated fornLeaves
at each height
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. Onceheight === -1
we stop parsing.
nLeaves
is repeated for each height, followed by the correspondingoffset
andleaf
for each.
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:
By convention we reverse the bytes of a txid hex string so these sequences will be seen in their inverse endian form below.
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
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.
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.
Deggen (deggen@kschw.com) Damian Orzepowski (damian.orzepowski@4chain.studio) Wojciech Regulski (wojciech.regulski@4chain.studio) Arkadiusz Osowski (arkadiusz.osowski@4chain.studio)
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.
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.
This BRC is licensed under the Open BSV license.
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:
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.
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.
BEEF combines thinking from several formats into one binary stream, prefixed with a very specific version number for disambiguation.
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.
We parse the BUMPs storing each in an array so that we can address them by index later.
We parse each transaction.
RawTx bytes double sha256 to get the txid.
Store in hashmap from txid => parsedTx
If there is a Merkle path after the tx then we lookup the BUMP using the BUMP index number.
Lookup the txid within level 0 leaves of the BUMP to get the index of the txid within a block.
Calculate the Merkle root with the index, txid, and BUMP data.
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.
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.
Check the txid exists in memory, and is marked as valid.
Check that all scripts evaluate to TRUE.
Check that the sum of satoshis in > satoshis out + fee
Mark the tx as valid.
We make a request to the local header service as soon as we have all merkle roots calculated.
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.
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.
Ty Everett (ty@projectbabbage.com)
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:
External Verification: Proof verification is expected to be performed by external systems or verifiers, not within the wallet itself.
We build on the existing standards:
This proposal extends these standards by defining an extensible proof-type format for specific key linkage claims (Method 2).
Specific Key Revelations: Encrypted according to BRC-72, including the linkage offset and the proof payload defined herein.
We define a binary format for the encrypted Schnorr proof payload for counterparty-level revelations:
We define a binary format for the encrypted payload for specific key linkage proofs:
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.
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.
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.
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.
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 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.
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.
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.
The key ID
The counterparty, or self
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.
The key ID
The counterparty, or self
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.
The key ID
The counterparty, self
, or anyone
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.
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 , which are also referenced by their BRC numbers.
You can read the TSC standard .
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.
The reference implementation was written by _unwriter of the 21st Century Motor Company and is available .
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.
We take the JSON version from eg.
We propose a binary format for sending Transactions between peers to allow (SPV). The format is optimized for minimal bandwidth while maintaining data required to independently validate the transaction in full.
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.
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.
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.
Raw Transaction Format:
BSV Universal Merkle Path (BUMP):
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.
The format will be built into BUX to begin real world testing. Thereafter common libraries such as and for easy incorporation into existing stacks.
This BRC proposes an extensible format for including zero-knowledge proofs (ZKPs) in specific key linkage revelations as per Method 2. While addresses limitations of 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.
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.
Non-Interactive Proofs: Only non-interactive proof schemes are considered, as per existing standards like .
Encrypted Proof Payloads: Proof payloads are encrypted according to to ensure confidentiality during transmission.
: 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).
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 .
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.
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.
Confidentiality: All proof payloads must be encrypted as per to ensure that sensitive linkage information is protected during transit.
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
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
leaf
Each leaf is a 32 byte hash
32 bytes
0
e86ec5732f55490a73677fe88a37c875cea49f572e4bc822b83fe96093bb008c
3
3b5a16dc41bbed3e58ad2a9017fb8954e7541975e2a4f37343761d96f431b3e5
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
nTransactions
VarInt number of transactions which follow
1-9 bytes
Raw Transaction
RawTx bytes as in standard format BRC-12
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
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
.
Darren Kellenschwiler (deggen@kschw.com), Deggen Tone Engel (tone@kizmet.org), TonesNotes Ty Everett (ty@projectbabbage.com) Damian Orzepowski (damian.orzepowski@4chain.studio) Arkadiusz Osowski (arkadiusz.osowski@4chain.studio)
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.
This BRC is licensed under the Open BSV license.
BUMP Showcase can help form an understanding of how BUMP works to encode all necessary data.
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.
BRC-61 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.
The top level encoding specifies a block height and a tree height.
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
Thereafter the number of leaves at the top height is specified, and the leaves for this height follow.
nLeaves
VarInt
number of leaves at this height
1-9 bytes
leaves
Each leaf encoded in the format below.
sum of leaf sizes
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.
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
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.
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
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.
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.
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.
Golang - go-bc
Deggen (deggen@kschw.com)
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.
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".
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:
The idea is to use the Merkle Path like so:
Convert all hex string into reverse bytes, txid and all leaves.
Calculate the Merkle root by hashing the txid with each element in the path.
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])
Right shift the index number
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])
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.
This root can be used to look up a block header.
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.
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.
The main difference between this and the TSC Merkle Proof Standard Format is renaming a few 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.
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.
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.
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.
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)
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.
Ty Everett (ty@projectbabbage.com)
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.
The introduction of the BEEF format (BRC-62) provided a solution for transmitting transaction data in a binary format to allow Simplified Payment Verification (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:
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.
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.
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.
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.
In response to these motivations, Atomic BEEF introduces a new mechanism for enforcing the atomicity of BEEF transactions.
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:
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.
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
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:
The subject transaction itself, or
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.
The validation of an Atomic BEEF structure follows these steps:
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.
Transaction Graph Validation:
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 BEEF introduces two specific error conditions that must cause validation to fail:
Missing Subject Transaction: If the BEEF structure does not include the subject transaction identified by the subject TXID in the header, validation fails.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
Graph Representation: The stripped transaction thus forms a node in the transaction graph, containing only the necessary information to link it to other transactions.
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.
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.
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.
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.
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.
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.
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:
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: 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).
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.
Model the transaction inputs as a Poisson process or another suitable stochastic process that reflects real-world arrival patterns.
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.
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.
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.
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
We specify an assembly language for Bitcoin script programs as follows:
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.
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.
For example:
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.
Template variables are placed in angle brackets like <hash>
For example:
Conditional statements should use the IF
opcode, followed by the conditional expression and the ELSE
or ENDIF
opcodes.
For example:
We specify that .basm
files can be used to represent Bitcoin assembly language programs.
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
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
Defining Simplified Payment Verification (SPV) without external reference for sake of clarity.
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.
Checks made on receipt of a transaction from a counterparty:
Script evaluation of each unlocking script results in TRUE
.
The sum of the satoshis-in must be greater than the sum of the satoshis-out.
Each input must be associated with a Merkle path to a block.
nLocktime, and nSequence of each input are set to the expected values.
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.
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:
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.
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.
Tone Engel (tone@projectbabbage.com)
The BEEF serialization format (as defined in BRC-62) is essentially two things:
An array of mined transaction proof validation data (BUMPS BRC-74)
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".
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:
In the general case, a BEEF does not need to be a single transaction tree.
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.
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.
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
many bytes x nBUMPs
nTransactions
VarInt number of transactions which follow
1-9 bytes
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
many bytes
txid only
Format 02
: 32 byte transaction hash in reverse byte order
32 bytes
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.
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.
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.
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.
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:
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.
Ty Everett (ty@projectbabbage.com)
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.
For example:
All of the BUMPs required to prove inclusion of inputs in longest chain of blocks
Format 00
or 01
: RawTx bytes as in standard format
Several implementations and protocols make use of the OP_RETURN script template, including the and .
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.
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 scripts, employing the OP_FALSE OP_RETURN pattern, are not compatible with this view.
We specify the same script template as , 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.
Because 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.
Ty Everett (ty@projectbabbage.com)
Tone Engel (tone@projectbabbage.com)
Brayden Langley (brayden@projectbabbage.com)
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.
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.
Standardization: The interface provides a consistent and standardized API that ensures that any application can integrate with any compliant wallet without needing custom adaptations.
Vendor-Neutrality: The interface abstracts the underlying wallet implementation, allowing applications to work seamlessly with wallets from different vendors.
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.
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.
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 BRC-43 for security levels, protocol IDs, key IDs, and counterparties (with BRC-44 protocols reserved for internal wallet use). We subscribe to the BRC-45 idea that "Outputs are tokens". We use BRC-46 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 BRC-67 rules for SPV validation. We use the BEEF standard outlined in BRC-62 for representing transactions. For encryption and decryption, we use the methods described in BRC-2. For creating digital signatures, we use the methods described in BRC-3. For HMACs BRC-56, we derive symmetric keys as in BRC-2, but then use them for HMAC operations instead of AES-GCM encryption. For the digital certificate structure and field encryption scheme, we use BRC-52. For internalizing payment outputs that increase the user's wallet balance, we employ the key derivation protocol described within BRC-29. For revealing key linkages, we employ the two methods described within BRC-69, and we protect this information as described in BRC-72. We incorporate BRC-97 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 BRC-98 to ensure forward compatibility with future permissioned protocols. Similarly, we reserve basket identifiers as outlined in BRC-99 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.
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.
At the heart of the Wallet Interface lies the BRC-42: 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 BRC-42. 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.
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.
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.
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 BRC-67'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.
To facilitate complex tracking and interaction with UTXOs, BRC-46 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 BRC-43, 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.
Authenticated transaction verification is critical in wallet operations, and this builds, in part, on BRC-67: Simplified Payment Verification and BRC-62: Background Evaluation Extended Format (BEEF) Transactions.
BEEF Data Structure:
The BEEF format specified in BRC-62 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:
BRC-67 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.
Security is paramount in the Wallet Interface, and BRC-2 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).
The Wallet Interface supports digital signing functionalities defined in BRC-3: Digital Signature Creation and Verification.
Digital Signature Process:
BRC-3 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 BRC-43.
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 BRC-43 mechanics to derive the corresponding public key and validates the signature using this key over the provided data.
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.
The Wallet Interface incorporates support for BRC-29: 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.
Flexible Payment Handling:
Multiple Outputs and Transactions: BRC-29 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.
The Wallet Interface incorporates methods to enhance transparency and auditability through BRC-69: Revealing Key Linkages, while ensuring the protection of sensitive data during transit with BRC-72: Protecting BRC-69 Key Linkage Information in Transit.
Key Linkage Revelations:
BKDS Based Key Linkage: BRC-69 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. BRC-72 specifies mechanisms for encrypting key linkage revelations when they are in transit. This encryption is done using the BRC-2 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.
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.
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:
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: 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.
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 BRC-69, with additional support for future zero-knowledge proof schemes outlined in BRC-97. These are essential for identity verification and the auditing of interactions between parties.
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.
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.
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.
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.
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
retrieve information about the network (mainnet or testnet) and the wallet's version.
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.
To ensure consistency and prevent errors, the interface defines various data types and associated constraints. A few key examples include:
BooleanDefaultFalse
: Defaults to false if not provided.
BooleanDefaultTrue
: Defaults to true if not provided.
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.
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.
ISOTimestampString
: Represents an ISO 8601 format timestamp.
HexString
: A string containing hexadecimal characters.
Base64String
: A string in standard base64 encoded format.
Specialized Strings: Defined for specific fields, including transactions, descriptions, version strings, certificate field names, etc.
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.
context
: (Optional) Additional contextual data relevant to the error---often binary or debug information.
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.
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
.
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.
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.
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.
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 BRC-98 and BRC-99), we specify the rules that apply to these namespaces here:
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.
Must not end with protocol
(this is redundant).
Must not start with p
(allows for future "specially permissioned" protocols). Specified in BRC-98.
Key IDs:
Must be at least one byte in length.
Must not exceed 800 bytes in length.
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).
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.
This interface is specified in TypeScript as follows:
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.
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.
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.
Each method in the Wallet Interface is assigned a unique call code. The call codes are defined as follows:
1
createAction
2
signAction
3
abortAction
4
listActions
5
internalizeAction
6
listOutputs
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
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.
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).
Stack Trace (variable length): UTF-8 encoded string containing the stack trace (optional).
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
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
).
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.
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.
Each method call has specific parameter and return value formats. The following sections detail the serialization and deserialization process for each method.
createAction
Call Code: 1
Parameters
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.
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
.
Inputs Array:
For each input:
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.
sequenceNumber
VarInt
Sequence number (optional). Use -1
to indicate absence.
Outputs Array:
For each output:
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
.
customInstructions
UTF-8 String
Custom instructions (optional). If absent, VarInt
-1
.
tags
VarInt Length + Array
Array of tags (optional). If absent, VarInt
-1
.
For each tag:
UTF-8 String
Options Struct:
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
.
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.
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:
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
.
signableTransaction
Int8 Flag + Struct
If present, 1
followed by signable transaction data. Else, 0
.
For each outpoint:
Byte Array (32 bytes + VarInt)
For each sendWithResults
entry:
txid
: Byte Array (32 bytes)
status
: Int8 (1
for 'unproven'
, 2
for 'sending'
, 3
for 'failed'
)
Signable Transaction Struct:
tx
VarInt Length + Byte Array
Transaction data in AtomicBEEF format.
reference
VarInt Length + Byte Array
Reference identifier as a Base64-encoded string.
signAction
Call Code: 2
Parameters
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
.
For each spend:
inputIndex
: VarInt
unlockingScript
: VarInt Length + Byte Array
sequenceNumber
: VarInt (optional). Use -1
to indicate absence.
Options Struct:
Same as in the createAction
method, but only applicable fields:
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
.
For each TXID:
Byte Array (32 bytes)
Error Code (1 byte): 0
on success.
Response Data:
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
.
abortAction
Call Code: 3
Parameters
reference
VarInt Length + Byte Array
Reference identifier (Base64-encoded).
Return Values
Error Code (1 byte): 0
on success.
Response Data: None.
listActions
Call Code: 4
Parameters
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.
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.
Return Values
Error Code (1 byte): 0
on success.
Response Data:
totalActions
VarInt
Total number of actions matching the query.
actions
Array
Serialized array of action objects (details follow).
Action Object:
For each action:
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
.
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).
Status Codes:
1
: 'completed'
2
: 'unprocessed'
3
: 'sending'
4
: 'unproven'
5
: 'unsigned'
6
: 'nosend'
7
: 'nonfinal'
Input Object:
For each input:
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).
inputDescription
UTF-8 String
Description of the input.
sequenceNumber
VarInt
Sequence number.
Output Object:
For each output:
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
.
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
).
internalizeAction
Call Code: 5
Parameters
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.
seekPermission
Int8
1
for true
(default), 0
for false
, -1
if not provided.
Output Object:
For each output:
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
).
Payment Remittance Struct:
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.
Insertion Remittance Struct:
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
.
Return Values
Error Code (1 byte): 0
on success.
Response Data: None.
listOutputs
Call Code: 6
Parameters
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.
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.
Return Values
Error Code (1 byte): 0
on success.
Response Data:
totalOutputs
VarInt
Total number of outputs matching the query.
outputs
Array
Serialized array of output objects (details follow).
Output Object:
For each output:
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).
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).
relinquishOutput
Call Code: 7
Parameters
basket
UTF-8 String
Basket name.
output
Byte Array
Outpoint (TXID + output index) to relinquish.
Return Values
Error Code (1 byte): 0
on success.
Response Data: None.
getPublicKey
Call Code: 8
Parameters
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'
.
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.
Protocol ID Struct:
securityLevel
UInt8
Security level (0
, 1
, or 2
).
protocolString
UTF-8 String
Protocol identifier string.
Return Values
Error Code (1 byte): 0
on success.
Response Data:
publicKey
Byte Array (33 bytes)
Compressed DER-formatted public key.
revealCounterpartyKeyLinkage
Call Code: 9
Parameters
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.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
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.
encryptedLinkage
VarInt Length + Byte Array
The encrypted linkage data.
encryptedLinkageProof
VarInt Length + Byte Array
The encrypted linkage proof data.
revealSpecificKeyLinkage
Call Code: 10
Parameters
Key-Related Parameters
See Key-Related Parameters as defined in call code 10
.
verifier
Byte Array (33 bytes)
The verifier's compressed public key.
Key-Related Parameters:
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.
privilegedReason
UTF-8 String
The privileged reason string (Optional).
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
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
).
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
encrypt
Call Code: 11
Parameters
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.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
ciphertext
Byte Array
The encrypted data (AES-256-GCM).
decrypt
Call Code: 12
Parameters
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.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
plaintext
Byte Array
The decrypted data.
createHmac
Call Code: 13
Parameters
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.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
hmac
Byte Array
The computed HMAC value.
verifyHmac
Call Code: 14
Parameters
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.
Return Values
Error Code (1 byte): 0
if the HMAC is valid, non-zero error code otherwise.
Response Data: Nothing extra on successful verification.
createSignature
Call Code: 15
Parameters
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
).
seekPermission
Int8
1
for true
(default), 0
for false
, -1
if not provided.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
signature
Byte Array
The DER-encoded ECDSA signature.
verifySignature
Call Code: 16
Parameters
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
.
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.
Return Values
Error Code (1 byte): 0
if the signature is valid, non-zero error code otherwise.
Response Data: Nothing extra if successfully verified.
acquireCertificate
Call Code: 17
Parameters
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.
privilegedReason
Int8 Length + UTF-8 String
The reason for the privileged request (Optional).
acquisitionProtocol
UInt8
1
for 'direct'
, 2
for 'issuance'
.
Depending on acquisitionProtocol
, include additional fields:
If acquisitionProtocol
is 'direct'
(1
):
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'.
keyringForSubject
VarInt number of entries + Map
Map of fieldName
to keyring values.
If acquisitionProtocol
is 'issuance'
(2
):
certifierUrl
UTF-8 String
The certifier's URL for issuance.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
certificate
Byte Array
The serialized certificate binary data (format described in call code 19
).
listCertificates
Call Code: 18
Parameters
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.
privileged
Int8
1
for true
, 0
for false
, -1
if not provided.
privilegedReason
Int8 Length + UTF-8 String
The privileged reason string (Optional)
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
totalCertificates
VarInt
Total number of certificates matching the criteria.
certificates
Array
Array of certificate binary data (see below).
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).
proveCertificate
Call Code: 19
Parameters
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.
privilegedReason
Int8 Length + UTF-8 String
The privileged reason (Optional).
Certificate Struct:
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.
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
.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data (on success):
keyringForVerifier
VarInt number of fields + Map
Map of fieldName
to keyring values.
relinquishCertificate
Call Code: 20
Parameters
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.
Return Values
Error Code (1 byte): 0
on success, non-zero error code otherwise.
Response Data: None.
discoverByIdentityKey
Call Code: 21
Parameters
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.
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.
totalCertificates
VarInt
Total certificates matching the identity key.
certificates
Array
Array of extended certificate structs (see below).
Each certificate includes:
Certificate Binary Data: Serialized certificate as in proveCertificate
method.
Certifier Info Struct: Contains the following fields:
name
UTF-8 String
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).
discoverByAttributes
Call Code: 22
Parameters
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.
Return Values
Same as discoverByIdentityKey
method.
isAuthenticated
Call Code: 23
Parameters
None.
Return Values
Error Code (1 byte): 0
on success.
Response Data (on success):
authenticated
UInt8
1
if authenticated, 0
otherwise.
waitForAuthentication
Call Code: 24
Parameters
None.
Return Values
Error Code (1 byte): 0
once the user is authenticated.
Response Data: None.
getHeight
Call Code: 25
Parameters
None.
Return Values
Error Code (1 byte): 0
on success.
Response Data (on success):
height
VarInt
Current block height.
getHeaderForHeight
Call Code: 26
Parameters
height
VarInt
The block height for which to retrieve the header.
Return Values
Error Code (1 byte): 0
on success.
Response Data (on success):
header
Byte Array (80 bytes)
The serialized block header (80 bytes).
getNetwork
Call Code: 27
Parameters
None.
Return Values
Error Code (1 byte): 0
on success.
Response Data (on success):
network
UInt8
0
for 'mainnet', 1
for 'testnet'.
getVersion
Call Code: 28
Parameters
None.
Return Values
Error Code (1 byte): 0
on success.
Response Data (on success):
version
UTF-8 String
The wallet's version string (e.g., vendor-1.0.0
).
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 (""
).
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.
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.
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 BRC-2). 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 BRC-62 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 BRC-46, 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 BRC-42 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 BRC-52, 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 BRC-43.
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 BRC-29 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 BRC-3 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 BRC-2 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 BRC-43.
Key Linkage: Information that reveals the relationship between derived keys, used for transparency, auditability, and verification, particularly as per BRC-69 and protected during transit by BRC-72.
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 BRC-29.
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 BRC-97 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 BRC-43 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 BRC-43, 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 BRC-100 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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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.
[Checksum]
is a 4-byte checksum computed using the first four bytes of the double-SHA256 hash of the serialized script.
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
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.
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.
The first-known implementation for R-puzzles was created by Dean Little.
Ty Everett (ty@projectbabbage.com)
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.
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.
We specify three commonly-used Bitcoin script formats as follows:
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.
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:
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:
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:
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.
Ty Everett (ty@projectbabbage.com)
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.
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 BRC-9 process for SPV enables recipients to verify transfers quickly.
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:
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.
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.
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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.
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.
The Push TX algorithm works as follows:
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.
The algorithm pushes the current transaction onto the stack.
The algorithm pushes a dummy private key onto the stack.
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.
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.
This has been implemented in the sCrypt ecosystem.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
The following is an example output script for a token as defined by this standard:
This script template has been implemented within the PushDrop JavaScript library.
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.
Ty Everett (ty@projectbabbage.com)
Upon receiving a query, the overlay network node will perform the following steps:
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.
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.
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.
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.
Below are examples of an HTTP request and response for the /lookup
route.
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.
Ty Everett (ty@projectbabbage.com)
Derive the signing private key from your identity key using the computed invoice number.
Computing the Signature:
Advertising the Transaction:
Create a transaction output containing the CLAP token.
Submit the transaction to all known nodes, including the advertiser's own node.
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.
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 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 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.
The specified provider name for the lookup service is CLAP
. This standardized name allows implementations to easily recognize and interact with the service.
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.
The query fields are as follows:
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.
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.
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.
There are no known implementations of this specification at this time. The specification will be updated when an implementation is published.
Deggen (deggen@kschw.com)
Minimalist protocol for tokenization, issuance, transfer, recovery, and redemption.
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.
Use a genesis transaction output as an assetId
concatenating the txid and vout.
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.
Push the amount
of tokens the output represents if it's a fungible token.
Drop the data so that you can use whatever functional logic you like thereafter ...
1 satoshi assigned to each output.
Prefix everything with a UTF8 exclamation point !
(0x21 in hex) for sake of measuring adoption.
The sum of input token amounts must equal the sum of output token amounts of the same assetId
.
The order of inputs and outputs is disregarded.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
In this case, tokens in
does not equal tokens out
.
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.
Not yet available. Proposal stage.
Ty Everett (ty@projectbabbage.com)
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.
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.
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:
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.
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.
Offer Presentation: Bob contacts Alice, identifies himself and shares the transaction and signature with her.
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.
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.
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.
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.
As introduced in , 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.
We build on the node first described in 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.
The 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.
Engage in authentication and learn the identity of the person making the request, to the extent required in order to fulfill the request.
If consistent with the policy set by the node operator, charge a payment based on the query being performed, providing a mechanism by which the node can monetize its operations.
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 .
The node will then return a JSON response to the consumer, comprising an array of -style UTXOs.
The /lookup
route may be behind a 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 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 paywall to monetize access to the overlay network's state.
In either case, all lookup provider queries are always protected by authentication, as with 's /submit
route, ensuring there are digitally signed records of all requests and responses between the parties.
The overlay network node processes the query and returns an HTTP response containing an array of -style UTXOs that match the query's criteria. The response includes the topic, TXID, output index, output script, number of satoshis, and other fields for each UTXO.
Developers should extend their protected server to host the POST /lookup
API endpoint. For monetization, a 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.
We specify the Confederacy Lookup Availability Protocol (CLAP), a protocol for advertising the availability of lookup services on overlay network nodes. CLAP is an extension of 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.
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.
In a similar manner to CHIP, we specify the various components of the CLAP architecture:
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:
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:
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 methodology with security level 2
, protocol ID CLAP
, and key ID of 1
.
Use the derived private key to compute the signature over the token fields.
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 3: Verify the 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 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.
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.
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.
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 ), and the asset ID for the asset she would like to exchange, reflected in a new transaction on the overlay network.
This Token Exchange Protocol can be implemented on any UTXO-based overlay network adhering to , , and . This protocol has security built-in, stipulating both SIGHASH
type usage and broadcasting and topical membership verification methods.
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.
output holding 9 tokens
21
assetId
04
OP_DROP
OP_2DROP
...
21
assetId
05
OP_DROP
OP_2DROP
...
any
21
OP_DROP
boundKey
OP_CHECKSIG
(the genesis outpoint, assetId, and authorized outpoint 0)
authorized outpoint n
21
OP_DROP
boundKey
OP_CHECKSIG
(authorized outpoint n+1)
21
assetId
09
OP_2DROP
P2PKH
(creates 9 tokens)
authorized outpoint n
21
OP_DROP
boundKey
OP_CHECKSIG
(authorized outpoint n+1)
Any token outpoint with our genesis_outpoint
no token outputs
Valid tokens
no token outputs, or too few
authorized outpoint n
21
OP_DROP
boundKey
OP_CHECKSIG
(authorized outpoint n+1)
21
assetId
05
OP_2DROP
P2PKH
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
Consistency: Names should be consistent across different implementations to avoid ambiguity.
Clarity: Names should be clear and descriptive enough for developers to understand their purpose.
Length: While names should be descriptive, they should also be concise to ensure ease of use in configurations and codebases.
Only lower-case letters and underscores.
Must not start or end with an underscore.
No consecutive underscores.
No longer than 50 characters.
Prefix: Use the prefix tm_
to indicate a topic manager.
Topic Identifier: Follow the prefix with a short descriptor of the topic.
Example:
tm_uhrp_files
tm_tempo_songs
Prefix: Use the prefix ls_
to denote a lookup service.
Service Identifier: Follow the prefix with a brief descriptor of the lookup service functionality.
Example:
ls_uhrp_files
ls_tempo_songs_search
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.
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.
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.
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.
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).
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.
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.
List of outputs – payment destinations.
This is a regular native BSV output which specifies the amount and recipient in bitcoin script form (usually p2pkh).
This output is used for getting tokens using the STAS protocol. It is required to define tokenId (with symbol), amount, and recipient.
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.
A list of input objects contains data needed to specify the required inputs which should be used.
An object containing some policy information like fees or SPV envelope.
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:
This object defines fields required by HybridPaymentMode:
An example of a Hybrid Payment Mode implementation is provided below:
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.
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.
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.
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.
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.
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 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.
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 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 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.
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.
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.
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.
Now that we have covered the basic concepts, we specify the data structures necessary to achieve compliance with the DPP protocol.
The DPP consists of three primary messages: PaymentTerms, Payment, and PaymentACK. Each message is a JSON object with specific fields and requirements.
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:
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.
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.
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.
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.
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.
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.
Several components are used within the messages described above. This section provides a detailed description of each component.
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.
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.
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.
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.
extendedData
(object, optional)
Additional optional data as a freestyle object.
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.
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).
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.
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.
extendedData
(object, optional)
Additional optional data as a freestyle object.
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.
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.
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.
The Direct Payment Protocol (over HTTPS) is implemented in this example from Jad Wahab.
Ty Everett (ty@projectbabbage.com)
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 BRC-42 key derivation to derive public and private keys between users, BRC-8 transaction envelopes to relay SPV-related information between the sender and the recipient, and a BRC-9 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.
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.
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.
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
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 BRC-8 transaction envelopes. Each of the envelopes is extended with an additional "outputs" field, which is specified below
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.
The steps for a sender to send a payment under this protocol are as follows:
Learn the identity key of the recipient, determine the total amount of the payment and generate a derivation prefix.
Decide on the number of outputs (across one or multiple transactions) that will comprise the payment.
For each output, generate a derivation suffix for the output and decide on the number of satoshis in the output.
Use any wallet capable of creating BRC-8 Transaction Envelopes to construct and sign transactions that contain the output scripts derived for the recipient from the previous step.
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.
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 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.
Ty Everett (ty@projectbabbage.com)
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.
The proliferation of UTXO-based overlay networks necessitates robust mechanisms for peer discovery and data synchronization. While BRC-22 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.
Readers of this document should be familiar with BRCs 45, 59, 22, 24, 23, and 25.
The Overlay Services Synchronization Architecture comprises two fundamental protocols:
Services Host Interconnect Protocol (SHIP)
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.
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.
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.
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.
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.
Field 1
The string SHIP
, denoting a SHIP advertisement.
Field 2
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
Field 3
The domain name of the HTTPS server hosting the network node.
Field 4
The advertiser creates a transaction output containing the token and submits it to known nodes, including their own. The process involves:
Deriving the locking key using the advertiser's identity key.
Computing the signature over the token fields.
Creating and submitting the transaction output containing the token.
Nodes validate the identity key's link to the signature-producing key before admitting the output. The steps include:
Extracting token fields.
Verifying the SHIP/SLAP identifier.
Verifying the locking key and signature.
Admitting the token if valid.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
Example:
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.
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:
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.
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.
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: "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.
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: "sCrypt"
.
baseDirectory
(string): Path to the directory containing contract source code and related build outputs, depending on the language.
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: 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).
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"
: 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.
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"]
.
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)
Example CARS Config:
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.
LARS uses deployment-info.json
to:
Determine which topic managers and lookup services to load locally.
Compile contracts if specified under contracts
.
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.
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).
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.
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.
deployment-info.json
No frontend, no contracts, no lookup services, and a single LARS config.
deployment-info.json
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
PacketPay uses the following HTTP headers for facilitating payments between API consumers and providers:
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.
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.
The PacketPay process is divided into the following stages:
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.
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.
To implement PacketPay, API providers and consumers must follow these steps:
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.
For API consumers, implement logic to read the x-bsv-payment-satoshis-paid
header and confirm successful 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.
Deggen (deggen@kschw.com)
A random ID was generated in order to avoid label collisions in the capability document of a paymail server.
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
.
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:
The server must validate the transaction and respond with the accepted transaction ID and an optional human-readable note.
A swimlanes diagram is included here for further clarification: https://swimlanes.io/u/6J2q8QCEb
Ty Everett (ty@projectbabbage.com)
Brayden Langley (brayden@projectbabbage.com)
HTTP 402 Payment Required responses
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.
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:
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.
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.
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.).
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.
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.
Server Determines Price
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.
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-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.
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.
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
.
When the server determines a payment is needed but not yet provided or invalid:
HTTP Status: 402 Payment Required
.
Headers:
x-bsv-payment-version
: 1.0
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:
After receiving this, the client is expected to construct and broadcast a payment transaction referencing this prefix.
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.
Upon receiving x-bsv-payment
, the server:
Ensures the prefix is the same as previously advertised (and not used before).
Validates the transaction using wallet.internalizeAction()
or similar. Steps might include:
Ensuring the output script pays to the correct derivation from derivationPrefix
.
Checking if the amount is at least the required satoshisRequired
.
Preventing double-spend or replay.
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.
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.
Auth Check (BRC-103/104)
If not authenticated, respond 401 Unauthorized
.
Calculate Price
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.
Send Request
If server returns 402
, parse x-bsv-payment-version
+ x-bsv-payment-satoshis-required
+ x-bsv-payment-derivation-prefix
.
Construct Payment
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:
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.
Contact your local police department.
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.
Man-in-the-Middle
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.
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.
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.
The identity key of the advertiser.
The identity key of the advertiser.
The service name, represented by a provider ID.
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.
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.
The BRC-55 API is implemented .
This standard describes PacketPay, a mechanism for facilitating micropayments using Bitcoin SV within HTTP requests. It relies on the payment protocol for processing payments, and 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.
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.
Authentication: The API consumer and provider exchange Authrite requests and responses to authenticate their identities and share necessary identity information.
Payment Processing: The API consumer reads the x-bsv-payment-satoshis-required
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 , and processes the request if the payment is valid.
Implement for processing payments and for authenticating communications between parties.
For API consumers, implement logic to read the x-bsv-payment-satoshis-required
header, construct a payment, and include the x-bsv-payment
header in the subsequent request.
For API providers, implement logic to read and verify the x-bsv-payment
header using , process the request if the payment is valid, and include the x-bsv-payment-satoshis-paid
header in the response.
The PacketPay and have been implemented in JavaScript by the Babbage Team.
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.
We propose that functionality between hosts to include the data required for the counterparty to run SPV on the transaction.
BEEF transaction hex is a string encoding of the binary format detailed in .
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:
Nonce-based derivation prefixes ()
Standardized BSV wallet functionality ()
Derivation Prefix: A random nonce string used to derive or reference a unique public key / payment output. Defined in .
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 .
x-bsv-payment-derivation-prefix
: A random nonce () for the transaction.
Clients should request more robust identity certificates using in the future.
File an .
: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol
: HTTP Transport for BRC-103
: Derivation-based Payment Protocol
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
Ty Everett (ty@projectbabbage.com)
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.
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.
The trust anchor details MUST be published in a file named manifest.json
.
The manifest.json
file MUST be hosted using the HTTPS protocol. Plain HTTP is not supported.
Only Fully Qualified Domain Names (FQDNs) are supported for hosting the manifest.json
file.
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.
name
MUST be a string.
MUST contain between 5 to 30 characters, inclusive.
note
MUST be a string.
MUST contain between 5 to 50 characters, inclusive.
icon
MUST be a valid image URL.
Should be accessed over HTTPS.
publicKey
MUST be a string in DER format.
MUST be compressed.
MUST use the secp256k1 elliptic curve.
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").
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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:
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.
The sender derives their own child private key and the child public key of the recipient using BRC-42 key derivation.
The sender then computes an ECDH shared secret between the two child keys which is used in symmetric encryption with AES-256-GCM.
With a random initialization vector, the message is encrypted and the vector is prepended to the ciphertext.
For decryption:
The recipient computes their own private key and the public key of the sender using BRC-42 key derivation.
The recipient computes the same Shared Secret and uses it along with the received initialization vector to decrypt the ciphertext.
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:
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
Ciphertext
Variable
The encrypted message data (AES-256-GCM with IV prepended)
This standard serialization format contributes towards a standardized way of securely transmitting and decrypting encrypted messages.
Todd Price (todd@bitcoinassociation.net)
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.
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.
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.
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 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.
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.
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
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
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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:
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.
Message sender derives a child private key for the counterparty (or anyone
) with the computed invoice number using the BRC-42 key derivation process.
Message sender then computes the digital signature using the ECDSA with the derived private key.
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.
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:
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
32 bytes
The specific key ID used for the signature
Signature
Variable
The ECDSA signature of the message, in DER format
Ty Everett (ty@projectbabbage.com)
This document builds upon the insights of BRC-80 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
This BRC extends BRC-56 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
) 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.
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.
This BRC introduces two new message types to the BRC-56 messaging layer:
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:
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.
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.
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:
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:
The Certificate Deletion Request message is sent by an application to request the deletion of a specific digital certificate. It contains the following fields:
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.
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.
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:
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 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.
Ty Everett (ty@projectbabbage.com)
This specification defines Authrite, a system for the mutual authentication of two parties over a communications channel. It facilitates the exchange of BRC-52 identity certificates between users, allowing them to certify each other's identities and share identity information selectively. Authrite leverages the BRC-42 Identity Keys of MetaNet Users and relies on BRC-43 Permissions and BRC-53 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.
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.
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.
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.
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:
The Nonce structure is a 256-bit number, converted to a base64 string.
Example
The RequestedCertificateCertifierList structure is an array of PublicKey structures, each denoting a certifier which the sending party will trust.
Example
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
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
The CertificateList structure is an array comprising a list of Certificate structures, given in response to a RequestedCertificateSet structure.
Example
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
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:
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.
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:
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.
When JSON is used, a message payload can simply be added to an Authrite JSON object:
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 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:
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
Ty Everett (ty@projectbabbage.com)
This document introduces a message box architecture and relay interface to enable data exchange between two parties using a BRC-31 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.
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.
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:
/sendMessage
Send a message to a recipient's message box.
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
message.body
string
The content of the message
Example Request:
status
string
The status of the message sending operation
Example Response:
/listMessages
List messages from the specified message box.
messageBox
string
The name of the message box to retrieve messages from
Example Request:
status
string
The status of the message listing operation
messages
array
Array of message objects
messages[].messageId
integer
Unique identifier for the message
messages[].body
string
The content of the message
messages[].sender
string
The sender's public key
Example Response:
/acknowledgeMessage
Acknowledge that a message has been received. After acknowledgment, the server deletes a message.
messageIds
array
Array of message IDs to acknowledge
Example Request:
status
string
The status of the message acknowledgment operation
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.
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.
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.
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.
The message relay architecture has been implemented in the PeerServ API, created by the Babbage Team.
Brayden Langley (brayden@projectbabbage.com)
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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
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:
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
The Certificate structure is an object with the following JSON fields:
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.
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.
Example
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:
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.
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.
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
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:
Retrieve the relevant symmetric field encryption keys
Encrypt the keys for the verifier following the BRC-2 process for counterparty encryption.
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:
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.
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.
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.
An example implementation of Identity Certificates can be seen in Authrite, and the MYAC tutorial can be followed for creating your own Authrite Certifier.
Ty Everett (ty@projectbabbage.com)
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 BRC-56 wallet over XDM, enabling a parent page that runs a wallet to communicate with one or multiple child pages that run applications.
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.
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
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:
All messages (requests, responses and errors) have a type
property equal to CWI
(this value, which stands for Computing with Integrity, is historical)
A random message ID is generated by the application
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
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
, 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
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.
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:
Upon receipt of a message with an event data field type
not equal to CWI
will drop the message
Upon receipt of an untrusted message, or one without a call
will drop the message
Upon receipt of a message with an unknown or unsupported call
will proceed to step 6
Based on the call
and params
will perform the necessary steps as required by the relevant BRC specifications for the specific operation
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
A result
value that is the result of the operation being performed, as specified by the particular operation
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
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
call
Associated with Various Message TypesFor 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
createAction
encrypt
decrypt
createSignature
verifySignature
createCertificate
proveCertificate
createHmac
verifyHmac
getPublicKey
ninja.findCertificates
This call name prefix is historical and retained for compatibility
getVersion
getNetwork
isAuthenticated
waitForAuthentication
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.
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.
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.
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 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 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.
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.
Ty Everett (ty@projectbabbage.com)
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.
The key derivation is specified as follows:
Each party has a master private key and a master public key that are derived from the secp256k1 elliptic curve.
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.
The invoice number is treated as a string and is converted into a buffer using UTF-8 encoding.
The sender generates a shared secret by multiplying his master private key with the recipient's master public key using elliptic curve point multiplication.
The sender generates an HMAC over the invoice number using the shared secret as the key.
The HMAC is 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 for the given invoice number.
The recipient generates the shared secret by multiplying his master private key with the sender's master public key using elliptic curve point multiplication.
The recipient generates the HMAC over the invoice number using the shared secret as the key.
The HMAC is converted into a scalar using big-endian encoding.
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.
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.
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,
Test vectors for this standard are provided:
Ty Everett (ty@projectbabbage.com)
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.
We specify that an invoice number has the following three components:
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.
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.
To illustrate how the system is intended to function, we provide several examples.
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.
The client checks if example.com
has already been granted permission to use this protocol. Because the security level is 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.
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
, 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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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.
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:
Important: Each certificate field is encrypted with a field-specific key. The encrypted version is signed.
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.
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.
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)
.
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.
Certificate Creation
User (subject) or certifier forms certificate fields (including Type
, SerialNumber
, etc.).
Each field is encrypted.
The certifier signs the certificate data.
Certificate Verification
A party verifying a certificate reassembles the binary structure.
Checks the signature against the “signature preimage” (all primary certificate fields except the signature itself, and not including their verifier keyring).
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.
Each message exchanged between peers contains:
Version: The protocol version string (e.g. “0.1”).
MessageType: One of: initialRequest
, initialResponse
, certificateRequest
, certificateResponse
, general
.
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.
The protocol does not mandate a specific transport. Any medium that can:
Deliver messages in a reliable or semi-reliable manner, and
Allow receiving peer messages,
can be used. HTTP requests, WebSockets, Bluetooth, NFC, or local function calls are all valid.
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.
The handshake typically has two messages in the simplest form: an initialRequest
and an initialResponse
.
initialRequest
Sender (A) generates a random nonce (A_Nonce).
A sends initialRequest
containing:
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.
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.
Signature ensures authenticity. The signing steps:
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.
Use the BKDS-based BRC-100 signature creation and verification mechanisms.
Place the resulting signature in the message’s signature
field.
Verification:
Recompute the same message preimage.
Verify the signature with the alleged identityKey.
If valid, accept the message. Otherwise, reject or treat as an error.
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.
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.
The signature
covers the payload plus nonces.
Replay Attacks:
Nonces must be unique and used once. The receiver ensures that the same nonce is not accepted more than once.
Man-in-the-Middle:
The handshake uses mutual signature verification. If a middle party tries to modify data, the signature verification fails.
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.
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.
Storage:
A wallet may store certificates in a local database.
A session manager maps sessionNonce
and peerIdentityKey
to a single in-memory record.
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.
Attribute
Attribute
Attribute
Attribute
Attribute
Attribute
Transaction Creation
Encryption
Decryption
Signature Creation
Signature Verification
Certificate Creation
Certificate Verification
HMAC Creation
HMAC Verification
Public Key Derivation
Certificate List
Version Request
Network Request
Authentication Request
Async Auth Request
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.
1:
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.
This technical standard is proposed to address the need for a standard method for key derivation between parties that enables greater ecosystem interoperability. While BIP32 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.
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 BIP32 and provides greater flexibility, privacy, and auditability.
This specification has been implemented into both the BSV and libraries.
Credit is given to the people who have worked on making these ideas into reality. In particular, we thank Xiaohui Liu for creating the of private addresses using this scheme, and Dr. Craig Wright for first .
1:
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.
The 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.
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 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 key derivation in a variety of contexts, improving security and facilitating innovation.
Some protocol IDs are used internally by various clients, and thus are never allowed within applications. These are specified by other standards, such as .
An application, example.com
, sends a request to the user's client for encrypting some data (as per ). The application is requesting to use security level 0
, a protocol ID of Hello World
, a key ID of 1
, and counterparty of self
.
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
.
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.
The system is implemented into the , which employs protocol IDs, key IDs and security levels when facilitating the functionality of the encryption and digital signature creation components.
Wallet: An interface or application managing the user’s keys, capable of signing, encrypting, and decrypting data in conformance with .
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.
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.
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).
This is a simple extension of the widely used BIP39 Mnemonic seed phrase scheme where 12 to 24 words are used to encode entropy which is then used to derive an extended private key for use with the BRC-32 derivation scheme.
This document proposes a way to encode a single private key as a mnemonic phrase which people have become accustomed to.
The purpose is to maintain the familiar interface to store a single key rather than an extended set. Users are already aware of the importance of keeping these words secret and secure, and have developed an awareness around not sharing them with a third party and so on. Rather than retraining users on a new concept, the idea is to do away with BIP32 in favor of BRC-42 style derivations, but keep the backup method for the master key as storing a mnemonic offline.
Note: There is no need to use BIP32 and BIP44 hereafter. You could just derive the first child key of an HD wallet and use that for BRC-44 derivations. However this is a simpler way to get to a single key and remains compatible with the menomics people may have been using for a decase now.
Using the standard BIP39 mnemonic scheme, a seed is created and can be maintained offline as words. Thereafter we must get from the mnemonic to a seed and then in this case to a private key. The simplest methodology can be used, a sha256 of the seed bytes is taken to arrive at the big number which is the private key.
Using libsv/go-bk
, we can generate a mnemonic, and derive the master key from it. All derivations for actual outputs can be derived using the scheme described in BRC-42.
Same idea in js but we use bsv
npm package, and a specific mnemonic to check we get the same resulting key pair:
Damian Orzepowski (damian.orzepowski@4chain.studio)
The Linked Key Derivation Scheme builds on and extends the "type 42" key derivation method. This scheme allows public key derivation using only the public keys of both parties, maintaining the flexibility and unlimited key derivation of type 42. It aims to enable non-custodial wallets to derive public keys from a master public key without private key access, while only the master private key owner can derive the corresponding private key.
The primary goal of this scheme is to enhance privacy and scalability in key derivation processes, enabling public key derivation based solely on the public keys of involved parties. Additionally, it ensures that the derived keys are linked back to their master keys, providing a mechanism for auditing and confirming the parties involved in transactions. This supports applications such as non-custodial wallets, ensuring secure and verifiable transactions without the need for private key access during the derivation process.
The assumptions regarding identity keys remain unchanged from type 42. Each party has a master key pair, where the master public key is used to derive linked public keys. This ensures that the derived keys are linked back to the master key without requiring the master private key during the public key derivation process.
The Linked Key Derivation Scheme maintains similar security properties to type 42, with the notable exception that no shared secret is generated or utilized. The scheme ensures that only the owner of the master private key can derive the corresponding linked private key, while public key derivation remains secure and private.
Generate HMAC from the invoice number using the serialized public key as the key.
Convert the HMAC to a scalar using big-endian encoding.
Multiply the generator point ( G ) by this scalar to obtain a point on the elliptic curve.
Add this point to the master public key (also expressed as a point) to get a new point on the elliptic curve.
This new point represents the derived linked child public key.
Generate HMAC from the invoice number using the serialized public key as the key.
Convert the HMAC to a scalar using big-endian encoding.
Add this scalar to the master private key (expressed as a number).
This resulting number is the derived linked child private key.
The Linked Key Derivation Scheme provides a robust method for public key derivation, suitable for applications like non-custodial wallets, ensuring privacy, auditability, and secure key management without compromising security.
Ty Everett (ty@projectbabbage.com)
We define a set of reserved protocol namespaces that can be employed by clients utilizing the BRC-43 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.
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.
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
Ty Everett (ty@projectbabbage.com)
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.
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.
The steps for verifying the validity of a payment transaction using the BRC-9 SPV protocol are as follows:
Ensure that the received BRC-8 Envelope is in the correct format
Add any previously-unknown headers provided in the BRC-8 Envelope to the chain of headers
Ensure that all SPV proofs link back to the genesis block and the chain with the most proof of-work
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
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.
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.
Ty Everett (ty@projectbabbage.com)
This method must never be used where the counterparty is the user themself (counterparty=self
), as that would reveal keys used internally by the user. The method is also ineffective where the counterparty is "anyone", as the anyone
private key is already publicly known (it is the value 1
).
This method allows the user to create an audit trail for specific protocols, key identifiers, and counterparties without exposing all interactions with the particular counterparty. This is because, while the root shared secret is used to compute the HMAC, it is not revealed — only the resulting HMAC is shared.
Below is TypeScript code that implements the described methods:
This BRC proposes two methods for revealing key linkages under the key derivation scheme and . One method reveals the root shared secret between two counterparties, allowing anyone to link all interactions between them. The other method reveal only a specific link (the key offset value) between a root identity key and one of its child public keys. This establishes proof of association with a particular derived key and provides an audit trail for a specific protocol ID, key ID, and counterparty. While these methods enable signature verification and transaction auditing, they do not allow anyone to decrypt data encrypted using , preserving privacy.
The key derivation architecture and allow for privacy-preserving transactions between parties. However, there are scenarios where users may wish to prove key associations and provide audit trails for their interactions. For example, a user may want to establish their ownership of a key used in a transaction, or authorities might need to audit transactions between specific parties. This technical standard aims to fulfill these requirements, allowing users to prove key associations and reveal transaction linkages between parties, while preserving the confidentiality of interactions with unrelated parties.
This method returns the root ECDH shared secret between a user's identity key and a specified counterparty's key. Revealing this key allows any party to link all past and future transactions between these two entities, since the shared secret is used as the HMAC key for computing all child key derivation offset values.
Although this enables transaction traceability, and the ability to verify signatures computed with , it does not allow for decryption of any data encrypted using a encryption mechanism. This is because while the child public keys are derivable by the person who has been given the shared secret, the corresponding private keys are not, and the shared secret used for encryption is computed between the two child keys, and not the root keys.
This method reveals the offset value (the link) that connects a root identity key to one of its derived child public keys, under a specified protocol ID, key ID, and counterparty. By exposing this link, the user can prove their association with the specific derived key, allowing for auditing of all activity involving this key for the specified protocol and counterparty.
The two methods in this technical standard are essential building blocks for creating protocols that support accountability and provide an added layer of security to Bitcoin and MetaNet client software implementing and protocols. Implementations should ensure that these methods are only used in ways that maintain user privacy and do not reveal linkage information — especially counterparty root shared secrets — to the public.
Ragnar Friedman ragnar.friedman@proton.me
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.
Alice: Initiates the sync process.
Bob: Responds and participates in the sync process.
Initialization
Alice starts by sending a bloom filter containing all current spendable TXID+VOUTs as elements.
Receiving and Building List
Bob receives the filter and builds a list of his items that are not members of the set.
Transaction Verification
Bob sends an INV (Inventory) message to Alice for each item not in the set.
The INV includes:
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.
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.
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.
When only metadata is included, it encompasses the list of spent VOUTs and associated metadata hashes.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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.
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.
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
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
As discussed in BRC-59, 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.
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.
The BRC-31 protected server will host a POST /submit
API endpoint, which accepts JSON request payloads. The JSON request body will include a BRC-8 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.
Upon receiving a transaction, the overlay network node will perform the following steps:
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.
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 BRC-24, 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.
We provide an example of an HTTP request and response.
In this example, a client submits a transaction to the /submit
API endpoint. The JSON payload contains the BRC-8 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.
To implement this data synchronization solution, developers should first set up a BRC-31 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 BRC-9.
Overlay network nodes must be programmed to process incoming transaction submissions following the steps outlined in the specification. This includes verifying the sender's BRC-31 identity, checking for hosted topics, validating the transaction using BRC-9, 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.
Ty Everett (ty@projectbabbage.com)
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.
The BRC-22 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.
We define the various components of the Confederacy Host Interconnect architecture.
CHIP tokens are registered on the Bitcoin SV blockchain as single-satoshi BRC-48 outputs representing hosting advertisements by Confederacy network operators. The token fields are ordered as follows:
Field 1
The string CHIP
, denoting a CHIP advertisement.
Field 2
Field 3
The internet domain name of the HTTPS server hosting the network node.
Field 4
The topic name hosted by the advertiser.
The advertiser creates a transaction output containing the token and submits it to known nodes, including their own. The BRC-48 locking key must be linked to the advertiser's BRC-31 identity key using the BRC-42 and BRC-43 methodologies.
The advertiser follows these steps to derive the BRC-48 locking key, compute the signature, and advertise the transaction to all known nodes:
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.
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.
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 BRC-31 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 BRC-48 locking key. Utilize the advertiser's claimed BRC-31 identity key as the sender public key in the BRC-42 key derivation process, with the "anyone" private key (1
) as the recipient. Compute the invoice number using the BRC-43 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 BRC-48 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.
The CHIP BRC-24 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.
The specified provider name for the lookup service is CHIP
. This standardized name allows implementations to easily recognize and interact with the service.
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.
The query fields are as follows:
topic
The topic name hosted by the advertiser, used to filter UTXOs based on the desired topic.
advertiser
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.
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 BRC-31 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 BRC-22 protocol, notifying them about a new transaction in the topic.
Verifying Identity Key during Transaction Submission. 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.
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.
There are no known implementations of this specification at this time. The specification will be updated when an implementation is published.
The identity key of the advertiser creating the token.
The identity key of the advertiser, used to filter UTXOs based on the specific advertiser.
Ty Everett (ty@projectbabbage.com)
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 BRC-22 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.
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.
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.
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.
Ty Everett (ty@projectbabbage.com)
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.
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.
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 john.galt@gateway.cash. 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.
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.
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.
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.
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:
The server must validate the transaction and respond with the accepted transaction ID and an optional human-readable note.
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.
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:
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.
Various implementations have been created which facilitate Paymail payment destination discovery, and the hosting of Paymail servers:
Money Button Express Paymail is a server-side package that hosts a set of compatible endpoints.
Money Button Paymail Client is a JavaScript client for interacting with the Paymail protocol.
AtFinder is the Paymail client created by Project Babbage [deprecated (no longer in active use)].
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 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 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:
Service
_bsvalias
Proto
_tcp
Name
<domain>.<tld>.
TTL (Time to Live)
3600
(recommended for production deployments)
Class
IN
Priority
10
Weight
10
Port
443
Target
<endpoint-discovery-host>
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.
Ty Everett (ty@projectbabbage.com)
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.
Ty Everett (ty@projectbabbage.com)
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 BRC-23 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 BRC-69 key linkage information.
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.
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 1
The term 'PHIP', representing a PHIP advertisement.
Field 2
Field 3
The domain name of the HTTPS server hosting the PeerServ instance.
Field 4
Field 5
A signature from the recipient authorizing this host to make this advertisement. The recipient signature is specified below.
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.
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.
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:
Obtaining the recipient's signature to authorize the message routing advertisement.
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.
Computing the Signature: The derived private key from the earlier step is used to calculate the BRC-48 signature covering the fields of the PHIP token.
Broadcast the Transaction: A transaction output is embedded with the PHIP token, and this transaction is then submitted to the PHIP overlay network.
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 BRC-48 locking key; if not, the token is rejected as invalid.
Verify the recipient signature. Use the recipient's claimed BRC-31 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.
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.
We specify PHIP
as the BRC-24 Lookup Service Provider Name.
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.
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.
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
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
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.
If the server received and validated the authorization from the recipient, a success response is returned.
If there was an error, appropriate HTTP status codes should be used. An example of a reasonable error response is provided.
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
originalSender
keyLinkage
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
The PeerServ instance that receives this request will perform the following steps:
Compute the child public key for the original message sender by adding (by point addition) the keyLinkage
value to the originalSender
public key.
Check the senderSignature
against the computed public key for validity.
Examine the signedMessage
to determine the appropriate message box and recipient.
If the server is willing to add this message to the specified message box for the specified recipient, the message is added.
If the message was successfully stored in the recipient's appropriate PeerServ message box, a success response is returned.
If there was an error, appropriate HTTP status codes should be used. An example of a reasonable error response is provided.
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:
Use the PHIP lookup service to look up UTXOs associated with the PeerServ instances in use by the recipient.
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.
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.
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.
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.
There are no known implementations of this standard at present. This specification will be updated as and when an appropriate implementation is developed.
The identity key of the instance operator who submitted the advertisement.
The identity key of the user who the instance operator believes will receive messages via the PeerServ instance.
The identity key of the original message sender
The (Method 2) key linkage information that links the original sender with the Authrite message signature
Darren Kellenschwiler (deggen@kschw.com) Damian Orzepowski (damian.orzepowski@4chain.studio)
Allowing humans to securely exchange public keys using web apis and an off channel sharing of TOTPs.
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.
A random ID was generated in order to avoid label collisions in the capability document of a paymail server.
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.
Sender wallet: generate random hash
Sender wallet generate public key from private key and random hash
Sender wallet is sending "add contact request" to Sender BUX containing: a. contact paymail address b. random hash c. generated public key
Sender BUX is performing Paymail host discovery (which is described on this page: https://tsc.bsvblockchain.org/standards/paymail/#ServiceDiscovery)
Sender BUX is performing Paymail capability discovery on Receiver BUX by requesting /.well-known/bsvalias
If Receiver BUX doesn't contain Proven Identity Key Exchange (PIKE) capability, Sender BUX should return an error to Sender Wallet
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
Receiver BUX stores that "contact" as "waiting" in database
Receiver BUX is answering to Sender BUX with success
Sender BUX is storing the "contact" as "waiting"
Receiver Wallet asks Receiver BUX for "waiting" "contact" to confirm or reject
Receiver BUX is responding with the list of contacts
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
else: Receiver Wallet generate public key from private key and random hash from the contact
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
Receiver BUX is marking a "contact" as "accepted"
Receiver BUX is sending the "contact accepted" request to Sender BUX with: a. paymail address of Receiver b. generated public key c. random hash
Sender BUX is validating random hash, and stores received public key in "contact" and marks it as accepted
Sender Wallet is asking Sender to confirm contact
Sender asks Receiver for TOTP
Receiver checks TOTP for Senders paymail in Receiver Wallet
Receiver Wallet calculates shared secret based on private key and Senders public key
Receiver Wallet generates TOTP based on shared secret
Receiver Wallet sends back TOTP to Receiver
Receiver is responding with TOTP to Sender
Sender is providing TOTP to Sender Wallet
Sender Wallet calculates shared secret based on private key and Receiver public key
Sender Wallet generates TOTP based on shared secret
Sender Wallet is comparing received TOTP with generated TOTP. If their match then it marks contact as confirmed.
Sender Wallet is now generating another TOTP and provides to Sender
Sender is providing TOTP to Receiver
Receiver is providing TOTP to Receiver Wallet
Receiver Wallet is generating TOTP and comparing it with received TOTP If their match then it marks contact as confirmed.
Ty Everett (ty@projectbabbage.com)
This BRC outlines additional security measures for the protection and controlled revelation of key linkage information as defined in BRC-69. This standard describes an approach for encrypting this sensitive data during communication, according to BRC-2. The intent is to ensure that only approved parties are capable of decrypting and accessing this information, thereby maintaining privacy and security.
Providers of key linkages, as defined in BRC-69, need a secure way to disclose this information to a particular verifier. The information, although intended for verification, is highly sensitive and could infringe on privacy and security if mishandled. Therefore, a standard way to protect and communicate it is required. This proposal allows provers to reveal linkage information intentionally and securely, minimizing the risk of breaches.
A counterparty-revelation
payload emphasizes encryption using the BRC-2 standard. The protocol ID in this context is counterparty linkage revelation
with security level 2
. The key ID comprises the current timestamp and serves to indicate the precise moment when the prover revealed the linkage information to the verifier.
Compute the root ECDH shared secret between user's identity key and a specified counterparty's key as per BRC-69 (method 1).
The prover's BRC-43 encryption protocol is counterparty linkage revelation
, with a security level of 2
. The key ID is the current timestamps in ISO string format.
Encrypt the computed shared secret using the verifier's public key with BRC-2.
An entity receives the encrypted linkage counterparty revelation payload.
The entity decrypts the payload by using their private key with the prover's public key and the protocol ID and key ID specified.
type
String
Indicates the type of payload, will be 'counterparty-revelation' for this payload.
prover
String (hex)
Public identity key of the entity revealing the key linkage.
verifier
String (hex)
Public identity key of the entity performing verification.
counterparty
String (hex)
Public identity key of the counterparty in question.
revelationTime
String (ISO Time)
Timestamp of when the linkage is revealed.
encryptedLinkage
String (base64)
The encrypted root shared secret computed between the prover's identity key and the counterparty's key.
The specific-revelation
payload involves encrypting the linkage information using BRC-2. The protocol ID incorporates the base specific linkage revelation
, and incorporates the security level and protocol ID used within the specific linkage being revealed. The key ID equals the key ID of the disclosed specific linkage.
Compute the child key offset with respect to specific BRC-43 protocol ID, key ID, and specified counterparty using BRC-69 (method 2).
The prover's BRC-43 encryption protocol is specific linkage revelation <s> <p>
, with a security level of 2
, where <s>
is the security level of the specific linkage protocol and <p>
is its protocol ID. The key ID equals the key ID of the revealed specific linkage.
Encrypt the computed key offset using the verifier's public key.
An entity receives the encrypted specific revelation payload.
The entity decrypts the payload by using their private key with the prover's public key and the protocol ID and key ID specified.
type
String
Indicates the type of payload, will be 'specific-revelation' for this payload.
prover
String (hex)
Public identity key of the entity revealing the key linkage.
verifier
String (hex)
Public identity key of the entity performing verification.
counterparty
String (hex)
Public identity key of the counterparty in question.
protocolID
Array
BRC-43 protocol ID for the specific linkage in question. It is defined as an array where first element is the security level and second element is the protocol string.
keyID
String
A string that specifies the key ID for the specific linkage in question.
encryptedLinkage
String (base64)
The encrypted key offset computed for the specific BRC-43 protocol ID, key ID, and specified counterparty.
Example Counterparty Revelation Payload:
Example Specific Revelation Payload:
In each of the two above examples, the verifier's private key is c1a97bde329903b2035a870955b570f9f795e372af8a3e0fee78534157a7af18
.
You should be able to successfully verify that the keys linked between the prover and the prover's counterparty are authentic.
Entities implementing this standard should consider privacy and security as critical. When creating a revelation payload, it is crucial to use precise protocol IDs and key IDs that correspond to the linkage being revealed. The use of accurate timestamps as key IDs in counterparty revelations is vital to document the exact time of the revelation. Entities should design their systems to handle these payloads correctly, ensuring the decryption process is secure. They should also ensure received payloads are legitimate by verifying accurate key linkages. If it is necessary to store linkage information, it should always be stored in an encrypted manner, away from less sensitive data.
Ty Everett (ty@projectbabbage.com)
Brayden Langley (brayden@projectbabbage.com)
This specification defines how to 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.
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.
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.
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.
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.
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.”
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.
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.”
BRC-104 introduces the following headers:
x-bsv-auth-version
: The BRC-103 version string (e.g. "1.0"
).
x-bsv-auth-identity-key
: The sender’s public identity key (33-byte compressed secp256k1 pubkey, typically hex).
x-bsv-auth-nonce
& x-bsv-auth-your-nonce
: 32-byte ephemeral nonces used in BRC-103’s handshake.
x-bsv-auth-signature
: ECDSA signature in hex, verifying the message.
x-bsv-auth-request-id
: A client-generated 32-byte random ID (base64) to correlate request/response pairs in “general” messages.
x-bsv-auth-message-type
: (Optional) The BRC-103 message type if returning a certificateRequest or certificateResponse via HTTP.
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.
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.
Client perspective:
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.
The BRC-103 identity key, version, nonce, etc., go into x-bsv-auth-*
headers.
Send the request over standard HTTP.
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:
On receiving the request, parse the x-bsv-auth-*
headers (nonce, signature, identityKey, etc.).
Construct the “general” BRC-103 message from the payload.
If signature checks pass, handle the HTTP request in memory (similar to a normal route).
Instead of sending the result directly to the wire, embed your final status code, headers, and body in a new “general” BRC-103 message.
Write it back in x-bsv-auth-*
headers + the binary payload within the same HTTP response.
Non-general BRC-103 messages—like initialRequest
, initialResponse
, certificateRequest
, certificateResponse
—MUST be exchanged via:
POST /.well-known/auth
, with a JSON body:
The server decodes the AuthMessage, verifies it, and possibly replies with another AuthMessage in JSON form:
On success, the client merges that result into the BRC-103 session state.
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
.
When sending a “general” message:
The body is included raw in the BRC-103 payload, but only after a length prefix.
If content-type
is application/json
, you typically convert your JSON object to UTF-8 bytes.
If it is binary data (e.g. images), you pass the binary as bytes.
If no body, specify a -1
length in the payload.
The same approach is used for the server’s return body in the “general” response message.
The code references BRC-103’s standard approach: concatenating these fields in a stable order:
x-bsv-auth-request-id
(32 bytes, base64-decoded).
Request method
length + UTF-8 bytes.
Path length + UTF-8 bytes (or -1
if empty).
Query string length + UTF-8 bytes (or -1
if none).
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
Body length + body bytes (or -1
if none).
Then sign with the identity key. The server reconstructs that same preimage from the request data, verifying the signature in x-bsv-auth-signature
.
In response to client request the server creates a BRC-103 payload as follows:
x-bsv-auth-request-id
(echoing back the client's requestId as seen on line 174).
Response status (varInt)
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
Body length + body bytes (or -1
if none).
A reference “client” does the following:
When sending a non-general message (e.g. handshake, certificate request), it:
Performs POST /.well-known/auth
with Content-Type: application/json
.
Embeds the entire AuthMessage (BRC-103 structure) in JSON.
When sending a general message:
Serializes method, path, query, whitelisted headers, and body into a BRC-103 payload.
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.
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.”
Intercept POST /.well-known/auth
requests, parse them as JSON, treat them as BRC-103 “non-general.”
For other paths, it checks for x-bsv-auth-request-id
to see if it’s a “general” message.
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.
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.
BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol (provides handshake and message definitions).