clightning-dumpkeys

dump clightning output descriptors
git clone git://jb55.com/clightning-dumpkeys
Log | Files | Refs | README | LICENSE

clightning-dumpkeys.c (6611B)


      1 
      2 #include "short_types.h"
      3 #include "hkdf.h"
      4 #include "compiler.h"
      5 #include "secp256k1.h"
      6 #include "bip32.h"
      7 #include "hash.h"
      8 #include "base58.h"
      9 #include "descriptor.h"
     10 
     11 #include <stdio.h>
     12 #include <unistd.h>
     13 #include <sys/types.h>
     14 #include <fcntl.h>
     15 #include <errno.h>
     16 #include <assert.h>
     17 
     18 #define BIP32_ENTROPY_LEN_256 32
     19 
     20 #define fatal(fmt, ...) do { fprintf(stderr, fmt "\n", __VA_ARGS__); exit(1); } while (0)
     21 #define fatal1(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0)
     22 
     23 /* General 256-bit secret, which must be private.  Used in various places. */
     24 struct secret {
     25 	u8 data[32];
     26 };
     27 
     28 static struct {
     29 	struct secret hsm_secret;
     30 	struct ext_key master;
     31 	struct ext_key parent_ext;
     32 	struct ext_key child_ext;
     33 } secretstuff;
     34 
     35 
     36 struct bip32_key_version {
     37 	u32 bip32_pubkey_version;
     38 	u32 bip32_privkey_version;
     39 };
     40 
     41 
     42 
     43 /* Version codes for BIP32 extended keys in libwally-core.
     44  * It's not suitable to add this struct into client struct,
     45  * so set it static.*/
     46 static struct  bip32_key_version  bip32_key_version;
     47 
     48 bool read_all(int fd, void *data, size_t size)
     49 {
     50 	while (size) {
     51 		ssize_t done;
     52 
     53 		done = read(fd, data, size);
     54 		if (done < 0 && errno == EINTR)
     55 			continue;
     56 		if (done <= 0)
     57 			return false;
     58 		data = (char *)data + done;
     59 		size -= done;
     60 	}
     61 
     62 	return true;
     63 }
     64 
     65 
     66 
     67 static void populate_secretstuff(void)
     68 {
     69 	u8 bip32_seed[BIP32_ENTROPY_LEN_256];
     70 	u32 salt = 0;
     71 	/* struct ext_key master_extkey, child_extkey; */
     72 	const u32 flags = SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN;
     73 	secp256k1_context *ctx = secp256k1_context_create(flags);
     74 
     75 	bip32_key_version = (struct bip32_key_version) {
     76 		.bip32_pubkey_version = BIP32_VER_MAIN_PUBLIC,
     77 		.bip32_privkey_version = BIP32_VER_MAIN_PRIVATE
     78 	};
     79 
     80 	assert(bip32_key_version.bip32_pubkey_version == BIP32_VER_MAIN_PUBLIC
     81 			|| bip32_key_version.bip32_pubkey_version == BIP32_VER_TEST_PUBLIC);
     82 
     83 	assert(bip32_key_version.bip32_privkey_version == BIP32_VER_MAIN_PRIVATE
     84 			|| bip32_key_version.bip32_privkey_version == BIP32_VER_TEST_PRIVATE);
     85 
     86 	/* Fill in the BIP32 tree for bitcoin addresses. */
     87 	/* In libwally-core, the version BIP32_VER_TEST_PRIVATE is for testnet/regtest,
     88 	 * and BIP32_VER_MAIN_PRIVATE is for mainnet. For litecoin, we also set it like
     89 	 * bitcoin else.*/
     90 	do {
     91 		hkdf_sha256(bip32_seed, sizeof(bip32_seed),
     92 			    &salt, sizeof(salt),
     93 			    &secretstuff.hsm_secret,
     94 			    sizeof(secretstuff.hsm_secret),
     95 			    "bip32 seed", strlen("bip32 seed"));
     96 		salt++;
     97 	} while (bip32_key_from_seed(ctx, bip32_seed, sizeof(bip32_seed),
     98 				     bip32_key_version.bip32_privkey_version,
     99 				     0, &secretstuff.master) != WALLY_OK);
    100 
    101 	/* BIP 32:
    102 	 *
    103 	 * The default wallet layout
    104 	 *
    105 	 * An HDW is organized as several 'accounts'. Accounts are numbered,
    106 	 * the default account ("") being number 0. Clients are not required
    107 	 * to support more than one account - if not, they only use the
    108 	 * default account.
    109 	 *
    110 	 * Each account is composed of two keypair chains: an internal and an
    111 	 * external one. The external keychain is used to generate new public
    112 	 * addresses, while the internal keychain is used for all other
    113 	 * operations (change addresses, generation addresses, ..., anything
    114 	 * that doesn't need to be communicated). Clients that do not support
    115 	 * separate keychains for these should use the external one for
    116 	 * everything.
    117 	 *
    118 	 *  - m/iH/0/k corresponds to the k'th keypair of the external chain of
    119 	 * account number i of the HDW derived from master m.
    120 	 */
    121 	/* Hence child 0, then child 0 again to get extkey to derive from. */
    122 	if (bip32_key_from_parent(ctx, &secretstuff.master, 0,
    123 				  BIP32_FLAG_KEY_PRIVATE,
    124 				  &secretstuff.child_ext) != WALLY_OK)
    125 		/*~ status_failed() is a helper which exits and sends lightningd
    126 		 * a message about what happened.  For hsmd, that's fatal to
    127 		 * lightningd. */
    128 		fatal1("Can't derive child bip32 key");
    129 
    130 	if (bip32_key_from_parent(ctx, &secretstuff.child_ext, 0,
    131 				  BIP32_FLAG_KEY_PRIVATE,
    132 				  &secretstuff.parent_ext) != WALLY_OK)
    133 		fatal1("Can't derive private bip32 key");
    134 }
    135 
    136 static void load_hsm(const char *secretfile)
    137 {
    138 	int fd = open(secretfile ? secretfile : "hsm_secret", O_RDONLY);
    139 	if (fd < 0)
    140 		fatal("opening: %s", strerror(errno));
    141 	if (!read_all(fd, &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret)))
    142 		fatal("reading: %s", strerror(errno));
    143 	close(fd);
    144 
    145 	populate_secretstuff();
    146 }
    147 
    148 static int wally_free_string(char *str)
    149 {
    150 	if (!str)
    151 		return WALLY_EINVAL;
    152 	wally_clear(str, strlen(str));
    153 	free(str);
    154 	return WALLY_OK;
    155 }
    156 
    157 static inline size_t hex_str_size(size_t bytes)
    158 {
    159 	return 2 * bytes + 1;
    160 }
    161 
    162 
    163 static char hexchar(unsigned int val)
    164 {
    165 	if (val < 10)
    166 		return '0' + val;
    167 	if (val < 16)
    168 		return 'a' + val - 10;
    169 	abort();
    170 }
    171 
    172 UNUSED static bool hex_encode(const void *buf, size_t bufsize, char *dest,
    173 		       size_t destsize)
    174 {
    175 	size_t i;
    176 
    177 	if (destsize < hex_str_size(bufsize))
    178 		return false;
    179 
    180 	for (i = 0; i < bufsize; i++) {
    181 		unsigned int c = ((const unsigned char *)buf)[i];
    182 		*(dest++) = hexchar(c >> 4);
    183 		*(dest++) = hexchar(c & 0xF);
    184 	}
    185 	*dest = '\0';
    186 
    187 	return true;
    188 }
    189 
    190 static void print_key(struct ext_key *key, const char *name, int key_type,
    191 		      const char *key_type_name) {
    192 	static u8 buf[128];
    193 	static char cbuf[512];
    194 	static char cbuf2[512];
    195 	char *out;
    196 
    197 	int ret = bip32_key_serialize(key, key_type, buf, BIP32_SERIALIZED_LEN);
    198 
    199 	assert(ret == WALLY_OK);
    200 
    201 	wally_base58_from_bytes(buf, BIP32_SERIALIZED_LEN,
    202 				BASE58_FLAG_CHECKSUM, &out);
    203 
    204 	printf("%s\t%s %s\n", out, name, key_type_name);
    205 
    206 	if (!streq(name, "root")) {
    207 		snprintf(cbuf, sizeof(cbuf), "combo(%s/*)", out);
    208 		descriptor_checksum(cbuf, strlen(cbuf), cbuf2, sizeof(cbuf2));
    209 
    210 		printf("%s#%s\t%s %s descriptor\n", cbuf, cbuf2, name, key_type_name);
    211 	}
    212 	wally_free_string(out);
    213 
    214 }
    215 
    216 static void dump_bip32(struct ext_key *key, const char *name) {
    217 	print_key(key, name, BIP32_FLAG_KEY_PRIVATE, "private");
    218 	print_key(key, name, BIP32_FLAG_KEY_PUBLIC, "public");
    219 }
    220 
    221 static int dump_xpriv(const char *secretfile) {
    222 
    223 	bip32_key_version = (struct bip32_key_version)
    224 		{   .bip32_pubkey_version  = BIP32_VER_MAIN_PUBLIC
    225 		  , .bip32_privkey_version = BIP32_VER_MAIN_PRIVATE
    226 		};
    227 
    228 
    229 	load_hsm(secretfile);
    230 
    231 	dump_bip32(&secretstuff.master, "root");
    232 	printf("\n");
    233 	dump_bip32(&secretstuff.parent_ext, "extended");
    234 	/* printf("\n"); */
    235 	/* dump_bip32(&secretstuff.child_ext, "extended internal"); */
    236 
    237 
    238 	return 0;
    239 }
    240 
    241 void usage()
    242 {
    243 	fprintf(stderr, "usage: clightning-dumpkeys <hsmd_secretfile>\n");
    244 	exit(42);
    245 }
    246 
    247 int main(int argc, char *argv[])
    248 {
    249 	if (argc != 2)
    250 		usage();
    251 
    252 	const char *secretfile = argv[1];
    253 
    254 	dump_xpriv(secretfile);
    255 
    256 	return 0;
    257 }