mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-01 17:47:30 +01:00
common/bech32: update to bech32m reference.
I did this by copying the updated bech32 code, and then re-patching in our minor changes: 1. Headers modded (we need size_t) 2. Explicit length for bech32_encode/decode (not 90). 3. Exposing and bech32_ prefix for convert_bits, charset, charset_rev. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
a4df2c7697
commit
4cc3eaf79c
6 changed files with 60 additions and 26 deletions
|
@ -1,7 +1,7 @@
|
||||||
/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.c,
|
/* 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 */
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
#include "bech32.h"
|
#include "bech32.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static uint32_t bech32_polymod_step(uint32_t pre) {
|
static uint32_t bech32_polymod_step(uint32_t pre) {
|
||||||
|
@ -35,7 +36,13 @@ static uint32_t bech32_polymod_step(uint32_t pre) {
|
||||||
(-((b >> 4) & 1) & 0x2a1462b3UL);
|
(-((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] = {
|
const int8_t bech32_charset_rev[128] = {
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||||
|
@ -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
|
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;
|
uint32_t chk = 1;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (hrp[i] != 0) {
|
while (hrp[i] != 0) {
|
||||||
|
@ -76,7 +83,7 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat
|
||||||
for (i = 0; i < 6; ++i) {
|
for (i = 0; i < 6; ++i) {
|
||||||
chk = bech32_polymod_step(chk);
|
chk = bech32_polymod_step(chk);
|
||||||
}
|
}
|
||||||
chk ^= 1;
|
chk ^= bech32_final_constant(enc);
|
||||||
for (i = 0; i < 6; ++i) {
|
for (i = 0; i < 6; ++i) {
|
||||||
*(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f];
|
*(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f];
|
||||||
}
|
}
|
||||||
|
@ -84,15 +91,14 @@ int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t dat
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input,
|
bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len) {
|
||||||
size_t max_input_len) {
|
|
||||||
uint32_t chk = 1;
|
uint32_t chk = 1;
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t input_len = strlen(input);
|
size_t input_len = strlen(input);
|
||||||
size_t hrp_len;
|
size_t hrp_len;
|
||||||
int have_lower = 0, have_upper = 0;
|
int have_lower = 0, have_upper = 0;
|
||||||
if (input_len < 8 || input_len > max_input_len) {
|
if (input_len < 8 || input_len > max_input_len) {
|
||||||
return 0;
|
return BECH32_ENCODING_NONE;
|
||||||
}
|
}
|
||||||
*data_len = 0;
|
*data_len = 0;
|
||||||
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
|
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
|
||||||
|
@ -100,13 +106,13 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input,
|
||||||
}
|
}
|
||||||
hrp_len = input_len - (1 + *data_len);
|
hrp_len = input_len - (1 + *data_len);
|
||||||
if (1 + *data_len >= input_len || *data_len < 6) {
|
if (1 + *data_len >= input_len || *data_len < 6) {
|
||||||
return 0;
|
return BECH32_ENCODING_NONE;
|
||||||
}
|
}
|
||||||
*(data_len) -= 6;
|
*(data_len) -= 6;
|
||||||
for (i = 0; i < hrp_len; ++i) {
|
for (i = 0; i < hrp_len; ++i) {
|
||||||
int ch = input[i];
|
int ch = input[i];
|
||||||
if (ch < 33 || ch > 126) {
|
if (ch < 33 || ch > 126) {
|
||||||
return 0;
|
return BECH32_ENCODING_NONE;
|
||||||
}
|
}
|
||||||
if (ch >= 'a' && ch <= 'z') {
|
if (ch >= 'a' && ch <= 'z') {
|
||||||
have_lower = 1;
|
have_lower = 1;
|
||||||
|
@ -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_lower = 1;
|
||||||
if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
|
if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
|
||||||
if (v == -1) {
|
if (v == -1) {
|
||||||
return 0;
|
return BECH32_ENCODING_NONE;
|
||||||
}
|
}
|
||||||
chk = bech32_polymod_step(chk) ^ v;
|
chk = bech32_polymod_step(chk) ^ v;
|
||||||
if (i + 6 < input_len) {
|
if (i + 6 < input_len) {
|
||||||
|
@ -137,9 +143,15 @@ int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input,
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
if (have_lower && have_upper) {
|
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) {
|
int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) {
|
||||||
|
@ -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) {
|
int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) {
|
||||||
uint8_t data[65];
|
uint8_t data[65];
|
||||||
size_t datalen = 0;
|
size_t datalen = 0;
|
||||||
|
bech32_encoding enc = BECH32_ENCODING_BECH32;
|
||||||
if (witver > 16) return 0;
|
if (witver > 16) return 0;
|
||||||
if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0;
|
if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0;
|
||||||
if (witprog_len < 2 || witprog_len > 40) return 0;
|
if (witprog_len < 2 || witprog_len > 40) return 0;
|
||||||
|
if (witver > 0) enc = BECH32_ENCODING_BECH32M;
|
||||||
data[0] = witver;
|
data[0] = witver;
|
||||||
bech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
|
bech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
|
||||||
++datalen;
|
++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) {
|
int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
|
||||||
uint8_t data[84];
|
uint8_t data[84];
|
||||||
char hrp_actual[84];
|
char hrp_actual[84];
|
||||||
size_t data_len;
|
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 (data_len == 0 || data_len > 65) return 0;
|
||||||
if (strncmp(hrp, hrp_actual, 84) != 0) return 0;
|
if (strncmp(hrp, hrp_actual, 84) != 0) return 0;
|
||||||
if (data[0] > 16) 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;
|
*witdata_len = 0;
|
||||||
if (!bech32_convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 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;
|
if (*witdata_len < 2 || *witdata_len > 40) return 0;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.h,
|
/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.h,
|
||||||
* with only the two ' > 90' checks hoisted */
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -69,7 +69,14 @@ int segwit_addr_decode(
|
||||||
const char* addr
|
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
|
* Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
|
||||||
* will be updated to contain the null-terminated Bech32 string.
|
* will be updated to contain the null-terminated Bech32 string.
|
||||||
|
@ -77,6 +84,7 @@ int segwit_addr_decode(
|
||||||
* data : Pointer to an array of 5-bit values.
|
* data : Pointer to an array of 5-bit values.
|
||||||
* data_len: Length of the data array.
|
* data_len: Length of the data array.
|
||||||
* max_input_len: Maximum valid length of input (90 for segwit usage).
|
* 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.
|
* Returns 1 if successful.
|
||||||
*/
|
*/
|
||||||
int bech32_encode(
|
int bech32_encode(
|
||||||
|
@ -84,10 +92,11 @@ int bech32_encode(
|
||||||
const char *hrp,
|
const char *hrp,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
size_t data_len,
|
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
|
* Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
|
||||||
* updated to contain the null-terminated human readable part.
|
* updated to contain the null-terminated human readable part.
|
||||||
|
@ -97,9 +106,11 @@ int bech32_encode(
|
||||||
* of entries in data.
|
* of entries in data.
|
||||||
* In: input: Pointer to a null-terminated Bech32 string.
|
* In: input: Pointer to a null-terminated Bech32 string.
|
||||||
* max_input_len: Maximum valid length of input (90 for segwit usage).
|
* 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,
|
char *hrp,
|
||||||
uint8_t *data,
|
uint8_t *data,
|
||||||
size_t *data_len,
|
size_t *data_len,
|
||||||
|
@ -120,3 +131,4 @@ extern const char bech32_charset[32];
|
||||||
extern const int8_t bech32_charset_rev[128];
|
extern const int8_t bech32_charset_rev[128];
|
||||||
|
|
||||||
#endif /* LIGHTNING_COMMON_BECH32_H */
|
#endif /* LIGHTNING_COMMON_BECH32_H */
|
||||||
|
|
||||||
|
|
|
@ -584,7 +584,8 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str,
|
||||||
hrp = tal_arr(tmpctx, char, strlen(str) - 6);
|
hrp = tal_arr(tmpctx, char, strlen(str) - 6);
|
||||||
data = tal_arr(tmpctx, u5, strlen(str) - 8);
|
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");
|
return decode_fail(b11, fail, "Bad bech32 string");
|
||||||
|
|
||||||
/* For signature checking at the end. */
|
/* For signature checking at the end. */
|
||||||
|
@ -1179,7 +1180,8 @@ char *bolt11_encode_(const tal_t *ctx,
|
||||||
bech32_push_bits(&data, sig_and_recid, sizeof(sig_and_recid) * CHAR_BIT);
|
bech32_push_bits(&data, sig_and_recid, sizeof(sig_and_recid) * CHAR_BIT);
|
||||||
|
|
||||||
output = tal_arr(ctx, char, strlen(hrp) + tal_count(data) + 8);
|
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);
|
output = tal_free(output);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|
|
@ -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);
|
const char **seednames = tal_arr(ctx, const char *, 0);
|
||||||
|
|
||||||
bech32_push_bits(&data, id->k, ARRAY_SIZE(id->k)*8);
|
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 */
|
/* This is cdecker's seed */
|
||||||
tal_arr_expand(&seednames, tal_fmt(seednames, "%s.lseed.bitcoinstats.com", bech32));
|
tal_arr_expand(&seednames, tal_fmt(seednames, "%s.lseed.bitcoinstats.com", bech32));
|
||||||
/* This is darosior's seed */
|
/* This is darosior's seed */
|
||||||
|
|
|
@ -15,15 +15,17 @@ void run(const uint8_t *data, size_t size)
|
||||||
uint8_t *data_out;
|
uint8_t *data_out;
|
||||||
size_t data_out_len;
|
size_t data_out_len;
|
||||||
int wit_version;
|
int wit_version;
|
||||||
|
bech32_encoding benc;
|
||||||
|
|
||||||
/* Buffer size is defined in each function's doc comment. */
|
/* Buffer size is defined in each function's doc comment. */
|
||||||
bech32_str = malloc(size + strlen(hrp_inv) + 8);
|
bech32_str = malloc(size + strlen(hrp_inv) + 8);
|
||||||
|
benc = data[0] ? BECH32_ENCODING_BECH32 : BECH32_ENCODING_BECH32M;
|
||||||
/* FIXME: needs a dictionary / a startup seed corpus to pass this more
|
/* FIXME: needs a dictionary / a startup seed corpus to pass this more
|
||||||
* frequently. */
|
* frequently. */
|
||||||
if (bech32_encode(bech32_str, hrp_inv, data, size, size) == 1) {
|
if (bech32_encode(bech32_str, hrp_inv, data+1, size-1, size-1, benc) == 1) {
|
||||||
hrp_out = malloc(strlen(bech32_str) - 6);
|
hrp_out = malloc(strlen(bech32_str) - 6);
|
||||||
data_out = malloc(strlen(bech32_str) - 8);
|
data_out = malloc(strlen(bech32_str) - 8);
|
||||||
bech32_decode(hrp_out, data_out, &data_out_len, bech32_str, size);
|
assert(bech32_decode(hrp_out, data_out, &data_out_len, bech32_str, size) == benc);
|
||||||
free(hrp_out);
|
free(hrp_out);
|
||||||
free(data_out);
|
free(data_out);
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,7 +363,7 @@ static int guess_to_remote(const char *address, struct node_id *node_id,
|
||||||
size_t witlen;
|
size_t witlen;
|
||||||
|
|
||||||
/* Get the hrp to accept addresses from any network. */
|
/* Get the hrp to accept addresses from any network. */
|
||||||
if (bech32_decode(hrp, goal_pubkeyhash, &witlen, address, 90) != 1)
|
if (bech32_decode(hrp, goal_pubkeyhash, &witlen, address, 90) != BECH32_ENCODING_BECH32)
|
||||||
errx(ERROR_USAGE, "Could not get address' network");
|
errx(ERROR_USAGE, "Could not get address' network");
|
||||||
if (segwit_addr_decode(&witver, goal_pubkeyhash, &witlen, hrp, address) != 1)
|
if (segwit_addr_decode(&witver, goal_pubkeyhash, &witlen, hrp, address) != 1)
|
||||||
errx(ERROR_USAGE, "Wrong bech32 address");
|
errx(ERROR_USAGE, "Wrong bech32 address");
|
||||||
|
|
Loading…
Add table
Reference in a new issue