mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
common/bolt11: add secret support.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
81c89aaef8
commit
854c64ffee
@ -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]);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"));
|
||||
|
||||
|
@ -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++) {
|
||||
|
@ -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)) {
|
||||
|
@ -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…
Reference in New Issue
Block a user