Browse Source

common/bolt11: add secret support.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
travis-debug
Rusty Russell 5 years ago
parent
commit
854c64ffee
  1. 46
      common/bolt11.c
  2. 3
      common/bolt11.h
  3. 39
      common/test/run-bolt11.c
  4. 5
      devtools/bolt11-cli.c
  5. 3
      lightningd/invoice.c
  6. 5
      lightningd/test/run-invoice-select-inchan.c

46
common/bolt11.c

@ -302,6 +302,37 @@ static char *decode_n(struct bolt11 *b11,
return NULL;
}
/* BOLT-e36f7b6517e1173dcbd49da3b516cfe1f48ae556 #11:
*
* * `s` (16): `data_length` 52. This 256-bit secret prevents
* forwarding nodes from probing the payment recipient.
*/
static char *decode_s(struct bolt11 *b11,
struct hash_u5 *hu5,
u5 **data, size_t *data_len,
size_t data_length,
bool *have_s)
{
if (*have_s)
return unknown_field(b11, hu5, data, data_len, 's',
data_length);
/* BOLT-e36f7b6517e1173dcbd49da3b516cfe1f48ae556 #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)
return unknown_field(b11, hu5, data, data_len, 's',
data_length);
b11->payment_secret = tal(b11, struct secret);
pull_bits_certain(hu5, data, data_len, b11->payment_secret, 256,
false);
*have_s = true;
return NULL;
}
/* BOLT #11:
*
* `f` (9): `data_length` variable, depending on version. Fallback
@ -500,6 +531,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx,
b11->expiry = DEFAULT_X;
b11->features = tal_arr(b11, u8, 0);
b11->min_final_cltv_expiry = DEFAULT_C;
b11->payment_secret = NULL;
if (msat)
b11->msat = tal_dup(b11, struct amount_msat, msat);
@ -519,7 +551,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
struct hash_u5 hu5;
struct sha256 hash;
bool have_p = false, have_n = false, have_d = false, have_h = false,
have_x = false, have_c = false;
have_x = false, have_c = false, have_s = false;
b11->routes = tal_arr(b11, struct route_info *, 0);
@ -694,6 +726,10 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str,
problem = decode_9(b11, &hu5, &data, &data_len,
data_length);
break;
case 's':
problem = decode_s(b11, &hu5, &data, &data_len,
data_length, &have_s);
break;
default:
unknown_field(b11, &hu5, &data, &data_len,
bech32_charset[type], data_length);
@ -874,6 +910,11 @@ static void encode_c(u5 **data, u16 min_final_cltv_expiry)
push_varlen_field(data, 'c', min_final_cltv_expiry);
}
static void encode_s(u5 **data, const struct secret *payment_secret)
{
push_field(data, 's', payment_secret, 256);
}
static void encode_f(u5 **data, const u8 *fallback)
{
struct bitcoin_address pkh;
@ -1040,6 +1081,9 @@ char *bolt11_encode_(const tal_t *ctx,
if (b11->min_final_cltv_expiry != DEFAULT_C)
encode_c(&data, b11->min_final_cltv_expiry);
if (b11->payment_secret)
encode_s(&data, b11->payment_secret);
for (size_t i = 0; i < tal_count(b11->fallbacks); i++)
encode_f(&data, b11->fallbacks[i]);

3
common/bolt11.h

@ -64,6 +64,9 @@ struct bolt11 {
/* signature of sha256 of entire thing. */
secp256k1_ecdsa_signature sig;
/* payment secret, if any. */
struct secret *payment_secret;
/* Features bitmap, if any. */
u8 *features;

39
common/test/run-bolt11.c

@ -100,6 +100,12 @@ static void test_b11(const char *b11str,
else
assert(streq(b11->description, expect_b11->description));
if (!b11->payment_secret)
assert(!expect_b11->payment_secret);
else
assert(memeq(b11->payment_secret, sizeof(*b11->payment_secret),
expect_b11->payment_secret,
sizeof(*expect_b11->payment_secret)));
assert(memeq(b11->features, tal_bytelen(b11->features),
expect_b11->features, tal_bytelen(expect_b11->features)));
assert(b11->expiry == expect_b11->expiry);
@ -312,10 +318,10 @@ int main(void)
test_b11("lntb30m1pw2f2yspp5s59w4a0kjecw3zyexm7zur8l8n4scw674w8sftjhwec33km882gsdpa2pshjmt9de6zqun9w96k2um5ypmkjargypkh2mr5d9cxzun5ypeh2ursdae8gxqruyqvzddp68gup69uhnzwfj9cejuvf3xshrwde68qcrswf0d46kcarfwpshyaplw3skw0tdw4k8g6tsv9e8g4a3hx0v945csrmpm7yxyaamgt2xu7mu4xyt3vp7045n4k4czxf9kj0vw0m8dr5t3pjxuek04rtgyy8uzss5eet5gcyekd6m7u0mzv5sp7mdsag", b11, NULL);
/* BOLT-a76d61dc9893eec75b2e9c4a361354c356c46894 #11:
/* BOLT-d8d45ed403e54cffdb049d2e44d1100e41df013c #11:
*
* > ### Please send $30 for coffee beans to the same peer, which supports features 1 and 9
* > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9qzsze992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq73t7cl
* > ### Please send $30 for coffee beans to the same peer, which supports features 15 and 99, using secret 0x1111111111111111111111111111111111111111111111111111111111111111
* > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sqdkcy8h
*
* Breakdown:
*
@ -327,11 +333,14 @@ int main(void)
* * `d`: short description
* * `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20)
* * `vdhkven9v5sxyetpdees`: 'coffee beans'
* * `s`: payment secret
* * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52)
* * `zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs`: 0x1111111111111111111111111111111111111111111111111111111111111111
* * `9`: features
* * `qz`: `data_length` (`q` = 0, `z` = 2; 0 * 32 + 2 == 2)
* * `sz`: b1000000010
* * `e992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq`: signature
* * `73t7cl`: Bech32 checksum
* * `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20) 4
* * `sqqqqqqqqqqqqqqqpqqq`: b1000....00001000000000000000
* * `pqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sq`: signature
* * `dkcy8h`: Bech32 checksum
*/
msatoshi = AMOUNT_MSAT(25 * (1000ULL * 100000000) / 1000);
b11 = new_bolt11(tmpctx, &msatoshi);
@ -343,20 +352,22 @@ int main(void)
abort();
b11->receiver_id = node;
b11->description = "coffee beans";
set_feature_bit(&b11->features, 1);
set_feature_bit(&b11->features, 9);
b11->payment_secret = tal(b11, struct secret);
memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret));
set_feature_bit(&b11->features, 15);
set_feature_bit(&b11->features, 99);
test_b11("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9qzsze992adudgku8p05pstl6zh7av6rx2f297pv89gu5q93a0hf3g7lynl3xq56t23dpvah6u7y9qey9lccrdml3gaqwc6nxsl5ktzm464sq73t7cl", b11, NULL);
test_b11("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sqdkcy8h", b11, NULL);
/* BOLT-a76d61dc9893eec75b2e9c4a361354c356c46894 #11:
/* BOLT-d8d45ed403e54cffdb049d2e44d1100e41df013c #11:
*
* > # Same, but using invalid unknown feature 100
* > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7
* > # Same, but adding invalid unknown feature 100
* > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqqqqu7fz6pjqczdm3jp3qps7xntj2w2mm70e0ckhw3c5xk9p36pvk3sewn7ncaex6uzfq0vtqzy28se6pcwn790vxex7xystzumhg55p6qq9wq7td
*/
/* This one can be encoded, but not decoded */
set_feature_bit(&b11->features, 100);
badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL);
assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdees9q4pqqqqqqqqqqqqqqqqqqszk3ed62snp73037h4py4gry05eltlp0uezm2w9ajnerhmxzhzhsu40g9mgyx5v3ad4aqwkmvyftzk4k9zenz90mhjcy9hcevc7r3lx2sphzfxz7"));
assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqqqqu7fz6pjqczdm3jp3qps7xntj2w2mm70e0ckhw3c5xk9p36pvk3sewn7ncaex6uzfq0vtqzy28se6pcwn790vxex7xystzumhg55p6qq9wq7td"));
assert(!bolt11_decode(tmpctx, badstr, NULL, &fail));
assert(streq(fail, "9: unknown feature bit 100"));

5
devtools/bolt11-cli.c

@ -1,6 +1,7 @@
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/chainparams.h>
#include <bitcoin/privkey.h>
#include <bitcoin/script.h>
#include <ccan/err/err.h>
#include <ccan/opt/opt.h>
@ -117,6 +118,10 @@ int main(int argc, char *argv[])
printf("description_hash: %s\n",
tal_hexstr(ctx, b11->description_hash,
sizeof(*b11->description_hash)));
if (b11->payment_secret)
printf("payment_secret: %s\n",
tal_hexstr(ctx, b11->payment_secret,
sizeof(*b11->payment_secret)));
if (tal_bytelen(b11->features)) {
printf("features:");
for (size_t i = 0; i < tal_bytelen(b11->features) * CHAR_BIT; i++) {

3
lightningd/invoice.c

@ -1084,6 +1084,9 @@ static struct command_result *json_decodepay(struct command *cmd,
b11->description_hash);
json_add_num(response, "min_final_cltv_expiry",
b11->min_final_cltv_expiry);
if (b11->payment_secret)
json_add_secret(response, "payment_secret",
b11->payment_secret);
if (b11->features)
json_add_hex_talarr(response, "features", b11->features);
if (tal_count(b11->fallbacks)) {

5
lightningd/test/run-invoice-select-inchan.c

@ -188,6 +188,11 @@ void json_add_node_id(struct json_stream *response UNNEEDED,
void json_add_num(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
unsigned int value UNNEEDED)
{ fprintf(stderr, "json_add_num called!\n"); abort(); }
/* Generated stub for json_add_secret */
void json_add_secret(struct json_stream *response UNNEEDED,
const char *fieldname UNNEEDED,
const struct secret *secret UNNEEDED)
{ fprintf(stderr, "json_add_secret called!\n"); abort(); }
/* Generated stub for json_add_sha256 */
void json_add_sha256(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
const struct sha256 *hash UNNEEDED)

Loading…
Cancel
Save