mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
432 lines
16 KiB
C
432 lines
16 KiB
C
#define SUPERVERBOSE printf
|
|
#include "config.h"
|
|
/* Needed before including bolt12_merkle.c: */
|
|
#include <common/type_to_string.h>
|
|
#include <stdio.h>
|
|
#include "../bolt12_merkle.c"
|
|
#include <assert.h>
|
|
#include <ccan/array_size/array_size.h>
|
|
#include <common/channel_type.h>
|
|
#include <common/features.h>
|
|
#include <common/setup.h>
|
|
#include <secp256k1_schnorrsig.h>
|
|
|
|
/* Definition of n1 from the spec */
|
|
#include <wire/peer_wire.h>
|
|
|
|
/* AUTOGENERATED MOCKS START */
|
|
/* Generated stub for features_unsupported */
|
|
int features_unsupported(const struct feature_set *our_features UNNEEDED,
|
|
const u8 *their_features UNNEEDED,
|
|
enum feature_place p UNNEEDED)
|
|
{ fprintf(stderr, "features_unsupported called!\n"); abort(); }
|
|
/* Generated stub for fromwire_blinded_path */
|
|
struct blinded_path *fromwire_blinded_path(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_blinded_path called!\n"); abort(); }
|
|
/* Generated stub for fromwire_channel_id */
|
|
bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
|
|
struct channel_id *channel_id UNNEEDED)
|
|
{ fprintf(stderr, "fromwire_channel_id called!\n"); abort(); }
|
|
/* Generated stub for towire_blinded_path */
|
|
void towire_blinded_path(u8 **p UNNEEDED, const struct blinded_path *blinded_path UNNEEDED)
|
|
{ fprintf(stderr, "towire_blinded_path called!\n"); abort(); }
|
|
/* Generated stub for towire_channel_id */
|
|
void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED)
|
|
{ fprintf(stderr, "towire_channel_id called!\n"); abort(); }
|
|
/* AUTOGENERATED MOCKS END */
|
|
|
|
/* Contat several tal objects */
|
|
#define concat(p, ...) concat_((p), __VA_ARGS__, NULL)
|
|
|
|
static LAST_ARG_NULL void *concat_(const void *p, ...)
|
|
{
|
|
va_list ap;
|
|
size_t len = 0;
|
|
u8 *ret = tal_arr(tmpctx, u8, len);
|
|
|
|
va_start(ap, p);
|
|
do {
|
|
tal_resize(&ret, len + tal_bytelen(p));
|
|
memcpy(ret + len, p, tal_bytelen(p));
|
|
len += tal_bytelen(p);
|
|
} while ((p = va_arg(ap, const void *)) != NULL);
|
|
va_end(ap);
|
|
return ret;
|
|
}
|
|
|
|
/* Just return type field from tlv */
|
|
static const u8 *tlv_type(const void *tlv)
|
|
{
|
|
size_t len = tal_bytelen(tlv);
|
|
const u8 *cursor = tlv;
|
|
|
|
fromwire_bigsize(&cursor, &len);
|
|
assert(cursor);
|
|
return tal_dup_arr(tmpctx, u8, tlv, tal_bytelen(tlv) - len, 0);
|
|
}
|
|
|
|
/* Hashes a tal object */
|
|
static struct sha256 *SHA256(const void *obj)
|
|
{
|
|
struct sha256 *ret = tal(tmpctx, struct sha256);
|
|
sha256(ret, obj, tal_bytelen(obj));
|
|
return ret;
|
|
}
|
|
|
|
/* Concatenate these two in lesser, greater order. */
|
|
static u8 *ordered(const struct sha256 *a, const struct sha256 *b)
|
|
{
|
|
u8 *ret = tal_arr(tmpctx, u8, sizeof(*a) + sizeof(*b));
|
|
|
|
if (memcmp(a, b, sizeof(*a)) < 0) {
|
|
memcpy(ret, a, sizeof(*a));
|
|
memcpy(ret + sizeof(*a), b, sizeof(*b));
|
|
} else {
|
|
memcpy(ret, b, sizeof(*b));
|
|
memcpy(ret + sizeof(*b), a, sizeof(*a));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static u8 *tlv(u64 type, const void *contents, size_t len)
|
|
{
|
|
u8 *ret = tal_arr(tmpctx, u8, 0);
|
|
|
|
towire_bigsize(&ret, type);
|
|
towire_bigsize(&ret, len);
|
|
towire(&ret, contents, len);
|
|
return ret;
|
|
}
|
|
|
|
/* BOLT-offers #12:
|
|
* Thus we define H(`tag`,`msg`) as SHA256(SHA256(`tag`) ||
|
|
* SHA256(`tag`) || `msg`) */
|
|
|
|
static struct sha256 *H(const void *tag, const void *msg)
|
|
{
|
|
const struct sha256 *taghash = SHA256(tag);
|
|
const u8 *full = concat(taghash, taghash, msg);
|
|
struct sha256 *ret = SHA256(full);
|
|
|
|
printf("test: H(tag=%s,msg=%s) -> SHA256(%s|%s|msg) -> %s\n",
|
|
tal_hex(tmpctx, tag), tal_hex(tmpctx, msg),
|
|
type_to_string(tmpctx, struct sha256, taghash),
|
|
type_to_string(tmpctx, struct sha256, taghash),
|
|
type_to_string(tmpctx, struct sha256, ret));
|
|
return ret;
|
|
}
|
|
|
|
static void merkle_n1(const struct tlv_n1 *n1, struct sha256 *test_m)
|
|
{
|
|
u8 *v;
|
|
size_t len;
|
|
struct tlv_n1 *tmp;
|
|
|
|
/* Linearize to populate ->fields */
|
|
v = tal_arr(tmpctx, u8, 0);
|
|
towire_tlv_n1(&v, n1);
|
|
|
|
len = tal_bytelen(v);
|
|
tmp = fromwire_tlv_n1(tmpctx, cast_const2(const u8 **, &v), &len);
|
|
assert(len == 0);
|
|
|
|
merkle_tlv(tmp->fields, test_m);
|
|
}
|
|
|
|
/* As a bonus, you get the bolt12/signature-test.json by running:
|
|
* common/test/run-bolt12_merkle | grep '^JSON:' | cut -d: -f2- | jq */
|
|
#define json_out(fmt, ...) printf("JSON: " fmt "\n" , ## __VA_ARGS__)
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct sha256 *m, test_m, *leaf[6];
|
|
const char *LnBranch, *LnNonce, *LnLeaf;
|
|
u8 *tlv1, *tlv2, *tlv3;
|
|
struct tlv_n1 *n1;
|
|
u8 node_id[PUBKEY_CMPR_LEN];
|
|
struct secret alice_secret, bob_secret;
|
|
struct pubkey alice, bob;
|
|
struct sha256 sha;
|
|
secp256k1_keypair kp;
|
|
char *fail;
|
|
|
|
common_setup(argv[0]);
|
|
/* Note: no nul term */
|
|
LnBranch = tal_dup_arr(tmpctx, char, "LnBranch", strlen("LnBranch"), 0);
|
|
LnLeaf = tal_dup_arr(tmpctx, char, "LnLeaf", strlen("LnLeaf"), 0);
|
|
LnNonce = tal_dup_arr(tmpctx, char, "LnNonce", strlen("LnNonce"), 0);
|
|
|
|
/* Create the tlvs, as per example `n1` in spec */
|
|
{
|
|
u8 *v;
|
|
struct short_channel_id scid;
|
|
struct node_id nid;
|
|
|
|
v = tal_arr(tmpctx, u8, 0);
|
|
towire_tu64(&v, 1000);
|
|
tlv1 = tlv(1, v, tal_bytelen(v));
|
|
|
|
v = tal_arr(tmpctx, u8, 0);
|
|
if (!mk_short_channel_id(&scid, 1, 2, 3))
|
|
abort();
|
|
towire_short_channel_id(&v, &scid);
|
|
tlv2 = tlv(2, v, tal_bytelen(v));
|
|
|
|
node_id_from_hexstr("0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", strlen("0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"), &nid);
|
|
v = tal_arr(tmpctx, u8, 0);
|
|
towire_node_id(&v, &nid);
|
|
towire_amount_msat(&v, AMOUNT_MSAT(1));
|
|
towire_amount_msat(&v, AMOUNT_MSAT(2));
|
|
tlv3 = tlv(3, v, tal_bytelen(v));
|
|
}
|
|
|
|
json_out("[");
|
|
|
|
json_out("{\"comment\": \"Simple n1 test, tlv1 = 1000\",");
|
|
json_out("\"tlv\": \"n1\",");
|
|
/* Simplest case, a single (msat) element. */
|
|
json_out("\"first-tlv\": \"%s\",", tal_hex(tmpctx, tlv1));
|
|
json_out("\"leaves\": [");
|
|
|
|
leaf[0] = H(LnBranch,
|
|
ordered(H(LnLeaf, tlv1),
|
|
H(concat(LnNonce, tlv1), tlv_type(tlv1))));
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,tlv1-type)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" }",
|
|
tal_hex(tmpctx, tlv1),
|
|
type_to_string(tmpctx, struct sha256, H(LnLeaf, tlv1)),
|
|
type_to_string(tmpctx, struct sha256, H(concat(LnNonce, tlv1), tlv_type(tlv1))),
|
|
type_to_string(tmpctx, struct sha256, leaf[0]));
|
|
json_out("],");
|
|
|
|
m = leaf[0];
|
|
|
|
json_out("\"branches\": [],");
|
|
json_out("\"merkle\": \"%s\"",
|
|
type_to_string(tmpctx, struct sha256, m));
|
|
json_out("},");
|
|
|
|
/* Create, linearize (populates ->fields) */
|
|
n1 = tlv_n1_new(tmpctx);
|
|
n1->tlv1 = tal(n1, u64);
|
|
*n1->tlv1 = 1000;
|
|
merkle_n1(n1, &test_m);
|
|
assert(sha256_eq(&test_m, m));
|
|
|
|
/* Two elements. */
|
|
json_out("{\"comment\": \"n1 test, tlv1 = 1000, tlv2 = 1x2x3\",");
|
|
json_out("\"tlv\": \"n1\",");
|
|
json_out("\"first-tlv\": \"%s\",", tal_hex(tmpctx, tlv1));
|
|
|
|
json_out("\"leaves\": [");
|
|
|
|
leaf[0] = H(LnBranch, ordered(H(LnLeaf, tlv1),
|
|
H(concat(LnNonce, tlv1), tlv_type(tlv1))));
|
|
leaf[1] = H(LnBranch, ordered(H(LnLeaf, tlv2),
|
|
H(concat(LnNonce, tlv1), tlv_type(tlv2))));
|
|
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,tlv1-type)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" },",
|
|
tal_hex(tmpctx, tlv1),
|
|
type_to_string(tmpctx, struct sha256, H(LnLeaf, tlv1)),
|
|
type_to_string(tmpctx, struct sha256, H(concat(LnNonce, tlv1), tlv_type(tlv1))),
|
|
type_to_string(tmpctx, struct sha256, leaf[0]));
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,tlv2-type)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" }",
|
|
tal_hex(tmpctx, tlv2),
|
|
type_to_string(tmpctx, struct sha256, H(LnLeaf, tlv2)),
|
|
type_to_string(tmpctx, struct sha256, H(concat(LnNonce, tlv1), tlv_type(tlv2))),
|
|
type_to_string(tmpctx, struct sha256, leaf[1]));
|
|
json_out("],");
|
|
|
|
json_out("\"branches\": [");
|
|
json_out("{ \"desc\": \"1: tlv1+nonce and tlv2+nonce\", \"H(`LnBranch`,%s)\": \"%s\" }",
|
|
tal_hex(tmpctx, ordered(leaf[0], leaf[1])),
|
|
tal_hex(tmpctx, H(LnBranch, ordered(leaf[0], leaf[1]))));
|
|
json_out("],");
|
|
|
|
m = H(LnBranch, ordered(leaf[0], leaf[1]));
|
|
|
|
json_out("\"merkle\": \"%s\"",
|
|
type_to_string(tmpctx, struct sha256, m));
|
|
json_out("},");
|
|
|
|
n1->tlv2 = tal(n1, struct short_channel_id);
|
|
if (!mk_short_channel_id(n1->tlv2, 1, 2, 3))
|
|
abort();
|
|
merkle_n1(n1, &test_m);
|
|
assert(sha256_eq(&test_m, m));
|
|
|
|
/* Three elements. */
|
|
json_out("{\"comment\": \"n1 test, tlv1 = 1000, tlv2 = 1x2x3, tlv3 = 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518, 1, 2\",");
|
|
json_out("\"tlv\": \"n1\",");
|
|
json_out("\"first-tlv\": \"%s\",", tal_hex(tmpctx, tlv1));
|
|
json_out("\"leaves\": [");
|
|
|
|
leaf[0] = H(LnBranch, ordered(H(LnLeaf, tlv1),
|
|
H(concat(LnNonce, tlv1), tlv_type(tlv1))));
|
|
leaf[1] = H(LnBranch, ordered(H(LnLeaf, tlv2),
|
|
H(concat(LnNonce, tlv1), tlv_type(tlv2))));
|
|
leaf[2] = H(LnBranch, ordered(H(LnLeaf, tlv3),
|
|
H(concat(LnNonce, tlv1), tlv_type(tlv3))));
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,1)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" },",
|
|
tal_hex(tmpctx, tlv1),
|
|
type_to_string(tmpctx, struct sha256, H(LnLeaf, tlv1)),
|
|
type_to_string(tmpctx, struct sha256, H(concat(LnNonce, tlv1), tlv_type(tlv1))),
|
|
type_to_string(tmpctx, struct sha256, leaf[0]));
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,2)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" },",
|
|
tal_hex(tmpctx, tlv2),
|
|
type_to_string(tmpctx, struct sha256, H(LnLeaf, tlv2)),
|
|
type_to_string(tmpctx, struct sha256, H(concat(LnNonce, tlv1), tlv_type(tlv2))),
|
|
type_to_string(tmpctx, struct sha256, leaf[1]));
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,3)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" }",
|
|
tal_hex(tmpctx, tlv3),
|
|
type_to_string(tmpctx, struct sha256, H(LnLeaf, tlv3)),
|
|
type_to_string(tmpctx, struct sha256, H(concat(LnNonce, tlv1), tlv_type(tlv3))),
|
|
type_to_string(tmpctx, struct sha256, leaf[2]));
|
|
json_out("],");
|
|
|
|
json_out("\"branches\": [");
|
|
json_out("{ \"desc\": \"1: tlv1+nonce and tlv2+nonce\", \"H(`LnBranch`,%s)\": \"%s\" },",
|
|
tal_hex(tmpctx, ordered(leaf[0], leaf[1])),
|
|
tal_hex(tmpctx, H(LnBranch, ordered(leaf[0], leaf[1]))));
|
|
json_out("{ \"desc\": \"1 and tlv3+nonce\", \"H(`LnBranch`,%s)\": \"%s\" }",
|
|
tal_hex(tmpctx, ordered(H(LnBranch, ordered(leaf[0], leaf[1])),
|
|
leaf[2])),
|
|
tal_hex(tmpctx, H(LnBranch,
|
|
ordered(H(LnBranch,
|
|
ordered(leaf[0], leaf[1])),
|
|
leaf[2]))));
|
|
json_out("],");
|
|
|
|
m = H(LnBranch,
|
|
ordered(H(LnBranch, ordered(leaf[0], leaf[1])),
|
|
leaf[2]));
|
|
json_out("\"merkle\": \"%s\"",
|
|
type_to_string(tmpctx, struct sha256, m));
|
|
json_out("},");
|
|
|
|
n1->tlv3 = tal(n1, struct tlv_n1_tlv3);
|
|
pubkey_from_hexstr("0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", strlen("0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"), &n1->tlv3->node_id);
|
|
n1->tlv3->amount_msat_1 = AMOUNT_MSAT(1);
|
|
n1->tlv3->amount_msat_2 = AMOUNT_MSAT(2);
|
|
merkle_n1(n1, &test_m);
|
|
assert(sha256_eq(&test_m, m));
|
|
|
|
/* Now try with an invoice request. */
|
|
struct tlv_invoice_request *invreq = tlv_invoice_request_new(tmpctx);
|
|
|
|
memset(&alice_secret, 'A', sizeof(alice_secret));
|
|
pubkey_from_secret(&alice_secret, &alice);
|
|
memset(&bob_secret, 'B', sizeof(bob_secret));
|
|
pubkey_from_secret(&bob_secret, &bob);
|
|
|
|
invreq->offer_node_id = tal_dup(invreq, struct pubkey, &alice);
|
|
invreq->offer_description = tal_dup_arr(invreq, char, "A Mathematical Treatise", strlen("A Mathematical Treatise"), 0);
|
|
invreq->offer_amount = tal(invreq, u64);
|
|
*invreq->offer_amount = 100;
|
|
invreq->offer_currency = tal_dup_arr(invreq, char, "USD", strlen("USD"), 0);
|
|
invreq->invreq_payer_id = tal_dup(invreq, struct pubkey, &bob);
|
|
invreq->invreq_metadata = tal_arrz(invreq, u8, 8);
|
|
|
|
/* Populate ->fields array, for merkle routine */
|
|
invreq->fields = tlv_make_fields(invreq, tlv_invoice_request);
|
|
merkle_tlv(invreq->fields, &test_m);
|
|
|
|
/* BOLT-offers #12:
|
|
* - MUST set `signature`.`sig` as detailed in [Signature Calculation](#signature-calculation) using the `invreq_payer_id`.
|
|
*/
|
|
invreq->signature = tal(invreq, struct bip340sig);
|
|
sighash_from_merkle("invoice_request", "signature", &test_m, &sha);
|
|
assert(secp256k1_keypair_create(secp256k1_ctx, &kp, bob_secret.data) == 1);
|
|
assert(secp256k1_schnorrsig_sign32(secp256k1_ctx, invreq->signature->u8,
|
|
sha.u.u8,
|
|
&kp,
|
|
NULL) == 1);
|
|
|
|
char *invreqtext = invrequest_encode(tmpctx, invreq);
|
|
invreq = invrequest_decode(tmpctx, invreqtext, strlen(invreqtext), NULL, NULL, &fail);
|
|
|
|
json_out("{\"comment\": \"invoice_request test: offer_node_id = Alice (privkey 0x414141...), offer_description = 'A Mathematical Treatise', offer_amount = 100, offer_currency = 'USD', invreq_payer_id = Bob (privkey 0x424242...), invreq_metadata = 0x0000000000000000\",");
|
|
json_out("\"bolt12\": \"%s\",", invreqtext);
|
|
json_out("\"tlv\": \"invoice_request\",");
|
|
|
|
assert(tal_count(invreq->fields) == 7);
|
|
u8 *fieldwires[6];
|
|
|
|
/* invreq_metadata: 8 bytes of 0 */
|
|
fieldwires[0] = tlv(0, "\0\0\0\0\0\0\0\0", 8);
|
|
/* offer_currency: USD */
|
|
fieldwires[1] = tlv(6, "USD", strlen("USD"));
|
|
/* offer_amount: 100 */
|
|
fieldwires[2] = tlv(8, "\x64", 1);
|
|
/* offer_description: A Mathematical Treatise */
|
|
fieldwires[3] = tlv(10, "A Mathematical Treatise", strlen("A Mathematical Treatise"));
|
|
/* offer_node_id: Alice */
|
|
pubkey_to_der(node_id, &alice);
|
|
fieldwires[4] = tlv(22, node_id, PUBKEY_CMPR_LEN);
|
|
/* invreq_payer_id: Bob */
|
|
pubkey_to_der(node_id, &bob);
|
|
fieldwires[5] = tlv(88, node_id, PUBKEY_CMPR_LEN);
|
|
|
|
json_out("\"first-tlv\": \"%s\",", tal_hex(tmpctx, fieldwires[0]));
|
|
|
|
json_out("\"leaves\": [");
|
|
for (size_t i = 0; i < ARRAY_SIZE(fieldwires); i++) {
|
|
leaf[i] = H(LnBranch,
|
|
ordered(H(LnLeaf, fieldwires[i]),
|
|
H(concat(LnNonce, fieldwires[0]), tlv_type(fieldwires[i]))));
|
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnNonce`|first-tlv,%u)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" }%s",
|
|
tal_hex(tmpctx, fieldwires[i]),
|
|
type_to_string(tmpctx, struct sha256,
|
|
H(LnLeaf, fieldwires[i])),
|
|
tlv_type(fieldwires[i])[0], /* Works becuase they're all 1-byte types! */
|
|
type_to_string(tmpctx, struct sha256,
|
|
H(concat(LnNonce, fieldwires[0]), tlv_type(fieldwires[i]))),
|
|
type_to_string(tmpctx, struct sha256, leaf[i]),
|
|
i == ARRAY_SIZE(fieldwires) - 1 ? "" : ",");
|
|
}
|
|
json_out("],");
|
|
|
|
json_out("\"branches\": [");
|
|
json_out("{ \"desc\": \"1: metadata+nonce and currency+nonce\", \"H(`LnBranch`,%s)\": \"%s\" },",
|
|
tal_hex(tmpctx, ordered(leaf[0], leaf[1])),
|
|
tal_hex(tmpctx, H(LnBranch, ordered(leaf[0], leaf[1]))));
|
|
json_out("{ \"desc\": \"2: amount+nonce and descripton+nonce\", \"H(`LnBranch`,%s)\": \"%s\"},",
|
|
tal_hex(tmpctx, ordered(leaf[2], leaf[3])),
|
|
tal_hex(tmpctx, H(LnBranch, ordered(leaf[2], leaf[3]))));
|
|
struct sha256 *b12 = H(LnBranch,
|
|
ordered(H(LnBranch,
|
|
ordered(leaf[0], leaf[1])),
|
|
H(LnBranch,
|
|
ordered(leaf[2], leaf[3]))));
|
|
json_out("{ \"desc\": \"3: 1 and 2\", \"H(`LnBranch`,%s)\": \"%s\" },",
|
|
tal_hex(tmpctx, ordered(H(LnBranch, ordered(leaf[0], leaf[1])),
|
|
H(LnBranch, ordered(leaf[2], leaf[3])))),
|
|
tal_hex(tmpctx, b12));
|
|
json_out("{ \"desc\": \"4: node_id+nonce and payer_id+nonce\", \"H(`LnBranch`,%s)\": \"%s\" },",
|
|
tal_hex(tmpctx, ordered(leaf[4], leaf[5])),
|
|
tal_hex(tmpctx, H(LnBranch, ordered(leaf[4], leaf[5]))));
|
|
json_out("{ \"desc\": \"5: 3 and 4\", \"H(`LnBranch`,%s)\": \"%s\" }",
|
|
tal_hex(tmpctx, ordered(b12,
|
|
H(LnBranch,
|
|
ordered(leaf[4], leaf[5])))),
|
|
tal_hex(tmpctx, H(LnBranch,
|
|
ordered(b12,
|
|
H(LnBranch,
|
|
ordered(leaf[4], leaf[5]))))));
|
|
m = H(LnBranch,
|
|
ordered(H(LnBranch,
|
|
ordered(H(LnBranch, ordered(leaf[0], leaf[1])),
|
|
H(LnBranch, ordered(leaf[2], leaf[3])))),
|
|
H(LnBranch, ordered(leaf[4], leaf[5]))));
|
|
|
|
json_out("],");
|
|
json_out("\"merkle\": \"%s\",",
|
|
type_to_string(tmpctx, struct sha256, m));
|
|
json_out("\"signature_tag\": \"lightninginvoice_requestsignature\",");
|
|
json_out("\"H(signature_tag,merkle)\": \"%s\",", type_to_string(tmpctx, struct sha256, &sha));
|
|
json_out("\"signature\": \"%s\"", type_to_string(tmpctx, struct bip340sig, invreq->signature));
|
|
json_out("}]");
|
|
|
|
assert(sha256_eq(&test_m, m));
|
|
|
|
common_shutdown();
|
|
}
|