Browse Source
e.g. $ PUBKEY1=0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518 $ PRIVKEY1=41bfd2660762506c9933ade59f1debf7e6495b10c14a92dbcd2d623da2507d3d $ PUBKEY2=022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59 $ PRIVKEY1=c4a813f81ffdca1da6864db81795ad2d320add274452cafa1fb2ac2d07d062bd # First line is blinding, second is contents and nodeids for onion. $ ./devtools/blindedpath create $PUBKEY1 $PUBKEY2 03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518/350633c340f28bc69cbc86f568b7b9e99fa41eb581452d066fcd70dd53c43ace14d034eebfbe472a2b9901b11c268d2cc2034a77928a 0326f31ff78e584461420e5026fe72374af2ef853e65c47a3f2406348b7c6c0911/00 # Generate the onion $ /devtools/onion generate 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518/350633c340f28bc69cbc86f568b7b9e99fa41eb581452d066fcd70dd53c43ace14d034eebfbe472a2b9901b11c268d2cc2034a77928a 0326f31ff78e584461420e5026fe72374af2ef853e65c47a3f2406348b7c6c0911/00 > /tmp/onion.dat # First node unwraps it, gives next blinding and onion $ ./devtools/blindedpath --first-node unwrap $PRIVKEY1 `cat /tmp/onion.dat` 03f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a Contents: 04210326f31ff78e584461420e5026fe72374af2ef853e65c47a3f2406348b7c6c0911 Next blinding: 021295ce94fcadc42c3e5187a12dd80122214c8f9da61635163cddb63282f1ee9b Next onion: 0003c8fa9d4997ebd049480db14f0a90db211ec2b9f062e569419ee2c2b528a2d7adc63aa9e7b74997c2c122c4c1923e2f4587fc62532965666dbe55a76aa1ea903cfe6c498c6b7e80c14609d3c0f98f86a30f94b0b8a405067ee3801aab03420922cdc847d6f2fc359655408047a8d7d7892a595f630cdf114d1cc0d1164dc8099378042cfba7a13711dff64000356aac29726a6039bf938b81cc0dcc7f65dc126ae58838c0446d6492b6381f0402a33318a9ae71486bcb4b58f66c9a056fca306668655c11f7d7d0cd447e4162100565369629ca8b705b2b999a40ad5493953cb70b35f382e6acdc04e5a933783f9c5859fb0beeaa9c54e5220f5de3b107813d33148501aebcf67e190d3dcf10553714d4de8a1643b519cd124da9a345e2da0d669954a10fce9c1e7795572fb2ac8fe6de4db856bdbd327f0c4ae3cb11f6e1422f663423ad57891d069bbc5bdc7613c742a2227d3789d9039dcdcbddc2703835002dd176004c56cc497d88deae2328ad1376877f4582c71a7fa1eba4ae4e6696782bd97d7b362f41e81335b47273a74c983c3bc80499069a08c6b7ffa32cc77f54a98d8bc2f80f38c370c98edd8f6d6f95c6bbf5c8040296f68560de3b50c3450de4fcceae41469bea6a24c83141c92956fa4c4087f11e9c26b282e9c3974fadc8f9bb9fb9c3fbd2ead0cf4ceaba452eb8791828a159ace7a2e1e8ff5c69704a821c6c898a3c38439149862f14b7ed34afb93640c3ae61b089011ef698c9e26dc16b8a5a8ec66fce702b7bdf04a21cf9a2ebff6b89b29904e7e3e6a98088c2848951c0d6915249a3e1199c2affe4635ac6ef3a16ddfefc5790435a14067b24d5ecd16a26d2f7dbd8065b8e5b86f73f878cf55ca0c9f12104d861d03ac5c4b3dcbd0e30ad7ba888ddcc2e89acb3c04be2ef4bce3ef8c8878fef5be65664f1ec288f91dbd1748e2e53bcbd7dc9cecd75a246992e76a844ab122c5e179f97531190c7d91586289410c9ddad33eb156ab7312c82e55f3d643f3c12468ce79f7221051da608dd17ceb235b7df89f3c4b9aa9448bf36206b2db7bb97f544d062d6aa1b1706376fb6e3e8ef1ac293b9adca478458e9e51845dc7b554c70a91e32c331962968f98db26faa5b10a39bc778b0aab5a9fd11fdbab7b456db286049e584b7e4d1c76d6c3c6249b567aa357982ceead2ad8d5113a866818997b24018059e93eb5cafd293942efec3cf4a43bf322cd444e8370dc2cf1f1164c5147b30a791e262acadc15c30f1e169af4bff5e6c098acf95534b0b59517e3168413134984d50c8242590c8729fe34190d20d7f88505747b919e0bf8b41ed4ec9146743339c6885dcb770dcac627a1570dc145f6f61a976d87d16473195d5f5ce39347ab040c34fe0888b498f0ba25686a9bae51f6e5973d15f10d1c7dbe5fbfa2c7fe05cdd52d8eca8150914b4cb2e75e52010bb4b9241160d7337f47bbebd3bea58ddcf320a0464c34dbfd3d3ea7ffaee966c36064b2cc77babbf4613a7d5d65b3931dc42f91ed902207c57509a46738d31671c439d052c16db5ce3e613c5b37f77e574e9a847ebab20159130f33186557d16ddd1d765e7a9adedb253b755128e1af58da9e8b0fe6ed5834ddf1537c0ee78cd9803ee06031c3c1331d405a94a54f06d1147b26d0788179320d882f57ee9c63ab7a76fb9572eb813fe55369b5061b0a242b07a72095754a9d5699534a46829398204e76f1eda1d65e98fab1e8f3cf7c85257c8e2da0546fed215c3db38d231a637fd7a4e6f10b786d15534137489c662a0f289da824ca8dfef335bdcc623d636d231e002cc32febbe6683046ee54702dbeb55a70911505844c79c0be4630cf49456fba55aec9218d3ba449540370d407fc653007fdf59b4711d1da3c2e569eec4de8cee7b05d248ad0 # Feed that onion and blinding to second node $ ./devtools/blindedpath unwrap $PRIVKEY2 0003c8fa9d4997ebd049480db14f0a90db211ec2b9f062e569419ee2c2b528a2d7adc63aa9e7b74997c2c122c4c1923e2f4587fc62532965666dbe55a76aa1ea903cfe6c498c6b7e80c14609d3c0f98f86a30f94b0b8a405067ee3801aab03420922cdc847d6f2fc359655408047a8d7d7892a595f630cdf114d1cc0d1164dc8099378042cfba7a13711dff64000356aac29726a6039bf938b81cc0dcc7f65dc126ae58838c0446d6492b6381f0402a33318a9ae71486bcb4b58f66c9a056fca306668655c11f7d7d0cd447e4162100565369629ca8b705b2b999a40ad5493953cb70b35f382e6acdc04e5a933783f9c5859fb0beeaa9c54e5220f5de3b107813d33148501aebcf67e190d3dcf10553714d4de8a1643b519cd124da9a345e2da0d669954a10fce9c1e7795572fb2ac8fe6de4db856bdbd327f0c4ae3cb11f6e1422f663423ad57891d069bbc5bdc7613c742a2227d3789d9039dcdcbddc2703835002dd176004c56cc497d88deae2328ad1376877f4582c71a7fa1eba4ae4e6696782bd97d7b362f41e81335b47273a74c983c3bc80499069a08c6b7ffa32cc77f54a98d8bc2f80f38c370c98edd8f6d6f95c6bbf5c8040296f68560de3b50c3450de4fcceae41469bea6a24c83141c92956fa4c4087f11e9c26b282e9c3974fadc8f9bb9fb9c3fbd2ead0cf4ceaba452eb8791828a159ace7a2e1e8ff5c69704a821c6c898a3c38439149862f14b7ed34afb93640c3ae61b089011ef698c9e26dc16b8a5a8ec66fce702b7bdf04a21cf9a2ebff6b89b29904e7e3e6a98088c2848951c0d6915249a3e1199c2affe4635ac6ef3a16ddfefc5790435a14067b24d5ecd16a26d2f7dbd8065b8e5b86f73f878cf55ca0c9f12104d861d03ac5c4b3dcbd0e30ad7ba888ddcc2e89acb3c04be2ef4bce3ef8c8878fef5be65664f1ec288f91dbd1748e2e53bcbd7dc9cecd75a246992e76a844ab122c5e179f97531190c7d91586289410c9ddad33eb156ab7312c82e55f3d643f3c12468ce79f7221051da608dd17ceb235b7df89f3c4b9aa9448bf36206b2db7bb97f544d062d6aa1b1706376fb6e3e8ef1ac293b9adca478458e9e51845dc7b554c70a91e32c331962968f98db26faa5b10a39bc778b0aab5a9fd11fdbab7b456db286049e584b7e4d1c76d6c3c6249b567aa357982ceead2ad8d5113a866818997b24018059e93eb5cafd293942efec3cf4a43bf322cd444e8370dc2cf1f1164c5147b30a791e262acadc15c30f1e169af4bff5e6c098acf95534b0b59517e3168413134984d50c8242590c8729fe34190d20d7f88505747b919e0bf8b41ed4ec9146743339c6885dcb770dcac627a1570dc145f6f61a976d87d16473195d5f5ce39347ab040c34fe0888b498f0ba25686a9bae51f6e5973d15f10d1c7dbe5fbfa2c7fe05cdd52d8eca8150914b4cb2e75e52010bb4b9241160d7337f47bbebd3bea58ddcf320a0464c34dbfd3d3ea7ffaee966c36064b2cc77babbf4613a7d5d65b3931dc42f91ed902207c57509a46738d31671c439d052c16db5ce3e613c5b37f77e574e9a847ebab20159130f33186557d16ddd1d765e7a9adedb253b755128e1af58da9e8b0fe6ed5834ddf1537c0ee78cd9803ee06031c3c1331d405a94a54f06d1147b26d0788179320d882f57ee9c63ab7a76fb9572eb813fe55369b5061b0a242b07a72095754a9d5699534a46829398204e76f1eda1d65e98fab1e8f3cf7c85257c8e2da0546fed215c3db38d231a637fd7a4e6f10b786d15534137489c662a0f289da824ca8dfef335bdcc623d636d231e002cc32febbe6683046ee54702dbeb55a70911505844c79c0be4630cf49456fba55aec9218d3ba449540370d407fc653007fdf59b4711d1da3c2e569eec4de8cee7b05d248ad0 021295ce94fcadc42c3e5187a12dd80122214c8f9da61635163cddb63282f1ee9b Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Header from folded patch 'fixup': fixup! devtool/blindedpath: primitive tool to make blinded onions. On decode, don't mess with op.ephemeralkey, since it will be used to derive the next hop. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>travis-debug
Rusty Russell
5 years ago
2 changed files with 322 additions and 0 deletions
@ -0,0 +1,316 @@ |
|||
#include "config.h" |
|||
#include <assert.h> |
|||
#include <bitcoin/privkey.h> |
|||
#include <ccan/err/err.h> |
|||
#include <ccan/mem/mem.h> |
|||
#include <ccan/opt/opt.h> |
|||
#include <ccan/str/hex/hex.h> |
|||
#include <ccan/tal/tal.h> |
|||
#include <common/hmac.h> |
|||
#include <common/sphinx.h> |
|||
#include <common/type_to_string.h> |
|||
#include <common/utils.h> |
|||
#include <common/version.h> |
|||
#include <secp256k1.h> |
|||
#include <secp256k1_ecdh.h> |
|||
#include <sodium/crypto_auth_hmacsha256.h> |
|||
#include <sodium/crypto_aead_chacha20poly1305.h> |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <unistd.h> |
|||
|
|||
/* Tal wrappers for opt. */ |
|||
static void *opt_allocfn(size_t size) |
|||
{ |
|||
return tal_arr_label(NULL, char, size, TAL_LABEL("opt_allocfn", "")); |
|||
} |
|||
|
|||
static void *tal_reallocfn(void *ptr, size_t size) |
|||
{ |
|||
if (!ptr) |
|||
return opt_allocfn(size); |
|||
tal_resize_(&ptr, 1, size, false); |
|||
return ptr; |
|||
} |
|||
|
|||
static void tal_freefn(void *ptr) |
|||
{ |
|||
tal_free(ptr); |
|||
} |
|||
|
|||
/* E(i-1) = H(E(i) || ss(i)) * E(i) */ |
|||
static struct sha256 hash_e_and_ss(const struct pubkey *e, |
|||
const struct secret *ss) |
|||
{ |
|||
u8 der[PUBKEY_CMPR_LEN]; |
|||
struct sha256_ctx shactx; |
|||
struct sha256 h; |
|||
|
|||
pubkey_to_der(der, e); |
|||
sha256_init(&shactx); |
|||
sha256_update(&shactx, der, sizeof(der)); |
|||
sha256_update(&shactx, ss->data, sizeof(ss->data)); |
|||
sha256_done(&shactx, &h); |
|||
|
|||
return h; |
|||
} |
|||
|
|||
/* E(i-1) = H(E(i) || ss(i)) * E(i) */ |
|||
static struct pubkey next_pubkey(const struct pubkey *pk, |
|||
const struct sha256 *h) |
|||
{ |
|||
struct pubkey ret; |
|||
|
|||
ret = *pk; |
|||
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, &ret.pubkey, h->u.u8) |
|||
!= 1) |
|||
abort(); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
/* e(i+1) = H(E(i) || ss(i)) * e(i) */ |
|||
static struct privkey next_privkey(const struct privkey *e, |
|||
const struct sha256 *h) |
|||
{ |
|||
struct privkey ret; |
|||
|
|||
ret = *e; |
|||
if (secp256k1_ec_privkey_tweak_mul(secp256k1_ctx, ret.secret.data, |
|||
h->u.u8) != 1) |
|||
abort(); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
bool first = false; |
|||
|
|||
setup_locale(); |
|||
|
|||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | |
|||
SECP256K1_CONTEXT_SIGN); |
|||
|
|||
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); |
|||
opt_register_noarg("--help|-h", opt_usage_and_exit, |
|||
"\n\n\tcreate <nodeid>[/<scid>]...\n" |
|||
"\tunwrap <privkey> <onion> <blinding>\n", |
|||
"Show this message"); |
|||
opt_register_noarg("--first-node", opt_set_bool, &first, |
|||
"Don't try to tweak key to unwrap onion"); |
|||
opt_register_version(); |
|||
|
|||
opt_parse(&argc, argv, opt_log_stderr_exit); |
|||
setup_tmpctx(); |
|||
|
|||
if (argc < 2) |
|||
errx(1, "You must specify create or unwrap"); |
|||
if (streq(argv[1], "create")) { |
|||
struct privkey e; |
|||
struct pubkey *pk_e, *b, *nodes; |
|||
struct secret *rho; |
|||
size_t num = argc - 2; |
|||
|
|||
if (argc < 3) |
|||
errx(1, "create requires at least one nodeid"); |
|||
|
|||
/* P(i) */ |
|||
nodes = tal_arr(tmpctx, struct pubkey, num); |
|||
/* E(i) */ |
|||
pk_e = tal_arr(tmpctx, struct pubkey, num); |
|||
/* B(i) */ |
|||
b = tal_arr(tmpctx, struct pubkey, num); |
|||
/* rho(i) */ |
|||
rho = tal_arr(tmpctx, struct secret, num); |
|||
|
|||
/* Randomness, chosen with a fair dice roll! */ |
|||
memset(&e, 6, sizeof(e)); |
|||
if (!pubkey_from_privkey(&e, &pk_e[0])) |
|||
abort(); |
|||
|
|||
for (size_t i = 0; i < num; i++) { |
|||
struct secret ss; |
|||
struct secret hmac; |
|||
struct sha256 h; |
|||
|
|||
if (!pubkey_from_hexstr(argv[2+i], |
|||
strcspn(argv[2+i], "/"), |
|||
&nodes[i])) |
|||
errx(1, "%s not a valid pubkey", argv[2+i]); |
|||
|
|||
if (secp256k1_ecdh(secp256k1_ctx, ss.data, |
|||
&nodes[i].pubkey, e.secret.data, NULL, NULL) != 1) |
|||
abort(); |
|||
|
|||
subkey_from_hmac("blinded_node_id", &ss, &hmac); |
|||
b[i] = nodes[i]; |
|||
if (i != 0) { |
|||
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, |
|||
&b[i].pubkey, hmac.data) != 1) |
|||
abort(); |
|||
} |
|||
subkey_from_hmac("rho", &ss, &rho[i]); |
|||
h = hash_e_and_ss(&pk_e[i], &ss); |
|||
if (i != num-1) |
|||
pk_e[i+1] = next_pubkey(&pk_e[i], &h); |
|||
e = next_privkey(&e, &h); |
|||
} |
|||
|
|||
/* Print initial blinding factor */ |
|||
printf("Blinding: %s\n", |
|||
type_to_string(tmpctx, struct pubkey, &pk_e[0])); |
|||
|
|||
for (size_t i = 0; i < num - 1; i++) { |
|||
u8 *p; |
|||
u8 buf[BIGSIZE_MAX_LEN]; |
|||
const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
|||
struct tlv_onionmsg_payload *inner, *outer; |
|||
int ret; |
|||
|
|||
/* Inner is encrypted */ |
|||
inner = tlv_onionmsg_payload_new(tmpctx); |
|||
/* FIXME: Use /scid for encblob if specified */ |
|||
inner->next_node_id = tal(inner, struct tlv_onionmsg_payload_next_node_id); |
|||
inner->next_node_id->node_id = nodes[i+1]; |
|||
p = tal_arr(tmpctx, u8, 0); |
|||
towire_encmsg_tlvs(&p, inner); |
|||
|
|||
outer = tlv_onionmsg_payload_new(tmpctx); |
|||
outer->enctlv = tal(outer, struct tlv_onionmsg_payload_enctlv); |
|||
outer->enctlv->enctlv = tal_arr(tmpctx, u8, tal_count(p) |
|||
+ crypto_aead_chacha20poly1305_ietf_ABYTES); |
|||
ret = crypto_aead_chacha20poly1305_ietf_encrypt(outer->enctlv->enctlv, NULL, |
|||
p, |
|||
tal_bytelen(p), |
|||
NULL, 0, |
|||
NULL, npub, |
|||
rho[i].data); |
|||
assert(ret == 0); |
|||
|
|||
p = tal_arr(tmpctx, u8, 0); |
|||
towire_onionmsg_payload(&p, outer); |
|||
ret = bigsize_put(buf, tal_bytelen(p)); |
|||
|
|||
/* devtools/onion wants length explicitly prepended */ |
|||
printf("%s/%.*s%s ", |
|||
type_to_string(tmpctx, struct pubkey, &b[i]), |
|||
ret * 2, |
|||
tal_hexstr(tmpctx, buf, ret), |
|||
tal_hex(tmpctx, p)); |
|||
} |
|||
/* No payload for last node */ |
|||
printf("%s/00\n", |
|||
type_to_string(tmpctx, struct pubkey, &b[num-1])); |
|||
} else if (streq(argv[1], "unwrap")) { |
|||
struct privkey privkey; |
|||
struct pubkey blinding; |
|||
u8 onion[TOTAL_PACKET_SIZE], *dec; |
|||
struct onionpacket op; |
|||
struct secret ss, onion_ss; |
|||
struct secret hmac, rho; |
|||
struct route_step *rs; |
|||
const u8 *cursor; |
|||
struct tlv_onionmsg_payload *outer; |
|||
size_t max, len; |
|||
struct pubkey res; |
|||
struct sha256 h; |
|||
int ret; |
|||
const unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
|||
|
|||
if (argc != 5) |
|||
errx(1, "unwrap requires privkey, onion and blinding"); |
|||
|
|||
if (!hex_decode(argv[2], strlen(argv[2]), &privkey, |
|||
sizeof(privkey))) |
|||
errx(1, "Invalid private key hex '%s'", argv[2]); |
|||
|
|||
if (!hex_decode(argv[3], strlen(argv[3]), onion, |
|||
sizeof(onion))) |
|||
errx(1, "Invalid onion %s", argv[3]); |
|||
|
|||
if (!pubkey_from_hexstr(argv[4], strlen(argv[4]), &blinding)) |
|||
errx(1, "Invalid blinding %s", argv[4]); |
|||
|
|||
if (parse_onionpacket(onion, sizeof(onion), &op) != 0) |
|||
errx(1, "Unparsable onion"); |
|||
|
|||
/* ss(r) = H(k(r) * E(r)) */ |
|||
if (secp256k1_ecdh(secp256k1_ctx, ss.data, &blinding.pubkey, |
|||
privkey.secret.data, NULL, NULL) != 1) |
|||
abort(); |
|||
|
|||
subkey_from_hmac("rho", &ss, &rho); |
|||
|
|||
/* b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) */ |
|||
subkey_from_hmac("blinded_node_id", &ss, &hmac); |
|||
|
|||
/* We instead tweak the *ephemeral* key from the onion
|
|||
* and use our raw privkey: this models how lightningd |
|||
* will do it, since hsmd knows only how to ECDH with |
|||
* our real key */ |
|||
res = op.ephemeralkey; |
|||
if (!first) { |
|||
if (secp256k1_ec_pubkey_tweak_mul(secp256k1_ctx, |
|||
&res.pubkey, |
|||
hmac.data) != 1) |
|||
abort(); |
|||
} |
|||
|
|||
if (secp256k1_ecdh(secp256k1_ctx, onion_ss.data, |
|||
&res.pubkey, |
|||
privkey.secret.data, NULL, NULL) != 1) |
|||
abort(); |
|||
|
|||
rs = process_onionpacket(tmpctx, &op, &onion_ss, NULL, 0, false); |
|||
if (!rs) |
|||
errx(1, "Could not process onionpacket"); |
|||
|
|||
cursor = rs->raw_payload; |
|||
max = tal_bytelen(cursor); |
|||
len = fromwire_bigsize(&cursor, &max); |
|||
|
|||
/* Always true since we're non-legacy */ |
|||
assert(len == max); |
|||
outer = tlv_onionmsg_payload_new(tmpctx); |
|||
if (!fromwire_onionmsg_payload(&cursor, &max, outer)) |
|||
errx(1, "Invalid payload %s", |
|||
tal_hex(tmpctx, rs->raw_payload)); |
|||
|
|||
if (rs->nextcase == ONION_END) { |
|||
printf("TERMINAL\n"); |
|||
return 0; |
|||
} |
|||
|
|||
/* Look for enctlv */ |
|||
if (!outer->enctlv) |
|||
errx(1, "No enctlv field"); |
|||
|
|||
if (tal_bytelen(outer->enctlv->enctlv) |
|||
< crypto_aead_chacha20poly1305_ietf_ABYTES) |
|||
errx(1, "enctlv field too short"); |
|||
|
|||
dec = tal_arr(tmpctx, u8, |
|||
tal_bytelen(outer->enctlv->enctlv) |
|||
- crypto_aead_chacha20poly1305_ietf_ABYTES); |
|||
ret = crypto_aead_chacha20poly1305_ietf_decrypt(dec, NULL, |
|||
NULL, |
|||
outer->enctlv->enctlv, |
|||
tal_bytelen(outer->enctlv->enctlv), |
|||
NULL, 0, |
|||
npub, |
|||
rho.data); |
|||
if (ret != 0) |
|||
errx(1, "Failed to decrypt enctlv field"); |
|||
|
|||
printf("Contents: %s\n", tal_hex(tmpctx, dec)); |
|||
|
|||
/* E(i-1) = H(E(i) || ss(i)) * E(i) */ |
|||
h = hash_e_and_ss(&blinding, &ss); |
|||
res = next_pubkey(&blinding, &h); |
|||
printf("Next blinding: %s\n", |
|||
type_to_string(tmpctx, struct pubkey, &res)); |
|||
printf("Next onion: %s\n", tal_hex(tmpctx, serialize_onionpacket(tmpctx, rs->next))); |
|||
} else |
|||
errx(1, "Either create or unwrap!"); |
|||
} |
Loading…
Reference in new issue