Skip to content

Publishing Data on Bitcoin Cash Anonymously Using Faucets

Status: DRAFT (Version 1)
Date: April 2021


To publish a transaction with a data payload on the Bitcoin Cash block chain, a transaction will need one or more transaction inputs to fund it. This input leaves a blockchain trace and can potentially be used to track the identity of the user.

Given a tag and a set of public keys associated with tag, we can use traceable ring signatures to enable faucets to trustlessly provide inputs for submitting a data payload, without revealing which of the key holders requested funding.

Traceable Ring Signatures allow the faucets to detect if a user has previously requested a input, protecting the faucet from being drained of funds. This is also a limitation, a faucet can only provide a input once per user per tag.

We use the Input Payload P2SH contract to enforce that funds can only be used for submitting a data payload. The faucet does not know the contents of the data payload, yet the payload cannot be changed after requesting funds.

This method for data payload publishing is for example applicable for online blockchain elections. In this application a tag can be the message "election #42" and a set of participants. This would allow participants to publish their vote anonymously.

Requesting funding from faucet

User request message

The user needs to send a request to a faucet to fund a P2SH contract used for delivering the data payload.

The request needs to be passed to the faucet via means of anonymous one-way messaging. The message itself does not reveal user identifying information, so the message can be public.

Anonymous message passing is it's own research topic and the specifics of it are out of scope for this document, however suggested implementation of it is discuss later in this document.

The contract we'll be using is the Input Payload P2SH contract.

Request Data Structure

This request must at minimum contain the following.

Data Data type Description
Tag Variable The identifying tag for purpose of request. For election, this would be an election identifier
Public key 33 bytes Public key (compressed) the user will unlock the funds with.
Hash of payload 20 bytes Hash of data payload the user will publish (hashing method specified by contract).
Signature Variable Signed hash of the request, excluding the signature itself.

Validation of message by faucet

Upon receiving a funding request, the faucet validates that.

  • The tag is supported by faucet.
  • That ring signature is signed by participant of tag.
  • That the ring signature signed the correct hash of the message.
  • That ring signature trace check does not reveal that user already has requested funding.
  • (Optional) That contract has not been funded (by another faucet).

If the validation passes, the faucet generates the locking script and funds the contract.

Rejecting funding

If the message passing protocol supports two-way message passing, the faucet can optionally send reject message with reason for rejection.

Otherwise ignore the request. User observes the blockchain and assumes failure when the contract is not funded within a timeout. Timeout duration of the timeout is message-passing protocol dependent.

Anonymous Message Passing

This protocol is agnostic to means of anonymous message passing. The implementation details on anonymous message passing are out of scope of this document. However, the following are notable for being good fits.

Counterparty and Protocol Discovery (CAPD)

Counterparty and Protocol Discovery (CAPD) describes a method for relaying short-lived messages through the Bitcoin Cash network.

Using CAPD the users client would act as a network node and connect to a set of random Bitcoin Cash nodes on the network. The faucets would also act as a network node and would be subscribed to CAPD messages.

CAPD describes a message priority based on proof-of-work (PoW) and age. A message that has stronger proof-of-work (lower difficultyBit) generally has higher priority. A high enough priority will make the nodes pass this message to each other globally. This is called a global priority message.

Unless faucets are engaging in targeted attacks, such as sybil attacks, it is difficult to tell the origin of a global priority message, as nodes only pass the message between each other and not its origin.

Data payload contract

input payload contract

The following properties need to be satisfied by the contract:

  • The faucets cannot know any of the payload (this could allow them to selectively reject payloads).

  • The contract must be unlockable without revealing the real identity of the user.

Unlocking the contract

The contract is unlocked by two conditions:

  1. The hash of the payload is the same as provided to the faucet

  2. The transaction is signed with the public key that matches the public key provided to the faucet.

Design decisions

When used in protocols such an on-chain voting, there can be a requirement of constraining the outputs of the transaction.

In VotePeer for example, to produce a valid vote there is a requirement of that the transaction spending the contract input must create a specific output. This output could be enforced with Script covenants.

However, such constraint would consume capacity in the unlocking script. It is more valuable to keep the potential payload as large as possible.

Attack vectors

Accepting invalid faucet requests

Creating a request for funding has no cost, while funding a contract requires \~3000 satoshis. If the faucet does not validate the request it can easily be drained of funding.

Deanonymizing by cross-checking faucet request and vote

This only applies when used in on-chain voting.

If it's possible to use a subset of the participants as decoys, rather than the whole set, users should use the same subset for both signing request of coins from faucet and signing the vote.

If the user uses a different subset, the faucet can derive that the two signatures only share a single public key between them, exposing the user.

Empty data loads for profit

Our contract sets no limitations on how the outputs are supposed to look like. The faucets do not know the size of the data payload, so they need to provide an input amount large enough to pay for a full data payload.

Users are able to submit empty payload and take all the excessive amount to themselves. The maximum gain for ding this is the size of the payload in fees, or 1510 satoshis (0.0000151 BCH) with a fee of 1 satoshi / byte.

This vector can be removed using covenant restrictions on outputs, but this would limit the avaiable data load size. See design decisions.

Alternative privacy technology




Not yet implemented.