BOLT12 Lightning Address Format

Overview

BOLT12 Address Support (DRAFT!)

Inspired by the awesome lightningaddress.com, except for BOLT12:

  1. Supports BOLT12
  2. Allows BOLT12 vendor string authentication
  3. Doesn't require your wallet to query the server directly
  4. Required only to establish the initial node linkage

How Does it Work?

Like lightningaddress.com, you turn [email protected] into a web request:

https://domain.com/.well-known/bolt12/bitcoin/[email protected]

But you can also authenticate the entire domain:

https://domain.com/.well-known/bolt12/bitcoin/domain.com

(Instead of bitcoin you could use testnet, signet or regtest)

The Format

The format is a bolt12 TLV binary (Content-type: application/x-lightning-bolt12), containing the following fields:

  1. tlv_stream: addressproof
  2. types:
    • type: 2 (chains)
    • data:
      • [...*chain_hash:chains]
    • type: 10 (description)
    • data:
      • [...*utf8:description]
    • type: 12 (features)
    • data:
      • [...*byte:features]
    • type: 14 (absolute_expiry)
    • data:
      • [tu64:seconds_from_epoch]
    • type: 16 (paths)
    • data:
      • [...*blinded_path:paths]
    • type: 20 (vendor)
    • data:
      • [...*utf8:vendor]
    • type: 60 (node_ids)
    • data:
      • [...*point32:node_ids]
    • type: 500 (certsignature)
    • data:
      • [...*byte:sig]
    • type: 501 (cert)
    • data:
      • [...*byte:cert]
    • type: 503 (certchain)
    • data:
      • [...*byte:chain]

Only the vendor, node_ids and certsignature fields are required, the others are optional.

Requirements

The writer:

  • MUST set vendor to filename being served:
  • MUST set node_ids to zero or more node_ids which will be used to sign offers for this vendor.
  • MUST set chains to the chains these node_ids are valid for, or MAY not set chains if the node_ids are valid for Bitcoin.
  • MAY set features, absolute_expiry, description and paths (see BOLT 12).
  • MUST set certsignature to the RSA signature (using PSS padding mode maximum saltlen) of the BOLT-12 merkle root as per BOLT12 Signature Calculation using the secret key for the domain in vendor.
  • MUST NOT set description unless it has an offer which is constructed using the other fields, and the offer's node_id set to the first of the node_ids.
  • If it is serving the addressproof over HTTPS:
    • MAY set cert and certchain
  • Otherwise:
    • MUST set both cert and certchain
  • If it sets cert:
    • MUST set it to the PEM-encoded certificate corresponding to the domain
  • If it sets certchain:
    • MUST set it to the PEM-encoded chain of certificates leading from cert to the root CA

The reader:

  • MUST NOT accept the address proof if vendor, node_ids or certsignature is not present.

  • MUST NOT accept the address proof if an even unknown bit is set in features.

  • If it has NOT retrieved the addressproof over HTTPS:

    • MUST NOT accept the address proof if:
      • cert is not present, or not valid for the domain in vendor.
      • certchain is not present, or does not link cert to a root certificate authority.
      • certsignature field is not a valid signature for BOLT-12 merkle root using the key in cert.
  • otherwise:

    • MAY retrieve cert and certchain from the HTTPS connection.
    • MAY NOT accept the address proof as it would in the non-HTTPS case above.
  • If if has a previous, valid addressproof for this vendor:

    • MUST ONLY replace it with this address proof if:
      • absolute_expiry is set, AND
      • it is greater than the previous absolute_expiry OR the previous had no absolute_expiry field.
  • MUST consider the addressproof no longer valid if absolute_expiry is set and the current number of seconds since 1970 is greater than that value.

  • if description is present:

    • MAY use the fields of this addressproof as an unsigned offer.
  • When it encounters a vendor field in a BOLT12 offer or invoice:

    • if the vendor begins with a valid domain, up to a space character:
      • SHOULD WARN the user if it cannot find a current valid address proof.
      • SHOULD reject the offer or invoice if the node_id is not one of the node_ids in the offer.

Text Encoding

The human-readable prefix for addressproof is lnap, if you want it encoded as a string.

What Does All This Do?

This allows domain validation for bolt 12 offers, which already have a vendor field for this purpose. e.g if the vendor in an offer is "blockstream.com Get your blocks here!" then your wallet can reach out to blockstream.com to see if it the node_id in the offer really is under their control.

It also allows node_id proofs for individual addresses.

But you don't need to reach out to blockstream.com: anyone (including your wallet vendor, or the node claiming to be blockstream.com) can collect all the addressproofs and certificates for you, as they contain a signature using the existing web certificate infrastructure. Bundling these protects your privacy more than having to request to a vendor's website before making a payment.

This format is a subset of the BOLT12 offer format, so if it has a description it is actually a valid (amountless) offer, allowing immediate tipping using it.

You can also include zero node_ids, as a way of indicating that you do not have any lightning nodes.

Examples

You will need access to your privkey.pem, cert.pem and chain.pem files on your HTTPS webserver which serves the domain.

This creates a proof that bolt12.org operates nodeid 4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 (note we omit the 02/03 prefix):

$ ./shell/make-addressproof.sh \
   --vendor=bolt12.org \
   --nodeid=4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 \
   --privkeyfile=certs/privkey.pem \
   --certfile=certs/cert.pem \
   --chainfile=certs/chain.pem > .well-known/bolt12/bitcoin/bolt12.org

This does the same thing using the Python script:

$ ./python/bolt12address.py create \
   --raw \
   bolt12.org \
   certs/privkey.pem \
   certs/cert.pem \
   certs/chain.pem \
   4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 \
   > .well-known/bolt12/bitcoin/bolt12.org

This creates a signet signature for multiple nodeids, for the user [email protected], and adds a description so it can also serve as offer for sending unsolicited payments (note: see below!):

$ ./shell/make-addressproof.sh \
   [email protected] \
   --nodeid=4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 \
   --nodeid=994b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc4496 \
   --privkeyfile=certs/privkey.pem \
   --certfile=certs/cert.pem \
   --chainfile=certs/chain.pem \
   --chain=signet \
   --description='Unsolicited bolt12address donation' \
   > .well-known/bolt12/signet/[email protected]

And in Python:

$ ./python/bolt12address.py create \
   --raw \
   --description='Unsolicited bolt12address donation' \
   --chain=signet \
   [email protected] \
   certs/privkey.pem \
   certs/cert.pem \
   certs/chain.pem \
   4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 \
   994b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc4496 \
   > .well-known/bolt12/signet/[email protected]

We can check this using python:

$ ./python/bolt12address.py check --raw-stdin < .well-known/bolt12/signet/[email protected]
chains: ['f61eee3b63a380a477a063af32b2bbc97c9ff9f01f2c4225e973988108000000']
description: Unsolicited bolt12address donation
vendor: [email protected]
node_ids: ['4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605', '994b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc4496']
certsignature: 173e...

offer_id: 3234297fb2414b62c16ac9751ac241050199ec5e2cd83e713136cc26974f09a8
offer_id: 3139b327c9fa6637a7ef620149425a1163e19a1181c9f1cbdc7820360dd40c23

The offer_id at the end if description is populated (one for each node_id) is the offer_id anyone reading would expect to be able to send funds to. You should create this offer (with that description and no amount) on your node!

Refreshing Existing Proofs

There's a simple helper to refresh existing address proofs, such as when your certificate changes:

$ ./python/bolt12address.py refresh \
   certs/privkey.pem \
   certs/cert.pem \
   certs/chain.pem \
   .well-known/bolt12/signet/*bolt12.org
.well-known/bolt12/signet/[email protected]: REFRESHED

TODO

This is a draft: I expect it to change after feedback (especially since the certinficates and signatures are large and clunky).

The code does not check the certificate chain, and is generally could use polishing.

We also need more routines in different languages to fetch and check the bolt12address, and a method so Lightning nodes can serve their addressproof directly.

Feedback

You can reach out to me as [email protected] or join the bolt12 telegram group at https://t.me/bolt12org.

Happy hacking!

Owner
Rusty Russell
GPG: 15EE 8D6C AB0E 7F0C F999 BFCB D920 0E6C D1AD B8F1 Rusty Russell
Rusty Russell
A library to easily convert climbing route grades between different grading systems.

pyclimb A library to easily convert climbing route grades between different grading systems. In rock climbing, mountaineering, and other climbing disc

Ilias Antonopoulos 4 Jan 26, 2022
A python script to generate wallpaper

wallpaper eits Warning You need to set the path to Robot Mono font in the source code. (Settings are in the main function) Usage A script that given a

Henrique Tsuyoshi Yara 5 Dec 02, 2021
Automatic generator of readmes for git repositories (Includes file' listing)

Readme Generator We are bored of write the same things once and once again. We trust in the comments made inside of our files, and we decided to autom

Natalia Vera Duran 6 Jul 20, 2021
Utility to extract Fantasy Grounds Unity Line-of-sight and lighting files from a Univeral VTT file exported from Dungeondraft

uvtt2fgu Utility to extract Fantasy Grounds Unity Line-of-sight and lighting files from a Univeral VTT file exported from Dungeondraft This program wo

Andre Kostur 29 Dec 05, 2022
Dice Rolling Simulator using Python-random

Dice Rolling Simulator As the name of the program suggests, we will be imitating a rolling dice. This is one of the interesting python projects and wi

PyLaboratory 1 Feb 02, 2022
Simple code to generate a password for your account!

Password-Generator Simple code to generate a password for your account! Password Generator for passwords for your accounts or anything else! This code

DEEM 1 Jun 05, 2022
An online streamlit development platform

streamlit-playground An online streamlit development platform Run, Experiment and Play with streamlit Components Develop full-fledged apps online All

Akshansh Kumar 3 Nov 06, 2021
A thing to simplify listening for PG notifications with asyncpg

asyncpg-listen This library simplifies usage of listen/notify with asyncpg: Handles loss of a connection Simplifies notifications processing from mult

ANNA 18 Dec 23, 2022
These scripts look for non-printable unicode characters in all text files in a source tree

find-unicode-control These scripts look for non-printable unicode characters in all text files in a source tree. find_unicode_control.py should work w

Siddhesh Poyarekar 25 Aug 30, 2022
Handy Tool to check the availability of onion site and to extract the title of submitted onion links.

This tool helps is to quickly investigate a huge set of onion sites based by checking its availability which helps to filter out the inactive sites and collect the site title that might helps us to c

Balaji 13 Nov 25, 2022
jfc is an utility to make reviewing ArXiv papers for your Journal Club easier.

jfc is an utility to make reviewing ArXiv papers for your Journal Club easier.

Miguel M. 3 Dec 20, 2021
Program to extract signatures from documents.

Extracting Signatures from Bank Checks Introduction Ahmed et al. [1] suggest a connected components-based method for segmenting signatures in document

Muhammad Saif Ullah Khan 9 Jan 26, 2022
This is Cool Utility tools that you can use in python.

This is Cool Utility tools that you can use in python. There are a few tools that you might find very useful, you can use this on pretty much any project and some utils might help you a lot and save

Senarc Studios 6 Apr 18, 2022
✨ Un code pour voir les disponibilités des vaccins contre le covid totalement fait en Python par moi, et en français.

Vaccine Notifier ❗ Un chois aléatoire d'un article sur Wikipedia totalement fait en Python par moi, et en français. 🔮 Grâce a une requète API, on peu

MrGabin 3 Jun 06, 2021
Script for generating Hearthstone card spoilers & checklists

This is a script for generating text spoilers and set checklists for Hearthstone. Installation & Running Python 3.6 or higher is required. Copy/clone

John T. Wodder II 1 Oct 11, 2022
Every 2 minutes, check for visa slots at VFS website

vfs-visa-slot-germany Every 2 minutes, check for visa slots at VFS website. If there are any, send a call and a message of the format: Sent from your

12 Dec 15, 2022
A python app which aggregates and splits costs from multiple public cloud providers into a csv

Cloud Billing This project aggregates the costs public cloud resources by accounts, services and tags by importing the invoices from public cloud prov

1 Oct 04, 2022
Keval allows you to call arbitrary Windows kernel-mode functions from user mode, even (and primarily) on another machine.

Keval Keval allows you to call arbitrary Windows kernel-mode functions from user mode, even (and primarily) on another machine. The user mode portion

42 Dec 17, 2022
✨ Un DNS Resolver totalement fait en Python par moi, et en français

DNS Resolver ❗ Un DNS Resolver totalement fait en Python par moi, et en français. 🔮 Grâce a une adresse (url) vous pourrez avoir l'ip ainsi que le DN

MrGabin 3 Jun 06, 2021
Dill_tils is a package that has my commonly used functions inside it for ease of use.

DilllonB07 Utilities Dill_tils is a package that has my commonly used functions inside it for ease of use. Installation Anyone can use this package by

Dillon Barnes 2 Dec 05, 2021