Skip to content

Commit

Permalink
BOLT 12: update to include replace_invoice options.
Browse files Browse the repository at this point in the history
We don't support it (yet), but update the spec to include it.

We include the previous field (recurrence_signature) as a shim for the
moment, for compat with existing nodes.  It's ugly, but next release
we'll stop *sending* it, then finally we'll stop accepting it!

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jul 2, 2021
1 parent 11720fc commit 2beb9c1
Show file tree
Hide file tree
Showing 20 changed files with 312 additions and 64 deletions.
13 changes: 11 additions & 2 deletions devtools/bolt12-cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,16 +545,25 @@ int main(int argc, char *argv[])
print_features(invreq->features);
if (invreq->quantity)
print_quantity(*invreq->quantity);
/* Note: old format didn't include this, so we don't complain! */
if (invreq->payer_signature)
well_formed &= print_signature("invoice_request",
"payer_signature",
invreq->fields,
invreq->payer_key,
invreq->payer_signature);
if (invreq->recurrence_counter) {
print_recurrence_counter(invreq->recurrence_counter,
invreq->recurrence_start);
if (must_have(invreq, recurrence_signature)) {
/* Old form included recurrence_signature */
if (invreq->recurrence_signature)
well_formed &= print_signature("invoice_request",
"recurrence_signature",
invreq->fields,
invreq->payer_key,
invreq->recurrence_signature);
}
else /* New form definitely should have this! */
must_have(invreq, payer_signature);
} else {
must_not_have(invreq, recurrence_start);
must_not_have(invreq, recurrence_signature);
Expand Down
26 changes: 14 additions & 12 deletions lightningd/offer.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <common/bolt12.h>
#include <common/bolt12_merkle.h>
#include <common/configdir.h>
#include <common/json_command.h>
#include <common/json_helpers.h>
#include <common/jsonrpc_errors.h>
Expand Down Expand Up @@ -403,6 +404,7 @@ static struct command_result *json_createinvoicerequest(struct command *cmd,
const char *label;
struct json_stream *response;
u64 *prev_basetime = NULL;
struct sha256 merkle;

if (!param(cmd, buffer, params,
p_req("bolt12", param_b12_invreq, &invreq),
Expand Down Expand Up @@ -448,24 +450,24 @@ static struct command_result *json_createinvoicerequest(struct command *cmd,
}

/* BOLT-offers #12:
* - if the offer contained `recurrence`:
*...
* - MUST set `recurrence_signature` `sig` as detailed in
* [Signature Calculation](#signature-calculation) using the
* `payer_key`.
* - MUST set `payer_signature` `sig` as detailed in
* [Signature Calculation](#signature-calculation) using the `payer_key`.
*/
if (invreq->recurrence_counter) {
struct sha256 merkle;

/* This populates the ->fields from our entries */
invreq->fields = tlv_make_fields(invreq, invoice_request);
merkle_tlv(invreq->fields, &merkle);
/* This populates the ->fields from our entries */
invreq->fields = tlv_make_fields(invreq, invoice_request);
merkle_tlv(invreq->fields, &merkle);
invreq->payer_signature = tal(invreq, struct bip340sig);
hsm_sign_b12(cmd->ld, "invoice_request", "payer_signature",
&merkle, invreq->payer_info, invreq->payer_key,
invreq->payer_signature);

/* Backwards compat for older version! */
if (deprecated_apis && invreq->recurrence_counter) {
invreq->recurrence_signature = tal(invreq, struct bip340sig);
hsm_sign_b12(cmd->ld, "invoice_request", "recurrence_signature",
&merkle, invreq->payer_info, invreq->payer_key,
invreq->recurrence_signature);
}

response = json_stream_success(cmd);
json_add_string(response, "bolt12", invrequest_encode(tmpctx, invreq));
if (label)
Expand Down
37 changes: 25 additions & 12 deletions plugins/offers.c
Original file line number Diff line number Diff line change
Expand Up @@ -665,28 +665,41 @@ static void json_add_invoice_request(struct json_stream *js,
json_add_hex_talarr(js, "payer_info", invreq->payer_info);

/* BOLT-offers #12:
* - if the offer had a `recurrence`:
* - MUST fail the request if there is no `recurrence_counter` field.
* - MUST fail the request if there is no `recurrence_signature` field.
* - MUST fail the request if `recurrence_signature` is not correct.
* - MUST fail the request if there is no `payer_signature` field.
* - MUST fail the request if `payer_signature` is not correct.
*/
if (invreq->recurrence_signature) {
json_add_bip340sig(js, "recurrence_signature",
invreq->recurrence_signature);
/* Older spec didn't have this, so we allow omission for now. */
if (invreq->payer_signature) {
json_add_bip340sig(js, "payer_signature",
invreq->payer_signature);
if (invreq->payer_key
&& !bolt12_check_signature(invreq->fields,
"invoice_request",
"payer_signature",
invreq->payer_key,
invreq->payer_signature)) {
json_add_string(js, "warning_invoice_request_invalid_payer_signature",
"Bad payer_signature");
valid = false;
}
} else {
json_add_string(js, "warning_invoice_request_missing_payer_signature",
"Missing payer_signature");
if (!deprecated_apis)
valid = false;
}

if (deprecated_apis && invreq->recurrence_counter) {
if (invreq->payer_key
&& !bolt12_check_signature(invreq->fields,
"invoice_request",
"recurrence_signature",
invreq->payer_key,
invreq->recurrence_signature)) {
json_add_string(js, "warning_invoice_request_invalid_recurrence_signature",
"Bad recurrence_signature");
"Bad recurrence_signature");
valid = false;
}
} else if (invreq->recurrence_counter) {
json_add_string(js, "warning_invoice_request_missing_recurrence_signature",
"invoice_request requires recurrence_signature");
valid = false;
}

json_add_bool(js, "valid", valid);
Expand Down
63 changes: 46 additions & 17 deletions plugins/offers_invreq_hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,7 @@ static struct command_result *check_previous_invoice(struct command *cmd,
return send_outreq(cmd->plugin, req);
}

/* BOLT-offers #12:
* - MUST fail the request if `recurrence_signature` is not correct.
*/
/* Obsolete recurrence_signature; we still check if present. */
static bool check_recurrence_sig(const struct tlv_invoice_request *invreq,
const struct pubkey32 *payer_key,
const struct bip340sig *sig)
Expand All @@ -425,6 +423,23 @@ static bool check_recurrence_sig(const struct tlv_invoice_request *invreq,
sighash.u.u8, &payer_key->pubkey) == 1;
}

/* BOLT-offers #12:
* - MUST fail the request if `payer_signature` is not correct.
*/
static bool check_payer_sig(const struct tlv_invoice_request *invreq,
const struct pubkey32 *payer_key,
const struct bip340sig *sig)
{
struct sha256 merkle, sighash;
merkle_tlv(invreq->fields, &merkle);
sighash_from_merkle("invoice_request", "payer_signature",
&merkle, &sighash);

return secp256k1_schnorrsig_verify(secp256k1_ctx,
sig->u8,
sighash.u.u8, &payer_key->pubkey) == 1;
}

static struct command_result *invreq_amount_by_quantity(struct command *cmd,
const struct invreq *ir,
u64 *raw_amt)
Expand Down Expand Up @@ -706,6 +721,19 @@ static struct command_result *listoffers_done(struct command *cmd,
return err;
}

/* FIXME: payer_signature is now always required, but we let it go
* for now. */
if (!deprecated_apis) {
err = invreq_must_have(cmd, ir, payer_signature);
if (err)
return err;
if (!check_payer_sig(ir->invreq,
ir->invreq->payer_key,
ir->invreq->payer_signature)) {
return fail_invreq(cmd, ir, "bad payer_signature");
}
}

if (ir->offer->recurrence) {
/* BOLT-offers #12:
*
Expand All @@ -721,30 +749,31 @@ static struct command_result *listoffers_done(struct command *cmd,
if (err)
return err;

err = invreq_must_have(cmd, ir, recurrence_signature);
if (err)
return err;

if (!check_recurrence_sig(ir->invreq,
ir->invreq->payer_key,
ir->invreq->recurrence_signature)) {
return fail_invreq(cmd, ir,
"bad recurrence_signature");
if (deprecated_apis) {
if (ir->invreq->recurrence_signature) {
if (!check_recurrence_sig(ir->invreq,
ir->invreq->payer_key,
ir->invreq->recurrence_signature)) {
return fail_invreq(cmd, ir,
"bad recurrence_signature");
}
} else {
/* You really do need payer_signature if
* you're using recurrence: we rely on it! */
err = invreq_must_have(cmd, ir, payer_signature);
if (err)
return err;
}
}
} else {
/* BOLT-offers #12:
* - otherwise (the offer had no `recurrence`):
* - MUST fail the request if there is a `recurrence_counter`
* field.
* - MUST fail the request if there is a `recurrence_signature`
* field.
*/
err = invreq_must_not_have(cmd, ir, recurrence_counter);
if (err)
return err;
err = invreq_must_not_have(cmd, ir, recurrence_signature);
if (err)
return err;
}

ir->inv = tlv_invoice_new(cmd);
Expand Down
3 changes: 3 additions & 0 deletions wire/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,17 @@ WIRE_BOLT_DEPS := $(BOLT_DEPS) tools/gen/impl_template tools/gen/header_template

ALL_PEER_PATCHES := $(sort $(wildcard wire/extracted_peer*.patch))
ALL_ONION_PATCHES := $(sort $(wildcard wire/extracted_onion*.patch))
ALL_BOLT12_PATCHES := $(sort $(wildcard wire/extracted_bolt12*.patch))

# These are applied to the non-exp csvs to make the exp csvs.
PEER_EXP_PATCHES := $(sort $(wildcard wire/extracted_peer_exp*.patch))
ONION_EXP_PATCHES := $(sort $(wildcard wire/extracted_onion_exp*.patch))
BOLT12_EXP_PATCHES := $(sort $(wildcard wire/extracted_bolt12_exp*.patch))

# These are always applied to the bolts.
PEER_PATCHES := $(filter-out $(PEER_EXP_PATCHES),$(ALL_PEER_PATCHES))
ONION_PATCHES := $(filter-out $(ONION_EXP_PATCHES),$(ALL_ONION_PATCHES))
BOLT12_PATCHES := $(filter-out $(BOLT12_EXP_PATCHES),$(ALL_BOLT12_PATCHES))

# Explicit command to re-extract CSV from BOLTs and patch.
# This is not a normal make depencency, since we don't want this
Expand Down
14 changes: 13 additions & 1 deletion wire/bolt12_exp_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,15 @@ tlvtype,invoice_request,recurrence_start,68
tlvdata,invoice_request,recurrence_start,period_offset,tu32,
tlvtype,invoice_request,payer_key,38
tlvdata,invoice_request,payer_key,key,pubkey32,
tlvtype,invoice_request,payer_note,39
tlvdata,invoice_request,payer_note,note,utf8,...
tlvtype,invoice_request,payer_info,50
tlvdata,invoice_request,payer_info,blob,byte,...
tlvtype,invoice_request,recurrence_signature,242
tlvtype,invoice_request,replace_invoice,56
tlvdata,invoice_request,replace_invoice,payment_hash,sha256,
tlvtype,invoice_request,payer_signature,241
tlvdata,invoice_request,payer_signature,sig,bip340sig,
tlvtype,invoice_request,recurrence_signature,240
tlvdata,invoice_request,recurrence_signature,sig,bip340sig,
tlvtype,invoice,chains,2
tlvdata,invoice,chains,chains,chain_hash,...
Expand All @@ -75,6 +81,8 @@ tlvtype,invoice,paths,16
tlvdata,invoice,paths,paths,blinded_path,...
tlvtype,invoice,blindedpay,18
tlvdata,invoice,blindedpay,payinfo,blinded_payinfo,...
tlvtype,invoice,blinded_capacities,19
tlvdata,invoice,blinded_capacities,incoming_msat,u64,...
tlvtype,invoice,vendor,20
tlvdata,invoice,vendor,vendor,utf8,...
tlvtype,invoice,node_id,30
Expand All @@ -92,6 +100,8 @@ tlvtype,invoice,recurrence_basetime,64
tlvdata,invoice,recurrence_basetime,basetime,tu64,
tlvtype,invoice,payer_key,38
tlvdata,invoice,payer_key,key,pubkey32,
tlvtype,invoice,payer_note,39
tlvdata,invoice,payer_note,note,utf8,...
tlvtype,invoice,payer_info,50
tlvdata,invoice,payer_info,blob,byte,...
tlvtype,invoice,timestamp,40
Expand All @@ -107,6 +117,8 @@ tlvdata,invoice,fallbacks,num,u8,
tlvdata,invoice,fallbacks,fallbacks,fallback_address,num
tlvtype,invoice,refund_signature,52
tlvdata,invoice,refund_signature,payer_signature,bip340sig,
tlvtype,invoice,replace_invoice,56
tlvdata,invoice,replace_invoice,payment_hash,sha256,
tlvtype,invoice,signature,240
tlvdata,invoice,signature,sig,bip340sig,
subtype,blinded_payinfo
Expand Down
14 changes: 13 additions & 1 deletion wire/bolt12_wire.csv
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,15 @@ tlvtype,invoice_request,recurrence_start,68
tlvdata,invoice_request,recurrence_start,period_offset,tu32,
tlvtype,invoice_request,payer_key,38
tlvdata,invoice_request,payer_key,key,pubkey32,
tlvtype,invoice_request,payer_note,39
tlvdata,invoice_request,payer_note,note,utf8,...
tlvtype,invoice_request,payer_info,50
tlvdata,invoice_request,payer_info,blob,byte,...
tlvtype,invoice_request,recurrence_signature,242
tlvtype,invoice_request,replace_invoice,56
tlvdata,invoice_request,replace_invoice,payment_hash,sha256,
tlvtype,invoice_request,payer_signature,241
tlvdata,invoice_request,payer_signature,sig,bip340sig,
tlvtype,invoice_request,recurrence_signature,240
tlvdata,invoice_request,recurrence_signature,sig,bip340sig,
tlvtype,invoice,chains,2
tlvdata,invoice,chains,chains,chain_hash,...
Expand All @@ -75,6 +81,8 @@ tlvtype,invoice,paths,16
tlvdata,invoice,paths,paths,blinded_path,...
tlvtype,invoice,blindedpay,18
tlvdata,invoice,blindedpay,payinfo,blinded_payinfo,...
tlvtype,invoice,blinded_capacities,19
tlvdata,invoice,blinded_capacities,incoming_msat,u64,...
tlvtype,invoice,vendor,20
tlvdata,invoice,vendor,vendor,utf8,...
tlvtype,invoice,node_id,30
Expand All @@ -92,6 +100,8 @@ tlvtype,invoice,recurrence_basetime,64
tlvdata,invoice,recurrence_basetime,basetime,tu64,
tlvtype,invoice,payer_key,38
tlvdata,invoice,payer_key,key,pubkey32,
tlvtype,invoice,payer_note,39
tlvdata,invoice,payer_note,note,utf8,...
tlvtype,invoice,payer_info,50
tlvdata,invoice,payer_info,blob,byte,...
tlvtype,invoice,timestamp,40
Expand All @@ -107,6 +117,8 @@ tlvdata,invoice,fallbacks,num,u8,
tlvdata,invoice,fallbacks,fallbacks,fallback_address,num
tlvtype,invoice,refund_signature,52
tlvdata,invoice,refund_signature,payer_signature,bip340sig,
tlvtype,invoice,replace_invoice,56
tlvdata,invoice,replace_invoice,payment_hash,sha256,
tlvtype,invoice,signature,240
tlvdata,invoice,signature,sig,bip340sig,
subtype,blinded_payinfo
Expand Down
Loading

0 comments on commit 2beb9c1

Please sign in to comment.