Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bech32m support! #4591

Merged
merged 6 commits into from
Jun 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ else
endif
endif

pytest: $(ALL_PROGRAMS)
pytest: $(ALL_PROGRAMS) $(ALL_TEST_PROGRAMS)
ifeq ($(PYTEST),)
@echo "py.test is required to run the integration tests, please install using 'pip3 install -r requirements.txt', and rerun 'configure'."
exit 1
Expand Down
45 changes: 31 additions & 14 deletions common/bech32.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.c,
* with only the two ' > 90' checks hoisted, and more internals exposed */

/* Copyright (c) 2017 Pieter Wuille
/* Copyright (c) 2017, 2021 Pieter Wuille
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand All @@ -23,6 +23,7 @@
*/
#include "bech32.h"

#include <assert.h>
#include <string.h>

static uint32_t bech32_polymod_step(uint32_t pre) {
Expand All @@ -35,7 +36,13 @@ static uint32_t bech32_polymod_step(uint32_t pre) {
(-((b >> 4) & 1) & 0x2a1462b3UL);
}

const char bech32_charset[32] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
static uint32_t bech32_final_constant(bech32_encoding enc) {
if (enc == BECH32_ENCODING_BECH32) return 1;
if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3;
assert(0);
}

const char bech32_charset[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";

const int8_t bech32_charset_rev[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
Expand All @@ -48,7 +55,7 @@ const int8_t bech32_charset_rev[128] = {
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};

int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len) {
int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len, bech32_encoding enc) {
uint32_t chk = 1;
size_t i = 0;
while (hrp[i] != 0) {
Expand Down Expand Up @@ -76,37 +83,36 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat
for (i = 0; i < 6; ++i) {
chk = bech32_polymod_step(chk);
}
chk ^= 1;
chk ^= bech32_final_constant(enc);
for (i = 0; i < 6; ++i) {
*(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f];
}
*output = 0;
return 1;
}

int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input,
size_t max_input_len) {
bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len) {
uint32_t chk = 1;
size_t i;
size_t input_len = strlen(input);
size_t hrp_len;
int have_lower = 0, have_upper = 0;
if (input_len < 8 || input_len > max_input_len) {
return 0;
return BECH32_ENCODING_NONE;
}
*data_len = 0;
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
++(*data_len);
}
hrp_len = input_len - (1 + *data_len);
if (1 + *data_len >= input_len || *data_len < 6) {
return 0;
return BECH32_ENCODING_NONE;
}
*(data_len) -= 6;
for (i = 0; i < hrp_len; ++i) {
int ch = input[i];
if (ch < 33 || ch > 126) {
return 0;
return BECH32_ENCODING_NONE;
}
if (ch >= 'a' && ch <= 'z') {
have_lower = 1;
Expand All @@ -128,7 +134,7 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input,
if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
if (v == -1) {
return 0;
return BECH32_ENCODING_NONE;
}
chk = bech32_polymod_step(chk) ^ v;
if (i + 6 < input_len) {
Expand All @@ -137,9 +143,15 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input,
++i;
}
if (have_lower && have_upper) {
return 0;
return BECH32_ENCODING_NONE;
}
if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) {
return BECH32_ENCODING_BECH32;
} else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) {
return BECH32_ENCODING_BECH32M;
} else {
return BECH32_ENCODING_NONE;
}
return chk == 1;
}

int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) {
Expand Down Expand Up @@ -167,23 +179,28 @@ int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t
int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) {
uint8_t data[65];
size_t datalen = 0;
bech32_encoding enc = BECH32_ENCODING_BECH32;
if (witver > 16) return 0;
if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0;
if (witprog_len < 2 || witprog_len > 40) return 0;
if (witver > 0) enc = BECH32_ENCODING_BECH32M;
data[0] = witver;
bech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
++datalen;
return bech32_encode(output, hrp, data, datalen, 90);
return bech32_encode(output, hrp, data, datalen, 90, enc);
}

int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
uint8_t data[84];
char hrp_actual[84];
size_t data_len;
if (!bech32_decode(hrp_actual, data, &data_len, addr, 90)) return 0;
bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr, 90);
if (enc == BECH32_ENCODING_NONE) return 0;
if (data_len == 0 || data_len > 65) return 0;
if (strncmp(hrp, hrp_actual, 84) != 0) return 0;
if (data[0] > 16) return 0;
if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0;
if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0;
*witdata_len = 0;
if (!bech32_convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0;
if (*witdata_len < 2 || *witdata_len > 40) return 0;
Expand Down
24 changes: 18 additions & 6 deletions common/bech32.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.h,
* with only the two ' > 90' checks hoisted */

/* Copyright (c) 2017 Pieter Wuille
/* Copyright (c) 2017, 2021 Pieter Wuille
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -69,25 +69,34 @@ int segwit_addr_decode(
const char* addr
);

/** Encode a Bech32 string
/** Supported encodings. */
typedef enum {
BECH32_ENCODING_NONE,
BECH32_ENCODING_BECH32,
BECH32_ENCODING_BECH32M
} bech32_encoding;

/** Encode a Bech32 or Bech32m string
*
* Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
* will be updated to contain the null-terminated Bech32 string.
* In: hrp : Pointer to the null-terminated human readable part.
* data : Pointer to an array of 5-bit values.
* data_len: Length of the data array.
* max_input_len: Maximum valid length of input (90 for segwit usage).
* enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}).
* Returns 1 if successful.
*/
int bech32_encode(
char *output,
const char *hrp,
const uint8_t *data,
size_t data_len,
size_t max_input_len
size_t max_input_len,
bech32_encoding enc
);

/** Decode a Bech32 string
/** Decode a Bech32 or Bech32m string
*
* Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
* updated to contain the null-terminated human readable part.
Expand All @@ -97,9 +106,11 @@ int bech32_encode(
* of entries in data.
* In: input: Pointer to a null-terminated Bech32 string.
* max_input_len: Maximum valid length of input (90 for segwit usage).
* Returns 1 if successful.
* Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful
* with the specified encoding standard. BECH32_ENCODING_NONE is returned if
* decoding failed.
*/
int bech32_decode(
bech32_encoding bech32_decode(
char *hrp,
uint8_t *data,
size_t *data_len,
Expand All @@ -120,3 +131,4 @@ extern const char bech32_charset[32];
extern const int8_t bech32_charset_rev[128];

#endif /* LIGHTNING_COMMON_BECH32_H */

6 changes: 4 additions & 2 deletions common/bolt11.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str,
hrp = tal_arr(tmpctx, char, strlen(str) - 6);
data = tal_arr(tmpctx, u5, strlen(str) - 8);

if (!bech32_decode(hrp, data, &data_len, str, (size_t)-1))
if (bech32_decode(hrp, data, &data_len, str, (size_t)-1)
!= BECH32_ENCODING_BECH32)
return decode_fail(b11, fail, "Bad bech32 string");

/* For signature checking at the end. */
Expand Down Expand Up @@ -1179,7 +1180,8 @@ char *bolt11_encode_(const tal_t *ctx,
bech32_push_bits(&data, sig_and_recid, sizeof(sig_and_recid) * CHAR_BIT);

output = tal_arr(ctx, char, strlen(hrp) + tal_count(data) + 8);
if (!bech32_encode(output, hrp, data, tal_count(data), (size_t)-1))
if (!bech32_encode(output, hrp, data, tal_count(data), (size_t)-1,
BECH32_ENCODING_BECH32))
output = tal_free(output);

return output;
Expand Down
13 changes: 7 additions & 6 deletions common/json_tok.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,14 +433,15 @@ json_to_address_scriptpubkey(const tal_t *ctx,

bip173 = segwit_addr_net_decode(&witness_version, witness_program,
&witness_program_len, addrz, chainparams);

if (bip173) {
bool witness_ok = false;
if (witness_version == 0 && (witness_program_len == 20 ||
witness_program_len == 32)) {
bool witness_ok;

/* We know the rules for v0, rest remain undefined */
if (witness_version == 0) {
witness_ok = (witness_program_len == 20 ||
witness_program_len == 32);
} else
witness_ok = true;
}
/* Insert other witness versions here. */

if (witness_ok) {
*scriptpubkey = scriptpubkey_witness_raw(ctx, witness_version,
Expand Down
3 changes: 2 additions & 1 deletion connectd/connectd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,7 +1412,8 @@ static const char **seednames(const tal_t *ctx, const struct node_id *id)
const char **seednames = tal_arr(ctx, const char *, 0);

bech32_push_bits(&data, id->k, ARRAY_SIZE(id->k)*8);
bech32_encode(bech32, "ln", data, tal_count(data), sizeof(bech32));
bech32_encode(bech32, "ln", data, tal_count(data), sizeof(bech32),
BECH32_ENCODING_BECH32);
/* This is cdecker's seed */
tal_arr_expand(&seednames, tal_fmt(seednames, "%s.lseed.bitcoinstats.com", bech32));
/* This is darosior's seed */
Expand Down
4 changes: 3 additions & 1 deletion devtools/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding devtools/mkclose devtools/mkgossip devtools/mkencoded devtools/mkquery devtools/lightning-checkmessage devtools/topology devtools/route devtools/blindedpath devtools/bolt12-cli
DEVTOOLS := devtools/bolt11-cli devtools/decodemsg devtools/onion devtools/dump-gossipstore devtools/gossipwith devtools/create-gossipstore devtools/mkcommit devtools/mkfunding devtools/mkclose devtools/mkgossip devtools/mkencoded devtools/mkquery devtools/lightning-checkmessage devtools/topology devtools/route devtools/blindedpath devtools/bolt12-cli devtools/encodeaddr
ifeq ($(HAVE_SQLITE3),1)
DEVTOOLS += devtools/checkchannels
endif
Expand Down Expand Up @@ -46,6 +46,8 @@ DEVTOOLS_COMMON_OBJS := \

devtools/bolt11-cli: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/bolt11-cli.o

devtools/encodeaddr: common/utils.o common/bech32.o devtools/encodeaddr.o

devtools/bolt12-cli: $(DEVTOOLS_COMMON_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/bolt12$(EXP)_wiregen.o wire/fromwire.o wire/towire.o common/bolt12.o common/bolt12_merkle.o devtools/bolt12-cli.o common/setup.o common/iso4217.o

devtools/decodemsg: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) $(WIRE_PRINT_OBJS) wire/fromwire.o wire/towire.o devtools/print_wire.o devtools/decodemsg.o
Expand Down
42 changes: 42 additions & 0 deletions devtools/encodeaddr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "config.h"
#include <assert.h>
#include <ccan/short_types/short_types.h>
#include <common/bech32.h>
#include <common/utils.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

static void test_enc(const char *hrp, const char *hex)
{
u8 *val;
bool ok;
u8 ver;
char *out;

val = tal_hexdata(NULL, hex, strlen(hex));
assert(val);
out = tal_arr(NULL, char, 73 + strlen(hrp));
/* First byte is version */
ver = (val[0] == 0 ? 0 : val[0] - 0x50);
/* Second byte is OP_PUSH */
assert(val[1] == tal_bytelen(val) - 2);
ok = segwit_addr_encode(out, hrp, ver, val+2, tal_bytelen(val)-2);
assert(ok);
printf("%s\n", out);
}

int main(int argc, char *argv[])
{
const char *hrp = argv[1];

setup_locale();
test_enc(hrp ?: "bc", "0014751e76e8199196d454941c45d1b3a323f1433bd6");
test_enc(hrp ?: "tb", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262");
test_enc(hrp ?: "bc", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6");
test_enc(hrp ?: "bc", "6002751e");
test_enc(hrp ?: "bc", "5210751e76e8199196d454941c45d1b3a323");
test_enc(hrp ?: "tb", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433");
test_enc(hrp ?: "tb", "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433");
test_enc(hrp ?: "bc", "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798");
}
7 changes: 5 additions & 2 deletions doc/lightning-close.7

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion doc/lightning-close.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ indefinitely until the peer is online and can negotiate a mutual close.
The default is 2 days (172800 seconds).

The *destination* can be of any Bitcoin accepted type, including bech32.
If it isn't specified, the default is a c-lightning wallet address.
If it isn't specified, the default is a c-lightning wallet address. If
the peer hasn't offered the `option_shutdown_anysegwit` feature, then
taproot addresses (or other v1+ segwit) are not allowed. Tell your
friends to upgrade!

The *fee_negotiation_step* parameter controls how closing fee
negotiation is performed assuming the peer proposes a fee that is
Expand Down
2 changes: 1 addition & 1 deletion lightningd/channel_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg)
channel_fail_permanent(channel,
REASON_PROTOCOL,
"Bad shutdown scriptpubkey %s",
tal_hex(channel, scriptpubkey));
tal_hex(tmpctx, scriptpubkey));
return;
}

Expand Down
Loading