Makefile: update to latest BOLT text.

In particular:
	- Bolt 4: add route blinding construction
	- Bolt 4: add blinded payments

And this means it's not experimental, so we can turn it on
by default!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Added: Protocol: blinded payments are now supported by default (not just with `--experimental-onion-messages`)
This commit is contained in:
Rusty Russell 2023-04-07 16:25:33 +09:30
parent 458a85042b
commit d4ffc75691
13 changed files with 58 additions and 105 deletions

View file

@ -23,7 +23,7 @@ CCANDIR := ccan
# Where we keep the BOLT RFCs
BOLTDIR := ../bolts/
DEFAULT_BOLTVERSION := 20066dc2aba906f37f3be5a810ae67040f265377
DEFAULT_BOLTVERSION := c4c5a8e5fb30b1b99fa5bb0aba7d0b6b4c831ee5
# Can be overridden on cmdline.
BOLTVERSION := $(DEFAULT_BOLTVERSION)

View file

@ -27,7 +27,7 @@ static bool blind_node(const struct privkey *blinding,
SUPERVERBOSE("\t\"blinded_node_id\": \"%s\",\n",
type_to_string(tmpctx, struct pubkey, node_alias));
/* BOLT-route-blinding #4:
/* BOLT #4:
* - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)`
* (NB: `N(i)` MUST NOT learn `e(i)`)
*/
@ -36,7 +36,7 @@ static bool blind_node(const struct privkey *blinding,
SUPERVERBOSE("\t\"E\": \"%s\",\n",
type_to_string(tmpctx, struct pubkey, &blinding_pubkey));
/* BOLT-route-blinding #4:
/* BOLT #4:
* - `e(i+1) = SHA256(E(i) || ss(i)) * e(i)`
* (blinding ephemeral private key, only known by `N(r)`)
*/
@ -63,7 +63,7 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx,
/* All-zero npub */
static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
/* BOLT-route-blinding #4:
/* BOLT #4:
* - `ss(i) = SHA256(e(i) * N(i)) = SHA256(k(i) * E(i))`
* (ECDH shared secret known only by `N(r)` and `N(i)`)
*/
@ -80,7 +80,7 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx,
ret = tal_dup_talarr(ctx, u8, raw_encmsg);
/* BOLT-route-blinding #4:
/* BOLT #4:
* - `rho(i) = HMAC256("rho", ss(i))`
* (key used to encrypt the payload for `N(i)` by `N(r)`)
*/
@ -88,10 +88,10 @@ static u8 *enctlv_from_encmsg_raw(const tal_t *ctx,
SUPERVERBOSE("\t\"rho\": \"%s\",\n",
type_to_string(tmpctx, struct secret, &rho));
/* BOLT-route-blinding #4:
* - MUST encrypt each `encrypted_data_tlv(i)` with ChaCha20-Poly1305
* using the corresponding `rho(i)` key and an all-zero nonce to
* produce `encrypted_recipient_data(i)`
/* BOLT #4:
* - MUST encrypt each `encrypted_data_tlv(i)` with ChaCha20-Poly1305 using
* the corresponding `rho(i)` key and an all-zero nonce to produce
* `encrypted_recipient_data(i)`
*/
/* Encrypt in place */
towire_pad(&ret, crypto_aead_chacha20poly1305_ietf_ABYTES);
@ -132,7 +132,7 @@ bool unblind_onion(const struct pubkey *blinding,
{
struct secret hmac;
/* BOLT-route-blinding #4:
/* BOLT #4:
* A reader:
*...
* - MUST compute:
@ -145,7 +145,7 @@ bool unblind_onion(const struct pubkey *blinding,
/* We instead tweak the *ephemeral* key from the onion and use
* our normal privkey: since hsmd knows only how to ECDH with
* our real key. IOW: */
/* BOLT-route-blinding #4:
/* BOLT #4:
* - MUST use `b(i)` instead of its private key `k(i)` to decrypt the onion. Note
* that the node may instead tweak the onion ephemeral key with
* `HMAC256("blinded_node_id", ss(i))` which achieves the same result.
@ -165,7 +165,7 @@ static u8 *decrypt_encmsg_raw(const tal_t *ctx,
/* All-zero npub */
static const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
/* BOLT-route-blinding #4:
/* BOLT #4:
* A reader:
*...
*- MUST decrypt the `encrypted_data` field using `rho(i)` and use
@ -222,7 +222,7 @@ bool blindedpath_get_alias(const struct secret *ss,
{
struct secret node_id_blinding;
/* BOLT-route-blinding #4:
/* BOLT #4:
* - `B(i) = HMAC256("blinded_node_id", ss(i)) * N(i)`
* (blinded `node_id` for `N(i)`, private key known only by `N(i)`)
*/
@ -242,13 +242,13 @@ void blindedpath_next_blinding(const struct tlv_encrypted_data_tlv *enc,
const struct secret *ss,
struct pubkey *next_blinding)
{
/* BOLT-route
* - `E(1) = SHA256(E(0) || ss(0)) * E(0)`
/* BOLT #4:
* - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)`
* ...
* - If `encrypted_data` contains a `next_blinding_override`:
* - MUST use it as the next blinding point instead of `E(1)`
* - MUST use it as the next blinding point instead of `E(i+1)`
* - Otherwise:
* - MUST use `E(1)` as the next blinding point
* - MUST use `E(i+1)` as the next blinding point
*/
if (enc->next_blinding_override)
*next_blinding = *enc->next_blinding_override;

View file

@ -18,7 +18,7 @@ u8 **blinded_onion_hops(const tal_t *ctx,
bool first = (i == 0);
bool final = (i == tal_count(onions) - 1);
/* BOLT-route-blinding #4:
/* BOLT-blinded-payments #4:
* - For every node inside a blinded route:
* - MUST include the `encrypted_recipient_data` provided by the
* recipient

View file

@ -174,7 +174,7 @@ static const struct dependency feature_deps[] = {
* `option_anchors_zero_fee_htlc_tx` | ... | ... | `option_static_remotekey`
*/
{ OPT_ANCHORS_ZERO_FEE_HTLC_TX, OPT_STATIC_REMOTEKEY },
/* BOLT-route-blinding #9:
/* BOLT #9:
* Name | Description | Context | Dependencies |
* ...
* `option_route_blinding` | ... | ... | `var_onion_optin`

View file

@ -114,6 +114,7 @@ struct feature_set *feature_set_dup(const tal_t *ctx,
* | 18/19 | `option_support_large_channel` |... IN ...
* | 20/21 | `option_anchor_outputs` |... IN ...
* | 22/23 | `option_anchors_zero_fee_htlc_tx` |... IN ...
* | 24/25 | `option_route_blinding` |...IN9 ...
* | 26/27 | `option_shutdown_anysegwit` |... IN ...
* | 44/45 | `option_channel_type` |... IN ...
* | 48/49 | `option_payment_metadata` |... 9 ...
@ -130,15 +131,11 @@ struct feature_set *feature_set_dup(const tal_t *ctx,
#define OPT_LARGE_CHANNELS 18
#define OPT_ANCHOR_OUTPUTS 20
#define OPT_ANCHORS_ZERO_FEE_HTLC_TX 22
#define OPT_ROUTE_BLINDING 24
#define OPT_SHUTDOWN_ANYSEGWIT 26
#define OPT_CHANNEL_TYPE 44
#define OPT_PAYMENT_METADATA 48
/* BOLT-route-blinding #9:
* | 24/25 | `option_route_blinding` | Node supports blinded paths | IN9 | `var_onion_optin` | ...
*/
#define OPT_ROUTE_BLINDING 24
/* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9:
* | 28/29 | `option_dual_fund` | ... IN9 ...
*/

View file

@ -9,7 +9,7 @@
#include <common/sphinx.h>
#include <sodium/crypto_aead_chacha20poly1305.h>
/* BOLT-route-blinding #4:
/* BOLT #4:
* - If `encrypted_recipient_data` is present:
*...
* - If it is not the final node:
@ -31,7 +31,7 @@ static bool check_nonfinal_tlv(const struct tlv_payload *tlv,
return true;
}
/* BOLT-route-blinding #4:
/* BOLT #4:
* - If `encrypted_recipient_data` is present:
*...
* - If it is the final node:
@ -74,7 +74,7 @@ static bool handle_blinded_forward(struct onion_payload *p,
if (!check_nonfinal_tlv(tlv, failtlvtype))
return false;
/* BOLT-route-blinding #4:
/* BOLT #4:
* - If it is not the final node:
*...
* - MUST return an error if `encrypted_recipient_data` does not
@ -97,7 +97,7 @@ static bool handle_blinded_forward(struct onion_payload *p,
p->total_msat = NULL;
/* BOLT-route-blinding #4:
/* BOLT #4:
* - If it is not the final node:
*...
* - MUST return an error if `encrypted_recipient_data` does not
@ -125,7 +125,7 @@ static bool handle_blinded_terminal(struct onion_payload *p,
if (!check_final_tlv(tlv, failtlvtype))
return false;
/* BOLT-route-blinding #4:
/* BOLT #4:
* - MUST return an error if `amt_to_forward`, `outgoing_cltv_value`
* or `total_amount_msat` are not present.
* - MUST return an error if `amt_to_forward` is below what it expects
@ -157,7 +157,7 @@ static bool handle_blinded_terminal(struct onion_payload *p,
*p->total_msat = amount_msat(*tlv->total_amount_msat);
} else {
/* BOLT #4:
* - if it is the final node:
* - If it is the final node:
* - MUST treat `total_msat` as if it were equal to
* `amt_to_forward` if it is not present. */
p->total_msat = tal_dup(p, struct amount_msat,
@ -205,7 +205,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
return tal_free(p);
}
/* BOLT-route-blinding #4:
/* BOLT #4:
*
* The reader:
*
@ -220,7 +220,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
goto field_bad;
}
/* BOLT-route-blinding #4:
/* BOLT #4:
*
* - If `blinding_point` is set in the incoming `update_add_htlc`:
* - MUST return an error if `current_blinding_point` is present.
@ -244,7 +244,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
p->tlv->blinding_point);
}
/* BOLT-route-blinding #4:
/* BOLT #4:
* The reader:
*...
* - MUST return an error if `encrypted_recipient_data` does
@ -260,7 +260,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
}
if (enc->payment_constraints) {
/* BOLT-route-blinding #4:
/* BOLT #4:
* - MUST return an error if:
* - the expiry is greater than
* `encrypted_recipient_data.payment_constraints.max_cltv_expiry`.
@ -270,7 +270,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
goto field_bad;
}
/* BOLT-route-blinding #4:
/* BOLT #4:
* - MUST return an error if:
*...
* - the amount is below
@ -282,8 +282,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
goto field_bad;
}
/* BOLT-route-blinding #4:
* - If `allowed_features` is present:
/* BOLT #4:
* - MUST return an error if:
*...
* - the payment uses a feature not included in
@ -292,8 +291,10 @@ struct onion_payload *onion_decode(const tal_t *ctx,
/* We don't have any features yet... */
}
/* BOLT-route-blinding #4:
* - If `allowed_features` is present:
/* BOLT #4:
* - If `allowed_features` is missing:
* - MUST process the message as if it were present and contained an
* empty array.
* - MUST return an error if:
* - `encrypted_recipient_data.allowed_features.features`
* contains an unknown feature bit (even if it is odd).
@ -328,7 +329,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
return p;
}
/* BOLT-route-blinding-fix #4:
/* BOLT #4:
* - Otherwise (it is not part of a blinded route):
* - MUST return an error if `blinding_point` is set in the
* incoming `update_add_htlc` or `current_blinding_point`
@ -341,7 +342,8 @@ struct onion_payload *onion_decode(const tal_t *ctx,
/* BOLT #4:
*
* The reader:
* - Otherwise (it is not part of a blinded route):
*...
* - MUST return an error if `amt_to_forward` or
* `outgoing_cltv_value` are not present.
*/
@ -359,10 +361,9 @@ struct onion_payload *onion_decode(const tal_t *ctx,
/* BOLT #4:
*
* The writer:
*...
* - For every non-final node:
* - MUST include `short_channel_id`
* - if it is not the final node:
* - MUST return an error if:
* - `short_channel_id` is not present,
*/
if (!p->final) {
if (!p->tlv->short_channel_id) {
@ -375,7 +376,7 @@ struct onion_payload *onion_decode(const tal_t *ctx,
} else {
p->forward_channel = NULL;
/* BOLT #4:
* - if it is the final node:
* - If it is the final node:
* - MUST treat `total_msat` as if it were equal to
* `amt_to_forward` if it is not present. */
p->total_msat = tal_dup(p, struct amount_msat,

View file

@ -45,8 +45,9 @@ u8 *onion_nonfinal_hop(const tal_t *ctx,
/* BOLT #4:
*
* The writer:
* - For every node:
* The writer of `tlv_payload`:
*...
* - For every node outside of a blinded route:
* - MUST include `amt_to_forward` and `outgoing_cltv_value`.
* - For every non-final node:
* - MUST include `short_channel_id`
@ -74,8 +75,9 @@ u8 *onion_final_hop(const tal_t *ctx,
/* BOLT #4:
*
* The writer:
* - For every node:
* The writer of `tlv_payload`:
*...
* - For every node outside of a blinded route:
* - MUST include `amt_to_forward` and `outgoing_cltv_value`.
*...
* - For the final node:

View file

@ -858,6 +858,7 @@ static struct feature_set *default_features(const tal_t *ctx)
OPTIONAL_FEATURE(OPT_SCID_ALIAS),
OPTIONAL_FEATURE(OPT_ZEROCONF),
OPTIONAL_FEATURE(OPT_CHANNEL_TYPE),
OPTIONAL_FEATURE(OPT_ROUTE_BLINDING),
#if EXPERIMENTAL_FEATURES
OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS),
OPTIONAL_FEATURE(OPT_QUIESCE),

View file

@ -1064,9 +1064,6 @@ static char *opt_set_onion_messages(struct lightningd *ld)
feature_set_or(ld->our_features,
take(feature_set_for_feature(NULL,
OPTIONAL_FEATURE(OPT_ONION_MESSAGES))));
feature_set_or(ld->our_features,
take(feature_set_for_feature(NULL,
OPTIONAL_FEATURE(OPT_ROUTE_BLINDING))));
return NULL;
}

View file

@ -311,7 +311,7 @@ static bool check_fwd_amount(struct htlc_in *hin,
* - MUST return an error if:
* ...
* - `cltv_expiry` - `cltv_expiry_delta` < `outgoing_cltv_value`
* - if it is the final node:
* - If it is the final node:
*...
* - MUST return an error if:
*...
@ -382,7 +382,7 @@ static void handle_localpay(struct htlc_in *hin,
struct lightningd *ld = hin->key.channel->peer->ld;
/* BOLT #4:
* - if it is the final node:
* - If it is the final node:
* - MUST treat `total_msat` as if it were equal to `amt_to_forward` if it
* is not present.
* - MUST return an error if:
@ -408,7 +408,7 @@ static void handle_localpay(struct htlc_in *hin,
}
/* BOLT #4:
* - if it is the final node:
* - If it is the final node:
* - MUST treat `total_msat` as if it were equal to `amt_to_forward` if it
* is not present.
* - MUST return an error if:

View file

@ -2081,6 +2081,7 @@ def test_list_features_only(node_factory):
]
if EXPERIMENTAL_FEATURES:
expected += ['option_anchor_outputs/odd']
expected += ['option_route_blinding/odd']
expected += ['option_shutdown_anysegwit/odd']
expected += ['option_quiesce/odd']
expected += ['option_onion_messages/odd']
@ -2089,6 +2090,7 @@ def test_list_features_only(node_factory):
expected += ['option_zeroconf/odd']
expected += ['supports_open_accept_channel_type']
else:
expected += ['option_route_blinding/odd']
expected += ['option_shutdown_anysegwit/odd']
expected += ['option_channel_type/odd']
expected += ['option_scid_alias/odd']

View file

@ -3472,53 +3472,6 @@ def test_reject_invalid_payload(node_factory):
l1.rpc.waitsendpay(inv['payment_hash'])
@pytest.mark.skip("Needs to be updated for modern onion")
@unittest.skipIf(not EXPERIMENTAL_FEATURES, "Needs blinding args to sendpay")
def test_sendpay_blinding(node_factory):
l1, l2, l3, l4 = node_factory.line_graph(4)
blindedpathtool = os.path.join(os.path.dirname(__file__), "..", "devtools", "blindedpath")
# Create blinded path l2->l4
output = subprocess.check_output(
[blindedpathtool, '--simple-output', 'create',
l2.info['id'] + "/" + l2.get_channel_scid(l3),
l3.info['id'] + "/" + l3.get_channel_scid(l4),
l4.info['id']]
).decode('ASCII').strip()
# First line is blinding, then <peerid> then <encblob>.
blinding, p1, p1enc, p2, p2enc, p3 = output.split('\n')
# First hop can't be blinded!
assert p1 == l2.info['id']
amt = 10**3
inv = l4.rpc.invoice(amt, "lbl", "desc")
route = [{'id': l2.info['id'],
'channel': l1.get_channel_scid(l2),
'amount_msat': Millisatoshi(1002),
'delay': 21,
'blinding': blinding,
'enctlv': p1enc},
{'id': p2,
'amount_msat': Millisatoshi(1001),
'delay': 15,
# FIXME: this is a dummy!
'channel': '0x0x0',
'enctlv': p2enc},
{'id': p3,
# FIXME: this is a dummy!
'channel': '0x0x0',
'amount_msat': Millisatoshi(1000),
'delay': 9,
'style': 'tlv'}]
l1.rpc.sendpay(route=route,
payment_hash=inv['payment_hash'],
bolt11=inv['bolt11'], payment_secret=inv['payment_secret'])
l1.rpc.waitsendpay(inv['payment_hash'])
def test_excluded_adjacent_routehint(node_factory, bitcoind):
"""Test case where we try have a routehint which leads to an adjacent
node, but the result exceeds our maxfee; we crashed trying to find

View file

@ -41,7 +41,7 @@ def hex_bits(features):
def expected_peer_features(wumbo_channels=False, extra=[]):
"""Return the expected peer features hexstring for this configuration"""
features = [1, 5, 7, 8, 11, 13, 14, 17, 27, 45, 47, 51]
features = [1, 5, 7, 8, 11, 13, 14, 17, 25, 27, 45, 47, 51]
if EXPERIMENTAL_FEATURES:
# OPT_ONION_MESSAGES
features += [39]
@ -61,7 +61,7 @@ def expected_peer_features(wumbo_channels=False, extra=[]):
# features for the 'node' and the 'peer' feature sets
def expected_node_features(wumbo_channels=False, extra=[]):
"""Return the expected node features hexstring for this configuration"""
features = [1, 5, 7, 8, 11, 13, 14, 17, 27, 45, 47, 51, 55]
features = [1, 5, 7, 8, 11, 13, 14, 17, 25, 27, 45, 47, 51, 55]
if EXPERIMENTAL_FEATURES:
# OPT_ONION_MESSAGES
features += [39]