nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

commit 4d783f1cbe1dbd9868acbb78cc876d698368d2c0
parent 958a8a84b5c4e6d1ab262c01ece70f2ca5f4db3b
Author: Rusty Russell <rusty@rustcorp.com.au>
Date:   Sun, 18 Aug 2024 11:28:48 +0930

bolt11: update to latest version from CLN

Copy the latest, which has parsing fixes.  We make a new explicit
"bolt11_decode_minimal" which doesn't check sigs, rather than neutering
the bolt11_decode logic.

As a bonus, this now correctly parses "LIGHTNING:BECH32..." format
(upper case, with prefix). 

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>


Diffstat:
Msrc/bolt11/bolt11.c | 693+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/bolt11/bolt11.h | 51++++-----------------------------------------------
Msrc/content_parser.c | 2+-
Mtest.c | 2+-
4 files changed, 402 insertions(+), 346 deletions(-)

diff --git a/src/bolt11/bolt11.c b/src/bolt11/bolt11.c @@ -28,6 +28,10 @@ #include <inttypes.h> #include <assert.h> +struct secret { + u8 data[32]; +}; + #define MSAT_PER_SAT ((u64)1000) #define SAT_PER_BTC ((u64)100000000) #define MSAT_PER_BTC (MSAT_PER_SAT * SAT_PER_BTC) @@ -55,10 +59,11 @@ static struct multiplier multipliers[] = { }; /* If pad is false, we discard any bits which don't fit in the last byte. - * Otherwise we add an extra byte */ -static bool pull_bits(struct hash_u5 *hu5, - u5 **data, size_t *data_len, void *dst, size_t nbits, - bool pad) + * Otherwise we add an extra byte. Returns error string or NULL on success. */ +static const char *pull_bits(struct hash_u5 *hu5, + const u5 **data, size_t *data_len, + void *dst, size_t nbits, + bool pad) { size_t n5 = nbits / 5; size_t len = 0; @@ -67,53 +72,67 @@ static bool pull_bits(struct hash_u5 *hu5, n5++; if (*data_len < n5) - return false; + return "truncated"; if (!bech32_convert_bits(dst, &len, 8, *data, n5, 5, pad)) - return false; + return "non-zero trailing bits"; if (hu5) hash_u5(hu5, *data, n5); *data += n5; *data_len -= n5; - return true; + return NULL; } -/* For pulling fields where we should have checked it will succeed already. */ -#ifndef NDEBUG -#define pull_bits_certain(hu5, data, data_len, dst, nbits, pad) \ - assert(pull_bits((hu5), (data), (data_len), (dst), (nbits), (pad))) -#else -#define pull_bits_certain pull_bits -#endif - /* Helper for pulling a variable-length big-endian int. */ -static bool pull_uint(struct hash_u5 *hu5, - u5 **data, size_t *data_len, - u64 *val, size_t databits) +static const char *pull_uint(struct hash_u5 *hu5, + const u5 **data, size_t *data_len, + u64 *val, size_t databits) { be64 be_val; + const char *err; /* Too big. */ if (databits > sizeof(be_val) * CHAR_BIT) - return false; - if (!pull_bits(hu5, data, data_len, &be_val, databits, true)) - return false; - *val = be64_to_cpu(be_val) >> (sizeof(be_val) * CHAR_BIT - databits); - return true; + return "integer too large"; + err = pull_bits(hu5, data, data_len, &be_val, databits, true); + if (err) + return err; + if (databits == 0) + *val = 0; + else + *val = be64_to_cpu(be_val) >> + (sizeof(be_val) * CHAR_BIT - databits); + return NULL; } -static size_t num_u8(size_t num_u5) +static void *pull_all(const tal_t *ctx, + struct hash_u5 *hu5, + const u5 **data, size_t *data_len, + bool pad, + const char **err) { - return (num_u5 * 5 + 4) / 8; + void *ret; + size_t retlen; + + if (pad) + retlen = (*data_len * 5 + 7) / 8; + else + retlen = (*data_len * 5) / 8; + + ret = tal_arr(ctx, u8, retlen); + *err = pull_bits(hu5, data, data_len, ret, *data_len * 5, pad); + if (*err) + return tal_free(ret); + return ret; } /* Frees bolt11, returns NULL. */ static struct bolt11 *decode_fail(struct bolt11 *b11, char **fail, - const char *fmt, ...) + const char *fmt, ...) PRINTF_FMT(3,4); static struct bolt11 *decode_fail(struct bolt11 *b11, char **fail, - const char *fmt, ...) + const char *fmt, ...) { va_list ap; @@ -127,20 +146,39 @@ static struct bolt11 *decode_fail(struct bolt11 *b11, char **fail, * These handle specific fields in the payment request; returning the problem * if any, or NULL. */ -static char *unknown_field(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - u5 type, size_t length) +static const char *unknown_field(struct bolt11 *b11, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + u5 type) { struct bolt11_field *extra = tal(b11, struct bolt11_field); - u8 u8data[num_u8(length)]; + const char *err; extra->tag = type; - extra->data = tal_dup_arr(extra, u5, *data, length, 0); + /* FIXME: record u8 data here, not u5! */ + extra->data = tal_dup_arr(extra, u5, *data, *field_len, 0); list_add_tail(&b11->extra_fields, &extra->list); - pull_bits_certain(hu5, data, data_len, u8data, length * 5, true); - return NULL; + tal_free(pull_all(extra, hu5, data, field_len, true, &err)); + return err; +} + +/* If field isn't expected length (in *bech32*!), call unknown_field. + * Otherwise copy into dst without padding, set have_flag if non-NULL. */ +static const char *pull_expected_length(struct bolt11 *b11, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + size_t expected_length, + u5 type, + bool *have_flag, + void *dst) +{ + if (*field_len != expected_length) + return unknown_field(b11, hu5, data, field_len, type); + + if (have_flag) + *have_flag = true; + return pull_bits(hu5, data, field_len, dst, *field_len * 5, false); } /* BOLT #11: @@ -148,34 +186,27 @@ static char *unknown_field(struct bolt11 *b11, * `p` (1): `data_length` 52. 256-bit SHA256 payment_hash. Preimage of this * provides proof of payment */ -static void decode_p(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, bool *have_p) +static const char *decode_p(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_p) { /* BOLT #11: * * A payer... SHOULD use the first `p` field that it did NOT * skip as the payment hash. */ - if (*have_p) { - unknown_field(b11, hu5, data, data_len, 'p', data_length); - return; - } + assert(!*have_p); /* BOLT #11: * * A reader... MUST skip over unknown fields, OR an `f` field * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do * NOT have `data_length`s of 52, 52, 52 or 53, respectively. - */ - if (data_length != 52) { - unknown_field(b11, hu5, data, data_len, 'p', data_length); - return; - } - - pull_bits_certain(hu5, data, data_len, &b11->payment_hash, 256, false); - *have_p = true; + */ + return pull_expected_length(b11, hu5, data, field_len, 52, 'p', + have_p, &b11->payment_hash); } /* Check for valid UTF-8 */ @@ -213,23 +244,24 @@ static char *utf8_str(const tal_t *ctx, const u8 *buf TAKES, size_t buflen) return ret; } - /* BOLT #11: * * `d` (13): `data_length` variable. Short description of purpose of payment * (UTF-8), e.g. '1 cup of coffee' or 'ナンセンス 1杯' */ -static char *decode_d(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, bool *have_d) +static const char *decode_d(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_d) { u8 *desc; - if (*have_d) - return unknown_field(b11, hu5, data, data_len, 'd', data_length); + const char *err; - desc = tal_arr(NULL, u8, data_length * 5 / 8); - pull_bits_certain(hu5, data, data_len, desc, data_length*5, false); + assert(!*have_d); + desc = pull_all(NULL, hu5, data, field_len, false, &err); + if (!desc) + return err; *have_d = true; b11->description = utf8_str(b11, take(desc), tal_bytelen(desc)); @@ -246,30 +278,28 @@ static char *decode_d(struct bolt11 *b11, * 639 bytes, but the transport mechanism for the description in that case is * transport specific and not defined here. */ -static void decode_h(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, bool *have_h) +static const char *decode_h(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_h) { - if (*have_h) { - unknown_field(b11, hu5, data, data_len, 'h', data_length); - return; - } + const char *err; + struct sha256 hash; + assert(!*have_h); /* BOLT #11: * * A reader... MUST skip over unknown fields, OR an `f` field * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do * NOT have `data_length`s of 52, 52, 52 or 53, respectively. */ - if (data_length != 52) { - unknown_field(b11, hu5, data, data_len, 'h', data_length); - return; - } + err = pull_expected_length(b11, hu5, data, field_len, 52, 'h', + have_h, &hash); - b11->description_hash = tal(b11, struct sha256); - pull_bits_certain(hu5, data, data_len, b11->description_hash, 256, - false); - *have_h = true; + /* If that gave us the hash, store it */ + if (*have_h) + b11->description_hash = tal_dup(b11, struct sha256, &hash); + return err; } /* BOLT #11: @@ -278,19 +308,20 @@ static void decode_h(struct bolt11 *b11, * (big-endian). Default is 3600 (1 hour) if not specified. */ #define DEFAULT_X 3600 -static char *decode_x(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, bool *have_x) +static const char *decode_x(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_x) { - if (*have_x) - return unknown_field(b11, hu5, data, data_len, 'x', - data_length); + const char *err; + + assert(!*have_x); /* FIXME: Put upper limit in bolt 11 */ - if (!pull_uint(hu5, data, data_len, &b11->expiry, data_length * 5)) - return tal_fmt(b11, "x: length %zu chars is excessive", - *data_len); + err = pull_uint(hu5, data, field_len, &b11->expiry, *field_len * 5); + if (err) + return tal_fmt(b11, "x: %s", err); *have_x = true; return NULL; @@ -298,24 +329,25 @@ static char *decode_x(struct bolt11 *b11, /* BOLT #11: * - * `c` (24): `data_length` variable. `min_final_cltv_expiry` to use for the + * `c` (24): `data_length` variable. `min_final_cltv_expiry_delta` to use for the * last HTLC in the route. Default is 18 if not specified. */ -static char *decode_c(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, bool *have_c) +static const char *decode_c(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_c) { u64 c; - if (*have_c) - return unknown_field(b11, hu5, data, data_len, 'c', - data_length); + const char *err; + + assert(!*have_c); /* FIXME: Put upper limit in bolt 11 */ - if (!pull_uint(hu5, data, data_len, &c, data_length * 5)) - return tal_fmt(b11, "c: length %zu chars is excessive", - *data_len); - b11->min_final_cltv_expiry = (u32)c; + err = pull_uint(hu5, data, field_len, &c, *field_len * 5); + if (err) + return tal_fmt(b11, "c: %s", err); + b11->min_final_cltv_expiry = c; /* Can overflow, since c is 64 bits but value must be < 32 bits */ if (b11->min_final_cltv_expiry != c) return tal_fmt(b11, "c: %"PRIu64" is too large", c); @@ -324,33 +356,95 @@ static char *decode_c(struct bolt11 *b11, return NULL; } -static char *decode_n(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, bool *have_n) +static const char *decode_n(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_n) { - if (*have_n) - return unknown_field(b11, hu5, data, data_len, 'n', - data_length); + const char *err; + assert(!*have_n); /* BOLT #11: * * A reader... MUST skip over unknown fields, OR an `f` field * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do * NOT have `data_length`s of 52, 52, 52 or 53, respectively. */ - if (data_length != 53) - return unknown_field(b11, hu5, data, data_len, 'n', - data_length); - - pull_bits_certain(hu5, data, data_len, &b11->receiver_id.k, - data_length * 5, false); - /* - if (!node_id_valid(&b11->receiver_id)) - return tal_fmt(b11, "n: invalid pubkey %s", - node_id_to_hexstr(b11, &b11->receiver_id)); - */ + err = pull_expected_length(b11, hu5, data, field_len, 53, 'n', have_n, + &b11->receiver_id.k); + + return err; +} + +/* BOLT #11: + * + * * `s` (16): `data_length` 52. This 256-bit secret prevents + * forwarding nodes from probing the payment recipient. + */ +static const char *decode_s(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_s) +{ + const char *err; + struct secret secret; + + assert(!*have_s); + + /* BOLT #11: + * + * A reader... MUST skip over unknown fields, OR an `f` field + * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do + * NOT have `data_length`s of 52, 52, 52 or 53, respectively. */ + err = pull_expected_length(b11, hu5, data, field_len, 52, 's', + have_s, &secret); + if (*have_s) + b11->payment_secret = tal_dup(b11, struct secret, &secret); + return err; +} + +static void shift_bitmap_down(u8 *bitmap, size_t bits) +{ + u8 prev = 0; + assert(bits < CHAR_BIT); + + for (size_t i = 0; i < tal_bytelen(bitmap); i++) { + /* Save top bits for next one */ + u8 v = bitmap[i]; + bitmap[i] = (prev | (v >> bits)); + prev = (v << (8 - bits)); + } + assert(prev == 0); +} - *have_n = true; +/* BOLT #11: + * + * `9` (5): `data_length` variable. One or more 5-bit values containing features + * supported or required for receiving this payment. + * See [Feature Bits](#feature-bits). + */ +static const char *decode_9(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_9) +{ + size_t flen = (*field_len * 5 + 7) / 8; + size_t databits = *field_len * 5; + const char *err; + + assert(!*have_9); + + b11->features = pull_all(b11, hu5, data, field_len, true, &err); + if (!b11->features) + return err; + + /* pull_bits pads with zero bits: we need to remove them. */ + shift_bitmap_down(b11->features, + flen * 8 - databits); + + *have_9 = true; return NULL; } @@ -361,80 +455,162 @@ static char *decode_n(struct bolt11 *b11, * maximum hop payload size. Long metadata fields reduce the maximum * route length. */ -static char *decode_m(struct bolt11 *b11, - struct hash_u5 *hu5, - u5 **data, size_t *data_len, - size_t data_length, - bool *have_m) +static const char *decode_m(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_m) { - size_t mlen = (data_length * 5) / 8; + const char *err; - if (*have_m) - return unknown_field(b11, hu5, data, data_len, 'm', - data_length); + assert(!*have_m); - b11->metadata = tal_arr(b11, u8, mlen); - pull_bits_certain(hu5, data, data_len, b11->metadata, - data_length * 5, false); + b11->metadata = pull_all(b11, hu5, data, field_len, false, &err); + if (!b11->metadata) + return err; *have_m = true; return NULL; } -struct bolt11 *new_bolt11(const tal_t *ctx) +static struct bolt11 *new_bolt11(const tal_t *ctx, + const struct amount_msat *msat TAKES) { struct bolt11 *b11 = tal(ctx, struct bolt11); list_head_init(&b11->extra_fields); b11->description = NULL; b11->description_hash = NULL; - b11->fallbacks = NULL; b11->msat = NULL; b11->expiry = DEFAULT_X; b11->features = tal_arr(b11, u8, 0); /* BOLT #11: - * - if the `c` field (`min_final_cltv_expiry`) is not provided: + * - if the `c` field (`min_final_cltv_expiry_delta`) is not provided: * - MUST use an expiry delta of at least 18 when making the payment */ b11->min_final_cltv_expiry = 18; - //b11->payment_secret = NULL; + b11->payment_secret = NULL; b11->metadata = NULL; - //if (msat) - //b11->msat = tal_dup(b11, struct amount_msat, msat); + if (msat) + b11->msat = tal_dup(b11, struct amount_msat, msat); return b11; } -/* Define sha256_eq. */ -//STRUCTEQ_DEF(sha256, 0, u); +struct decoder { + /* What BOLT11 letter this is */ + const char letter; + /* If false, then any dups get treated as "unknown" fields */ + bool allow_duplicates; + /* Routine to decode: returns NULL if it decodes ok, and + * sets *have_field = true if it is not an unknown form. + * Otherwise returns error string (literal or tal off b11). */ + const char *(*decode)(struct bolt11 *b11, + const struct feature_set *our_features, + struct hash_u5 *hu5, + const u5 **data, size_t *field_len, + bool *have_field); +}; -/* Extracts signature but does not check it. */ -struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, char **fail) +static const struct decoder decoders[] = { + /* BOLT #11: + * + * A payer... SHOULD use the first `p` field that it did NOT + * skip as the payment hash. + */ + { 'p', false, decode_p }, + { 'd', false, decode_d }, + { 'h', false, decode_h }, + { 'x', false, decode_x }, + { 'c', false, decode_c }, + { 'n', false, decode_n }, + { 's', false, decode_s }, + { '9', false, decode_9 }, + { 'm', false, decode_m }, +}; + +static const struct decoder *find_decoder(char c) { - char *hrp, *amountstr, *prefix; - u5 *data; - size_t data_len; - struct bolt11 *b11 = new_bolt11(ctx); - struct hash_u5 hu5; - bool have_p = false, have_d = false, have_h = false, have_n = false, - have_x = false, have_c = false, have_m = false; + for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { + if (decoders[i].letter == c) + return decoders + i; + } + return NULL; +} + +static bool bech32_decode_alloc(const tal_t *ctx, + const char **hrp_ret, + const u5 **data_ret, + size_t *data_len, + const char *str) +{ + char *hrp = tal_arr(ctx, char, strlen(str) - 6); + u5 *data = tal_arr(ctx, u5, strlen(str) - 8); + + if (bech32_decode(hrp, data, data_len, str, (size_t)-1) + != BECH32_ENCODING_BECH32) { + tal_free(hrp); + tal_free(data); + return false; + } + /* We needed temporaries because these are const */ + *hrp_ret = hrp; + *data_ret = data; + return true; +} + +static bool has_lightning_prefix(const char *invstring) +{ /* BOLT #11: * * If a URI scheme is desired, the current recommendation is to either - * use 'lightning:' as a prefix before the BOLT-11 encoding - */ - if (strstarts(str, "lightning:") || strstarts(str, "LIGHTNING:")) - str += strlen("lightning:"); + * use 'lightning:' as a prefix before the BOLT-11 encoding */ + return (strstarts(invstring, "lightning:") || + strstarts(invstring, "LIGHTNING:")); +} + +static char *str_lowering(const void *ctx, const char *string TAKES) +{ + char *ret; + + ret = tal_strdup(ctx, string); + for (char *p = ret; *p; p++) *p = tolower(*p); + return ret; +} + +static const char *to_canonical_invstr(const tal_t *ctx, + const char *invstring) +{ + if (has_lightning_prefix(invstring)) + invstring += strlen("lightning:"); + return str_lowering(ctx, invstring); +} + +/* Extracts signature but does not check it. */ +static struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, + const struct feature_set *our_features, + struct sha256 *hash, + const u5 **sig, + bool *have_n, + char **fail) +{ + const char *hrp, *prefix; + char *amountstr; + const u5 *data; + size_t data_len; + struct bolt11 *b11 = new_bolt11(ctx, NULL); + struct hash_u5 hu5; + const char *err; + /* We don't need all of these, but in theory we could have 32 types */ + bool have_field[32]; + + memset(have_field, 0, sizeof(have_field)); if (strlen(str) < 8) return decode_fail(b11, fail, "Bad bech32 string"); - hrp = tal_arr(b11, char, strlen(str) - 6); - data = tal_arr(b11, u5, strlen(str) - 8); - - if (bech32_decode(hrp, data, &data_len, str, (size_t)-1) - != BECH32_ENCODING_BECH32) + if (!bech32_decode_alloc(b11, &hrp, &data, &data_len, str)) return decode_fail(b11, fail, "Bad bech32 string"); /* For signature checking at the end. */ @@ -447,7 +623,7 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, * `lntb` for Bitcoin testnet, `lntbs` for Bitcoin signet, and `lnbcrt` for Bitcoin regtest) * 1. `amount`: optional number in that currency, followed by an optional * `multiplier` letter. The unit encoded here is the 'social' convention of a payment unit -- in the case of Bitcoin the unit is 'bitcoin' NOT satoshis. - */ + */ prefix = tal_strndup(b11, hrp, strcspn(hrp, "0123456789")); /* BOLT #11: @@ -456,7 +632,7 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, */ if (!strstarts(prefix, "ln")) return decode_fail(b11, fail, - "Prefix '%s' does not start with ln", prefix); + "Prefix '%s' does not start with ln", prefix); /* BOLT #11: * @@ -493,17 +669,17 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, amount = strtoull(amountstr, &end, 10); if (amount == ULLONG_MAX && errno == ERANGE) return decode_fail(b11, fail, - "Invalid amount '%s'", amountstr); + "Invalid amount '%s'", amountstr); if (!*amountstr || *end) return decode_fail(b11, fail, - "Invalid amount postfix '%s'", end); + "Invalid amount postfix '%s'", end); /* BOLT #11: * * if the `multiplier` is present... MUST multiply * `amount` by the `multiplier` value to derive the * amount required for payment. - */ + */ b11->msat = tal(b11, struct amount_msat); /* BOLT #11: * @@ -513,8 +689,8 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, */ if (amount * m10 % 10 != 0) return decode_fail(b11, fail, - "Invalid sub-millisatoshi amount" - " '%sp'", amountstr); + "Invalid sub-millisatoshi amount" + " '%sp'", amountstr); *b11->msat = amount_msat(amount * m10 / 10); } @@ -527,12 +703,16 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, * 1. zero or more tagged parts * 1. `signature`: Bitcoin-style signature of above (520 bits) */ - if (!pull_uint(&hu5, &data, &data_len, &b11->timestamp, 35)) - return decode_fail(b11, fail, "Can't get 35-bit timestamp"); + err = pull_uint(&hu5, &data, &data_len, &b11->timestamp, 35); + if (err) + return decode_fail(b11, fail, + "Can't get 35-bit timestamp: %s", err); while (data_len > 520 / 5) { const char *problem = NULL; - u64 type, data_length; + u64 type, field_len64; + size_t field_len; + const struct decoder *decoder; /* BOLT #11: * @@ -542,153 +722,72 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, * 1. `data_length` (10 bits, big-endian) * 1. `data` (`data_length` x 5 bits) */ - if (!pull_uint(&hu5, &data, &data_len, &type, 5) - || !pull_uint(&hu5, &data, &data_len, &data_length, 10)) + err = pull_uint(&hu5, &data, &data_len, &type, 5); + if (err) return decode_fail(b11, fail, - "Can't get tag and length"); + "Can't get tag: %s", err); + err = pull_uint(&hu5, &data, &data_len, &field_len64, 10); + if (err) + return decode_fail(b11, fail, + "Can't get length: %s", err); /* Can't exceed total data remaining. */ - if (data_length > data_len) + if (field_len64 > data_len) return decode_fail(b11, fail, "%c: truncated", - bech32_charset[type]); - - switch (bech32_charset[type]) { - case 'p': - decode_p(b11, &hu5, &data, &data_len, data_length, - &have_p); - break; - - case 'd': - problem = decode_d(b11, &hu5, &data, &data_len, - data_length, &have_d); - break; - - case 'h': - decode_h(b11, &hu5, &data, &data_len, data_length, - &have_h); - break; - - case 'n': - problem = decode_n(b11, &hu5, &data, - &data_len, data_length, - &have_n); - break; - - case 'x': - problem = decode_x(b11, &hu5, &data, - &data_len, data_length, - &have_x); - break; - - case 'c': - problem = decode_c(b11, &hu5, &data, - &data_len, data_length, - &have_c); - break; - - /* - case 'f': - problem = decode_f(b11, &hu5, &data, - &data_len, data_length); - break; - case 'r': - problem = decode_r(b11, &hu5, &data, &data_len, - data_length); - break; - case '9': - problem = decode_9(b11, our_features, &hu5, - &data, &data_len, - data_length); - break; - case 's': - problem = decode_s(b11, &hu5, &data, &data_len, - data_length, &have_s); - break; - */ - case 'm': - problem = decode_m(b11, &hu5, &data, &data_len, - data_length, &have_m); - break; - default: - unknown_field(b11, &hu5, &data, &data_len, - bech32_charset[type], data_length); + bech32_charset[type]); + + /* These are different types on 32 bit! But since data_len is + * also size_t, above check ensures this will fit. */ + field_len = field_len64; + assert(field_len == field_len64); + + /* Do this now: the decode function fixes up the data ptr */ + data_len -= field_len; + + decoder = find_decoder(bech32_charset[type]); + if (!decoder || (have_field[type] && !decoder->allow_duplicates)) { + problem = unknown_field(b11, &hu5, &data, &field_len, + bech32_charset[type]); + } else { + problem = decoder->decode(b11, our_features, &hu5, + &data, &field_len, &have_field[type]); } if (problem) return decode_fail(b11, fail, "%s", problem); + if (field_len) + return decode_fail(b11, fail, "%c: extra %zu bytes", + bech32_charset[type], field_len); } - if (!have_p) + if (!have_field[bech32_charset_rev['p']]) return decode_fail(b11, fail, "No valid 'p' field found"); - *sig = tal_dup_arr(ctx, u5, data, data_len, 0); - return b11; -} - -/* Decodes and checks signature; returns NULL on error. */ -struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, char **fail) -{ - u5 *sigdata; - size_t data_len; - u8 sig_and_recid[65]; - //secp256k1_ecdsa_recoverable_signature sig; - struct bolt11 *b11; - - b11 = bolt11_decode_nosig(ctx, str, &sigdata, fail); - if (!b11) - return NULL; - /* 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 include either exactly one `d` or exactly one `h` field. */ - data_len = tal_count(sigdata); - if (!pull_bits(NULL, &sigdata, &data_len, sig_and_recid, 520, false)) - return decode_fail(b11, fail, "signature truncated"); - - assert(data_len == 0); + /* FIXME: It doesn't actually say the reader must check though! */ + if (!have_field[bech32_charset_rev['d']] + && !have_field[bech32_charset_rev['h']]) + return decode_fail(b11, fail, + "must have either 'd' or 'h' field"); - /* - if (!secp256k1_ecdsa_recoverable_signature_parse_compact - (secp256k1_ctx, &sig, sig_and_recid, sig_and_recid[64])) - return decode_fail(b11, fail, "signature invalid"); + hash_u5_done(&hu5, hash); + *sig = tal_dup_arr(ctx, u5, data, data_len, 0); - secp256k1_ecdsa_recoverable_signature_convert(secp256k1_ctx, - &b11->sig, &sig); - */ + *have_n = have_field[bech32_charset_rev['n']]; + return b11; +} - /* BOLT #11: - * - * A reader... MUST check that the `signature` is valid (see - * the `n` tagged field specified below). ... A reader... - * MUST use the `n` field to validate the signature instead of - * performing signature recovery. - */ - /* - if (!have_n) { - struct pubkey k; - if (!secp256k1_ecdsa_recover(secp256k1_ctx, - &k.pubkey, - &sig, - (const u8 *)&hash)) - return decode_fail(b11, fail, - "signature recovery failed"); - node_id_from_pubkey(&b11->receiver_id, &k); - } else { - struct pubkey k; - if (!pubkey_from_node_id(&k, &b11->receiver_id)) - abort(); - if (!secp256k1_ecdsa_verify(secp256k1_ctx, &b11->sig, - (const u8 *)&hash, - &k.pubkey)) - return decode_fail(b11, fail, "invalid signature"); - } - */ +struct bolt11 *bolt11_decode_minimal(const tal_t *ctx, const char *str, + char **fail) +{ + const u5 *sigdata; + struct sha256 hash; + bool have_n; - return b11; + str = to_canonical_invstr(ctx, str); + return bolt11_decode_nosig(ctx, str, NULL, &hash, &sigdata, &have_n, + fail); } diff --git a/src/bolt11/bolt11.h b/src/bolt11/bolt11.h @@ -1,5 +1,6 @@ #ifndef LIGHTNING_COMMON_BOLT11_H #define LIGHTNING_COMMON_BOLT11_H +/* Borrowed from CLN's common/bolt11.[ch] implementation as of v24.08rc1 */ #include "ccan/short_types/short_types.h" #include "hash_u5.h" @@ -28,25 +29,7 @@ struct bolt11_field { u5 *data; }; -/* BOLT #11: - * * `pubkey` (264 bits) - * * `short_channel_id` (64 bits) - * * `fee_base_msat` (32 bits, big-endian) - * * `fee_proportional_millionths` (32 bits, big-endian) - * * `cltv_expiry_delta` (16 bits, big-endian) - */ - -/* -struct route_info { - struct node_id pubkey; - u16 cltv_expiry_delta; - struct short_channel_id short_channel_id; - u32 fee_base_msat, fee_proportional_millionths; -}; - */ - struct bolt11 { - const struct chainparams *chain; u64 timestamp; struct amount_msat *msat; /* NULL if not specified. */ @@ -63,17 +46,7 @@ struct bolt11 { /* How many blocks final hop requires. */ u32 min_final_cltv_expiry; - /* If non-NULL, indicates fallback addresses to pay to. */ - const u8 **fallbacks; - - /* If non-NULL: array of route arrays */ - //struct route_info **routes; - - /* signature of sha256 of entire thing. */ - //secp256k1_ecdsa_signature sig; - - /* payment secret, if any. */ - //struct secret *payment_secret; + struct secret *payment_secret; /* Features bitmap, if any. */ u8 *features; @@ -84,23 +57,7 @@ struct bolt11 { struct list_head extra_fields; }; -/* Decodes and checks signature; returns NULL on error; description is - * (optional) out-of-band description of payment, for `h` field. - * fset is NULL to accept any features (usually not desirable!). - * - * if @must_be_chain is not NULL, fails unless it's this chain. - */ -struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, char **fail); - -/* Extracts signature but does not check it. */ -struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sigdata, char **fail); - -/* Initialize an empty bolt11 struct with optional amount */ -struct bolt11 *new_bolt11(const tal_t *ctx); - -#if DEVELOPER -/* Flag for tests to suppress `min_final_cltv_expiry` field generation, to match test vectors */ -extern bool dev_bolt11_no_c_generation; -#endif +/* Does not check signature, nor extract node. */ +struct bolt11 *bolt11_decode_minimal(const tal_t *ctx, const char *str, char **fail); #endif /* LIGHTNING_COMMON_BOLT11_H */ diff --git a/src/content_parser.c b/src/content_parser.c @@ -168,7 +168,7 @@ static int push_invoice_str(struct ndb_content_parser *p, struct ndb_str_block * struct bolt11 *bolt11; char *fail; - if (!(bolt11 = bolt11_decode(NULL, str->str, &fail))) + if (!(bolt11 = bolt11_decode_minimal(NULL, str->str, &fail))) return 0; start = p->buffer.p; diff --git a/test.c b/test.c @@ -172,7 +172,7 @@ static void test_invoice_encoding(const char *bolt11_str) struct ndb_invoice invoice; struct bolt11 *bolt11; - bolt11 = bolt11_decode(NULL, bolt11_str, &fail); + bolt11 = bolt11_decode_minimal(NULL, bolt11_str, &fail); make_cursor(buf, buf + sizeof(buf), &cur); assert(fail == NULL);