diff --git a/Makefile b/Makefile index 2942ad9d17b6..5ce1997b60f4 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/common/blindedpath.c b/common/blindedpath.c index 44a1d7ed9827..5721c36ad7f4 100644 --- a/common/blindedpath.c +++ b/common/blindedpath.c @@ -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; diff --git a/common/blindedpay.c b/common/blindedpay.c index d959f8f55d94..a9a9aa0cf61b 100644 --- a/common/blindedpay.c +++ b/common/blindedpay.c @@ -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 diff --git a/common/features.c b/common/features.c index 96f1bbff689b..8e0918db117c 100644 --- a/common/features.c +++ b/common/features.c @@ -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` diff --git a/common/features.h b/common/features.h index d9ec5744ed72..768cd0f68f3a 100644 --- a/common/features.h +++ b/common/features.h @@ -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 ... */ diff --git a/common/onion_decode.c b/common/onion_decode.c index 4df0ba53098b..57e78df2b23c 100644 --- a/common/onion_decode.c +++ b/common/onion_decode.c @@ -9,7 +9,7 @@ #include #include -/* 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, diff --git a/common/onion_encode.c b/common/onion_encode.c index e5a9e5e8d904..2a32c5ee5f77 100644 --- a/common/onion_encode.c +++ b/common/onion_encode.c @@ -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: diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 8135c282e7ce..c60e0127530d 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -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), diff --git a/lightningd/options.c b/lightningd/options.c index b35b930429b2..ee3d56001020 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -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; } diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index b6fc4fec27d5..6adbd248db55 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -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: diff --git a/tests/test_misc.py b/tests/test_misc.py index 7eb0e87a765b..de40b3f4c5b8 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -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'] diff --git a/tests/test_pay.py b/tests/test_pay.py index 09964a788317..bcd26773e31f 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -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 then . - 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 diff --git a/tests/utils.py b/tests/utils.py index 9b8eea7e0272..c93f6b024ec5 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -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]