What changed, and why it matters
This commit only updates comments, documentation strings, and the order of wire protocol definitions to match a newer version of the Lightning specification (BOLTs). No actual program logic, checks, or behavior were changed. It is not a security fix.
No security action needed; treat as routine spec-alignment/documentation cleanup.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is entirely cosmetic/spec-sync: BOLT version bump in Makefile; comment rewording in common/bolt11.c, common/sphinx.c, hsmd/libhsmd.c, and contrib/pyln-proto/pyln/proto/invoice.py; and reordering of closing_signed/closing_complete entries in wire/peer_wire.csv and wire/extracted_peer-shutdown-wrong_funding.patch. No executable code, validation logic, or wire format handling was modified.
Changed components
Makefile (BOLT version reference)common/bolt11.c (comments only)common/sphinx.c (comments only)contrib/pyln-proto/pyln/proto/invoice.py (comments only)hsmd/libhsmd.c (comments only)wire/extracted_peer-shutdown-wrong_funding.patch (reordered definitions)wire/peer_wire.csv (reordered definitions)Inspect captured patch +38 / −40
diff --git a/Makefile b/Makefile
index e9a6942e..f8e586e5 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ CCANDIR := ccan
# Where we keep the BOLT RFCs
BOLTDIR := ../bolts/
-DEFAULT_BOLTVERSION := 4fe3f0b6056638b46dd3e5317947ebc2491758e8
+DEFAULT_BOLTVERSION := bdf790bfdc10c2e894be3546efdc80a60d93da8c
# Can be overridden on cmdline.
BOLTVERSION := $(DEFAULT_BOLTVERSION)
diff --git a/common/bolt11.c b/common/bolt11.c
index bd15e3af..26263dd0 100644
--- a/common/bolt11.c
+++ b/common/bolt11.c
@@ -185,7 +185,7 @@ static const char *decode_p(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
- * - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
+ * - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53).
*/
return pull_expected_length(b11, hu5, data, field_len, 52, 'p',
@@ -239,7 +239,7 @@ static const char *decode_h(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
- * - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
+ * - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53). */
err = pull_expected_length(b11, hu5, data, field_len, 52, 'h',
have_h, &hash);
@@ -324,7 +324,7 @@ static const char *decode_n(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
- * - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
+ * - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53). */
err = pull_expected_length(b11, hu5, data, field_len, 53, 'n', have_n,
&b11->receiver_id.k);
@@ -360,7 +360,7 @@ static const char *decode_s(struct bolt11 *b11,
/* BOLT #11:
*
* A reader...
- * - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`)
+ * - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
* does not have the correct length (52, 52, 52, 53). */
err = pull_expected_length(b11, hu5, data, field_len, 52, 's',
have_s, &secret);
@@ -876,7 +876,8 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str,
*
* 1. `timestamp`: seconds-since-1970 (35 bits, big-endian)
* 1. zero or more tagged parts
- * 1. `signature`: Bitcoin-style signature of above (520 bits)
+ * 1. `signature`: compact ECDSA/secp256k1 signature of the above
+ * (520 bits: 64-byte R||S + 1-byte recovery id)
*/
err = pull_uint(&hu5, &data, &data_len, &b11->timestamp, 35, false);
if (err)
@@ -999,13 +1000,12 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
/* BOLT #11:
*
- * A writer...MUST set `signature` to a valid 512-bit
- * secp256k1 signature of the SHA2 256-bit hash of the
- * human-readable part, represented as UTF-8 bytes,
- * concatenated with the data part (excluding the signature)
- * with 0 bits appended to pad the data to the next byte
- * boundary, with a trailing byte containing the recovery ID
- * (0, 1, 2, or 3).
+ * A writer...MUST set `signature` to a valid
+ * compact ECDSA signature over secp256k1 of the SHA-256 hash of:
+ * the human-readable part (as UTF-8 bytes) concatenated with the data part
+ * (excluding the signature), with 0 bits appended to pad to a byte boundary.
+ * The signature is encoded as 64 bytes (R || S), followed by a trailing 1-byte
+ * recovery id in {0,1,2,3}.
*/
data_len = tal_count(sigdata);
err = pull_bits(NULL, &sigdata, &data_len, sig_and_recid, 520, false);
@@ -1036,7 +1036,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
* A reader:
* ...
* - if a valid `n` field is provided:
- * - MUST use the `n` field to validate the signature instead of performing signature recovery.
+ * - MUST use the `n` field to validate the signature instead of performing public-key recovery.
*/
if (!have_n) {
struct pubkey k;
@@ -1319,7 +1319,8 @@ char *bolt11_encode_(const tal_t *ctx,
*
* 1. `timestamp`: seconds-since-1970 (35 bits, big-endian)
* 1. zero or more tagged parts
- * 1. `signature`: Bitcoin-style signature of above (520 bits)
+ * 1. `signature`: compact ECDSA/secp256k1 signature of the above
+ * (520 bits: 64-byte R||S + 1-byte recovery id)
*/
push_varlen_uint(&data, b11->timestamp, 35);
diff --git a/common/sphinx.c b/common/sphinx.c
index 6761c79f..7adea816 100644
--- a/common/sphinx.c
+++ b/common/sphinx.c
@@ -768,9 +768,8 @@ struct onionreply *create_onionreply(const tal_t *ctx,
/* BOLT #4:
*
- * The node generating the error message (_erring node_) builds a return
- * packet consisting of
- * the following fields:
+ * The node generating the error message builds a _return
+ * packet_ consisting of the following fields:
*
* 1. data:
* * [`32*byte`:`hmac`]
@@ -816,8 +815,6 @@ struct onionreply *wrap_onionreply(const tal_t *ctx,
* The erring node then generates a new key, using the key type `ammag`.
* This key is then used to generate a pseudo-random stream, which is
* in turn applied to the packet using `XOR`.
- *
- * The obfuscation step is repeated by every hop along the return path.
*/
subkey_from_hmac("ammag", shared_secret, &key);
result->contents = tal_dup_talarr(result, u8, reply->contents);
diff --git a/contrib/pyln-proto/pyln/proto/invoice.py b/contrib/pyln-proto/pyln/proto/invoice.py
index 27591cb0..9a53f871 100755
--- a/contrib/pyln-proto/pyln/proto/invoice.py
+++ b/contrib/pyln-proto/pyln/proto/invoice.py
@@ -329,7 +329,8 @@ class Invoice(object):
# BOLT #11:
# A reader:
# - MUST skip over `f` fields that use an unknown `version`.
- # - MUST fail the payment if any mandatory field (`p`, `h`, `s`, `n`) does not have the correct length (52, 52, 52, 53).
+ # - MUST fail the payment if any field with fixed `data_length` (`p`, `h`, `s`, `n`)
+ # does not have the correct length (52, 52, 52, 53).
data_length = len(tagdata) / 5
if tag == 'r':
@@ -392,7 +393,7 @@ class Invoice(object):
# BOLT #11:
# A reader:...
# - if a valid `n` field is provided:
- # - MUST use the `n` field to validate the signature instead of performing signature recovery.
+ # - MUST use the `n` field to validate the signature instead of performing public-key recovery.
inv.signature = inv.pubkey.ecdsa_deserialize_compact(sigdecoded[0:64])
if not inv.pubkey.ecdsa_verify(bytearray([ord(c) for c in hrp]) + data.tobytes(), inv.signature):
raise ValueError('Invalid signature')
diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c
index f8d35a04..c605198a 100644
--- a/hsmd/libhsmd.c
+++ b/hsmd/libhsmd.c
@@ -1016,13 +1016,12 @@ static u8 *handle_sign_invoice(struct hsmd_client *c, const u8 *msg_in)
/* BOLT #11:
*
- * A writer... MUST set `signature` to a valid 512-bit
- * secp256k1 signature of the SHA2 256-bit hash of the
- * human-readable part, represented as UTF-8 bytes,
- * concatenated with the data part (excluding the signature)
- * with 0 bits appended to pad the data to the next byte
- * boundary, with a trailing byte containing the recovery ID
- * (0, 1, 2, or 3).
+ * A writer... MUST set `signature` to a valid compact ECDSA signature
+ * over secp256k1 of the SHA-256 hash of: the human-readable part (as
+ * UTF-8 bytes) concatenated with the data part (excluding the
+ * signature), with 0 bits appended to pad to a byte boundary. The
+ * signature is encoded as 64 bytes (R || S), followed by a trailing
+ * 1-byte recovery id in {0,1,2,3}.
*/
/* FIXME: Check invoice! */
diff --git a/wire/extracted_peer-shutdown-wrong_funding.patch b/wire/extracted_peer-shutdown-wrong_funding.patch
index 11438023..ec8f5239 100644
--- a/wire/extracted_peer-shutdown-wrong_funding.patch
+++ b/wire/extracted_peer-shutdown-wrong_funding.patch
@@ -8,6 +8,6 @@
+tlvtype,shutdown_tlvs,wrong_funding,100
+tlvdata,shutdown_tlvs,wrong_funding,txid,sha256,
+tlvdata,shutdown_tlvs,wrong_funding,outnum,u32,
- msgtype,closing_signed,39
- msgdata,closing_signed,channel_id,channel_id,
- msgdata,closing_signed,fee_satoshis,u64,
+ msgtype,closing_complete,40
+ msgdata,closing_complete,channel_id,channel_id,
+ msgdata,closing_complete,closer_scriptpubkey_len,u16,
diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv
index 4b01c568..1dad37d9 100644
--- a/wire/peer_wire.csv
+++ b/wire/peer_wire.csv
@@ -241,14 +241,6 @@ msgdata,shutdown,tlvs,shutdown_tlvs,
tlvtype,shutdown_tlvs,wrong_funding,100
tlvdata,shutdown_tlvs,wrong_funding,txid,sha256,
tlvdata,shutdown_tlvs,wrong_funding,outnum,u32,
-msgtype,closing_signed,39
-msgdata,closing_signed,channel_id,channel_id,
-msgdata,closing_signed,fee_satoshis,u64,
-msgdata,closing_signed,signature,signature,
-msgdata,closing_signed,tlvs,closing_signed_tlvs,
-tlvtype,closing_signed_tlvs,fee_range,1
-tlvdata,closing_signed_tlvs,fee_range,min_fee_satoshis,u64,
-tlvdata,closing_signed_tlvs,fee_range,max_fee_satoshis,u64,
msgtype,closing_complete,40
msgdata,closing_complete,channel_id,channel_id,
msgdata,closing_complete,closer_scriptpubkey_len,u16,
@@ -273,6 +265,14 @@ tlvtype,closing_tlvs,closee_output_only,2
tlvdata,closing_tlvs,closee_output_only,sig,signature,
tlvtype,closing_tlvs,closer_and_closee_outputs,3
tlvdata,closing_tlvs,closer_and_closee_outputs,sig,signature,
+msgtype,closing_signed,39
+msgdata,closing_signed,channel_id,channel_id,
+msgdata,closing_signed,fee_satoshis,u64,
+msgdata,closing_signed,signature,signature,
+msgdata,closing_signed,tlvs,closing_signed_tlvs,
+tlvtype,closing_signed_tlvs,fee_range,1
+tlvdata,closing_signed_tlvs,fee_range,min_fee_satoshis,u64,
+tlvdata,closing_signed_tlvs,fee_range,max_fee_satoshis,u64,
msgtype,update_add_htlc,128
msgdata,update_add_htlc,channel_id,channel_id,
msgdata,update_add_htlc,id,u64,
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.