Sharing Unblinded Transaction Data With Third Parties

As Blockstream AMP transactions are carried out on the Liquid network they are, by default, covered by confidential transactions. Confidential transactions on Liquid mean that normally only the sender and receiver know how much of an asset, and which asset, has been sent. Blockstream AMP issued assets allow the asset issuer to also view the transacted asset and amount, via the Blockstream AMP API.

In some cases the issuer, or the user, might want to share the unblinded details of the transaction with a third party, such as an auditor.

For normal Liquid assets the unblinding data can only be shared by the user. Blockstream AMP unblinding data can additionally be shared by the issuer. We will look at each of these cases in turn from the perspective of the issuer and then the user.

For our example we will be unblinding transactions that involve Blockstream’s ‘Issuer Tracked Demo Asset’. The asset details can be found on the Blockstream explorer. You will see that the issuance itself was not confidential, meaning that the issuance data is viewable via the details section of the page. As with all AMP assets, any subsequent transactions involving the asset (apart from issuer-invoked reissuances and burns) will be covered by Liquid’s confidential transactions, where the amount and asset being transacted are cryptographically hidden from everyone looking at Liquid blockchain data.

By providing the ‘blinding keys’ to someone it is possible for either the issuer, or the user, to share the actual amount and asset id being transacted with a third party.

First, we will see how to use the Blockstream Liquid explorer to unblind a transaction’s output, from the perspective of the issuer and then the user, and then we will use the verify-elements-commitments Python script to verify the data ourselves.

Verifying commitments yourself

Rather than trust the commitment proof provided by the Blockstream Liquid explorer above you may want to run your own proof of commitments. You can do this using the verify-elements-commitments Python script, which itself uses Libwally, a cross-platform, cross-language collection of useful primitives for cryptocurrency wallets.

We’ll use the same transaction and commitment data used above, involving the Blockstream AMP demo site’s Issuer Tracked Demo Asset for this example.

To run the Python script the issuer first needs to install the prerequisites. From the terminal, create a folder to run the code from and move into it:

mkdir verify_elements_commitments
cd verify_elements_commitments

Then (optionally) initialize a Python virtual environment to install the requirements within:

virtualenv -p python3 venv
source venv/bin/activate

Into this environment you need to install libwally-core. The source code for libwally can be found in the Libwally repository.

pip install wallycore

Download the file from:

Place the downloaded file in the verify_elements_commitments folder.

Get the relevant transaction hex from your Elements node. For your own transaction this would be done using the following command from the terminal:

elements-cli getrawtransaction <transaction_id>

So for our example we would run:

elements-cli getrawtransaction e6d8feb9a539628fe9386570fc6c546315a1ce37d64ce104fc742545c45102ea

Alternatively you can get the transaction hex from the Blockstream liquid explorer:

Save the results of either of the above to a new file named transaction.txt within the verify_elements_commitments folder.

Next, the issuer would call the Blockstream AMP API /assets/{assetUuid}/activities endpoint for whichever asset they want to prove commitments for. The returned activities data contains everything that is needed to form the required blinders data. Using the example of the 100 ‘Issuer-Tracked Demo Asset’ sent to the GA2eP3RJnt4CYHNmc8GwbwGfpzCz5C wallet of the user in transaction e6d8feb9... the issuer singles out the relevant activity using the txid, GAID, and amount.

The data for our example asset looks like this when the example issuer calls the activities API and filters the returned data to only show the investor receive activity:

    "type": "transfer",
    "datetime": "2021-02-11T09:10:58Z",
    "description": "Transfer to wallet GA2eP3RJnt4CYHNmc8GwbwGfpzCz5C",
    "txid": "e6d8feb9a539628fe9386570fc6c546315a1ce37d64ce104fc742545c45102ea",
    "vout": 0,
    "blockheight": 1188465,
    "investor": null,
    "GAID": "GA2eP3RJnt4CYHNmc8GwbwGfpzCz5C",
    "amount": 100,
    "asset_blinder": "7dadf08a4b5750f4795a48f7ede24732ea6efca3dc46c51806d332fdd6464cc3",
    "amount_blinder": "3d48822703130651d51583438f5d4692b337b9483a1b4d81d158672a4f288838",
    "registered_user": null

The issuer then selects and saves the output blinders they are interested in, using the following format, and saves it to a file named blinders.json:

            "asset_id_hex": "f266a3f15e78b71481adfedff9aefe47c69501a181ffc68527bb5fb26da6a4b2",
            "asset_blinder_hex": "7dadf08a4b5750f4795a48f7ede24732ea6efca3dc46c51806d332fdd6464cc3",
            "amount_satoshi": 100,
            "amount_blinder_hex": "3d48822703130651d51583438f5d4692b337b9483a1b4d81d158672a4f288838"


You can include as many outputs as you like for the transaction in the format shown above, i.e. if you wanted to include the change output as well, you can. We will just use the output where the investor received the asset in our example.

Now the issuer can execute the proof like this:

python --tx transaction.txt --blinded blinders.json

Which, in our example case, will output:

  "txid": "e6d8feb9a539628fe9386570fc6c546315a1ce37d64ce104fc742545c45102ea",
  "inputs": [],
  "outputs": [
      "vout": 0,
      "asset": "f266a3f15e78b71481adfedff9aefe47c69501a181ffc68527bb5fb26da6a4b2",
      "satoshi": 100

Using the Python script you can verify the blinders yourself, without having to trust the Blockstream Liquid explorer’s implementation of the same process.