From 419612c4bdfe5f9a952eae0806b67c77db034515 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Fri, 30 Oct 2020 12:27:22 +0100 Subject: [PATCH] common: add a descriptor checksum computation module This is stolen from William's clightning-dumpkeys (https://github.com/jb55/clightning-dumpkeys), itself adapted from https://github.com/bitcoin/bitcoin/blob/42b66a6b814bca130a9ccf0a3f747cf33d628232/src/script/descriptor.cpp#L25 Co-authored-by: William Casarin Signed-off-by: Antoine Poinsot --- common/Makefile | 1 + common/descriptor_checksum.c | 82 ++++++++++++++++++++++++++++++++++++ common/descriptor_checksum.h | 16 +++++++ 3 files changed, 99 insertions(+) create mode 100644 common/descriptor_checksum.c create mode 100644 common/descriptor_checksum.h diff --git a/common/Makefile b/common/Makefile index b6788be57..a3ad87d57 100644 --- a/common/Makefile +++ b/common/Makefile @@ -21,6 +21,7 @@ COMMON_SRC_NOGEN := \ common/daemon_conn.c \ common/decode_array.c \ common/derive_basepoints.c \ + common/descriptor_checksum.c \ common/dev_disconnect.c \ common/dijkstra.c \ common/ecdh_hsmd.c \ diff --git a/common/descriptor_checksum.c b/common/descriptor_checksum.c new file mode 100644 index 000000000..ed16b06ea --- /dev/null +++ b/common/descriptor_checksum.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include + + +static const char CHECKSUM_CHARSET[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + +static const char INPUT_CHARSET[] = + "0123456789()[],'/*abcdefgh@:$%{}" + "IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~" + "ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "; + +static inline int charset_find(char ch) { + for (size_t i = 0; i < sizeof(INPUT_CHARSET); i++) { + if (INPUT_CHARSET[i] == ch) + return i; + } + return -1; +} + +static u64 polymod(u64 c, int val) +{ + u8 c0 = c >> 35; + c = ((c & 0x7ffffffff) << 5) ^ val; + if (c0 & 1) c ^= 0xf5dee51989; + if (c0 & 2) c ^= 0xa9fdca3312; + if (c0 & 4) c ^= 0x1bab10e32d; + if (c0 & 8) c ^= 0x3706b1677a; + if (c0 & 16) c ^= 0x644d626ffd; + return c; +} + + +bool descriptor_checksum(const char *descriptor, int desc_size, + struct descriptor_checksum *checksum) +{ + checksum->csum[0] = 0; + + int j; + u64 c = 1; + int cls = 0; + int clscount = 0; + + for (int i = 0; i < desc_size; i++) { + char ch = descriptor[i]; + int pos = charset_find(ch); + if (pos == -1) { + checksum->csum[0] = 0; + return false; + } + /* Emit a symbol for the position inside the group, for every + * character. */ + c = polymod(c, pos & 31); + + /* Accumulate the group numbers */ + cls = cls * 3 + (pos >> 5); + + if (++clscount == 3) { + c = polymod(c, cls); + cls = 0; + clscount = 0; + } + } + + if (clscount > 0) + c = polymod(c, cls); + + /* Shift further to determine the checksum. */ + for (j = 0; j < DESCRIPTOR_CHECKSUM_LENGTH; ++j) + c = polymod(c, 0); + + /* Prevent appending zeroes from not affecting the checksum. */ + c ^= 1; + + for (j = 0; j < DESCRIPTOR_CHECKSUM_LENGTH; ++j) + checksum->csum[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31]; + + checksum->csum[DESCRIPTOR_CHECKSUM_LENGTH] = 0; + + return true; +} diff --git a/common/descriptor_checksum.h b/common/descriptor_checksum.h new file mode 100644 index 000000000..ed321cbde --- /dev/null +++ b/common/descriptor_checksum.h @@ -0,0 +1,16 @@ +#ifndef LIGHTNING_COMMON_DESCRIPTOR_CHECKSUM_H +#define LIGHTNING_COMMON_DESCRIPTOR_CHECKSUM_H +#include "config.h" +#include + +/* https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md#reference */ +#define DESCRIPTOR_CHECKSUM_LENGTH 8 + +struct descriptor_checksum { + char csum[DESCRIPTOR_CHECKSUM_LENGTH + 1]; +}; + +bool descriptor_checksum(const char *descriptor, int desc_size, + struct descriptor_checksum *checksum); + +#endif /* LIGHTNING_COMMON_DESCRIPTOR_CHECKSUM_H */