mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
bolt12_merkle: change offer merkle to latest spec.
And fix up the mess we'd made: 1. We didn't order merkles by lesser-first. 2. We didn't correctly construct tree with last nodes on shortest path. Now we have tests! Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Changelog-EXPERIMENTAL: protocol: offer signature format changed.
This commit is contained in:
parent
a29847f0c6
commit
3b40bfa801
@ -1,8 +1,14 @@
|
|||||||
#include <bitcoin/signature.h>
|
#include <bitcoin/signature.h>
|
||||||
|
#include <ccan/cast/cast.h>
|
||||||
#include <ccan/crypto/sha256/sha256.h>
|
#include <ccan/crypto/sha256/sha256.h>
|
||||||
|
#include <ccan/ilog/ilog.h>
|
||||||
#include <ccan/mem/mem.h>
|
#include <ccan/mem/mem.h>
|
||||||
#include <common/bolt12_merkle.h>
|
#include <common/bolt12_merkle.h>
|
||||||
|
|
||||||
|
#ifndef SUPERVERBOSE
|
||||||
|
#define SUPERVERBOSE(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* BOLT-offers #12:
|
/* BOLT-offers #12:
|
||||||
* TLV types 240 through 1000 are considered signature elements.
|
* TLV types 240 through 1000 are considered signature elements.
|
||||||
*/
|
*/
|
||||||
@ -17,6 +23,7 @@ static void sha256_update_bigsize(struct sha256_ctx *ctx, u64 bigsize)
|
|||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
len = bigsize_put(buf, bigsize);
|
len = bigsize_put(buf, bigsize);
|
||||||
|
SUPERVERBOSE("%s", tal_hexstr(tmpctx, buf, len));
|
||||||
sha256_update(ctx, buf, len);
|
sha256_update(ctx, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,93 +33,165 @@ static void sha256_update_tlvfield(struct sha256_ctx *ctx,
|
|||||||
/* We don't keep it raw, so reconstruct. */
|
/* We don't keep it raw, so reconstruct. */
|
||||||
sha256_update_bigsize(ctx, field->numtype);
|
sha256_update_bigsize(ctx, field->numtype);
|
||||||
sha256_update_bigsize(ctx, field->length);
|
sha256_update_bigsize(ctx, field->length);
|
||||||
|
SUPERVERBOSE("%s", tal_hexstr(tmpctx, field->value, field->length));
|
||||||
sha256_update(ctx, field->value, field->length);
|
sha256_update(ctx, field->value, field->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BOLT-offers #12:
|
/* BOLT-offers #12:
|
||||||
* The Merkle Tree's leaves are, in TLV-ascending order:
|
* Thus we define H(`tag`,`msg`) as SHA256(SHA256(`tag`) || SHA256(`tag`) || `msg`)*/
|
||||||
* 1. The SHA256 of: `LnLeaf` followed by the TLV entry.
|
/* Create a sha256_ctx which has the tag part done. */
|
||||||
* 2. The SHA256 of: `LnAll` followed all non-signature TLV entries appended
|
static void h_simpletag_ctx(struct sha256_ctx *sctx, const char *tag)
|
||||||
* in ascending order.
|
{
|
||||||
|
struct sha256 sha;
|
||||||
|
sha256(&sha, tag, strlen(tag));
|
||||||
|
sha256_init(sctx);
|
||||||
|
sha256_update(sctx, &sha, sizeof(sha));
|
||||||
|
sha256_update(sctx, &sha, sizeof(sha));
|
||||||
|
SUPERVERBOSE("tag=SHA256(%s) -> %s",
|
||||||
|
tal_hexstr(tmpctx, tag, strlen(tag)),
|
||||||
|
type_to_string(tmpctx, struct sha256, &sha));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* BOLT-offers #12:
|
||||||
|
* The Merkle tree's leaves are, in TLV-ascending order for each tlv:
|
||||||
|
* 1. The H(`LnLeaf`,tlv).
|
||||||
|
* 2. The H(`LnAll`|all-tlvs,tlv) where "all-tlvs" consists of all non-signature TLV entries appended in ascending order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void calc_lnall(const struct tlv_field *fields, struct sha256 *hash)
|
/* Create a sha256_ctx which has the tag part done. */
|
||||||
|
static void h_lnall_ctx(struct sha256_ctx *sctx, const struct tlv_field *fields)
|
||||||
{
|
{
|
||||||
struct sha256_ctx sctx;
|
struct sha256_ctx inner_sctx;
|
||||||
|
struct sha256 sha;
|
||||||
|
|
||||||
sha256_init(&sctx);
|
sha256_init(&inner_sctx);
|
||||||
sha256_update(&sctx, "LnAll", 5);
|
sha256_update(&inner_sctx, "LnAll", 5);
|
||||||
|
SUPERVERBOSE("tag=SHA256(%s", tal_hexstr(tmpctx, "LnAll", 5));
|
||||||
for (size_t i = 0; i < tal_count(fields); i++) {
|
for (size_t i = 0; i < tal_count(fields); i++) {
|
||||||
if (!is_signature_field(&fields[i]))
|
if (!is_signature_field(&fields[i]))
|
||||||
sha256_update_tlvfield(&sctx, &fields[i]);
|
sha256_update_tlvfield(&inner_sctx, &fields[i]);
|
||||||
}
|
}
|
||||||
sha256_done(&sctx, hash);
|
sha256_done(&inner_sctx, &sha);
|
||||||
|
SUPERVERBOSE(") -> %s\n",
|
||||||
|
type_to_string(tmpctx, struct sha256, &sha));
|
||||||
|
|
||||||
|
sha256_init(sctx);
|
||||||
|
sha256_update(sctx, &sha, sizeof(sha));
|
||||||
|
sha256_update(sctx, &sha, sizeof(sha));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use h_lnall_ctx to create nonce */
|
||||||
|
static void calc_nonce(const struct sha256_ctx *lnall_ctx,
|
||||||
|
const struct tlv_field *field,
|
||||||
|
struct sha256 *hash)
|
||||||
|
{
|
||||||
|
/* Copy context, to add field */
|
||||||
|
struct sha256_ctx ctx = *lnall_ctx;
|
||||||
|
|
||||||
|
SUPERVERBOSE("nonce: H(noncetag,");
|
||||||
|
sha256_update_tlvfield(&ctx, field);
|
||||||
|
|
||||||
|
sha256_done(&ctx, hash);
|
||||||
|
SUPERVERBOSE(") = %s\n", type_to_string(tmpctx, struct sha256, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calc_lnleaf(const struct tlv_field *field, struct sha256 *hash)
|
static void calc_lnleaf(const struct tlv_field *field, struct sha256 *hash)
|
||||||
{
|
{
|
||||||
struct sha256_ctx sctx;
|
struct sha256_ctx sctx;
|
||||||
|
|
||||||
sha256_init(&sctx);
|
SUPERVERBOSE("leaf: H(");
|
||||||
sha256_update(&sctx, "LnLeaf", 6);
|
h_simpletag_ctx(&sctx, "LnLeaf");
|
||||||
|
SUPERVERBOSE(",");
|
||||||
sha256_update_tlvfield(&sctx, field);
|
sha256_update_tlvfield(&sctx, field);
|
||||||
sha256_done(&sctx, hash);
|
sha256_done(&sctx, hash);
|
||||||
|
SUPERVERBOSE(") -> %s\n", type_to_string(tmpctx, struct sha256, hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sha256 merkle_pair(const struct sha256 a, const struct sha256 b)
|
/* BOLT-offers #12:
|
||||||
|
* The Merkle tree inner nodes are H(`LnBranch`, lesser-SHA256|greater-SHA256);
|
||||||
|
*/
|
||||||
|
static struct sha256 *merkle_pair(const tal_t *ctx,
|
||||||
|
const struct sha256 *a, const struct sha256 *b)
|
||||||
{
|
{
|
||||||
struct sha256 res;
|
struct sha256 *res;
|
||||||
struct sha256_ctx sctx;
|
struct sha256_ctx sctx;
|
||||||
|
|
||||||
sha256_init(&sctx);
|
/* Make sure a < b */
|
||||||
sha256_update(&sctx, "LnBranch", 8);
|
if (memcmp(a->u.u8, b->u.u8, sizeof(a->u.u8)) > 0)
|
||||||
sha256_update(&sctx, a.u.u8, sizeof(a.u.u8));
|
return merkle_pair(ctx, b, a);
|
||||||
sha256_update(&sctx, b.u.u8, sizeof(b.u.u8));
|
|
||||||
sha256_done(&sctx, &res);
|
|
||||||
|
|
||||||
|
SUPERVERBOSE("branch: H(");
|
||||||
|
h_simpletag_ctx(&sctx, "LnBranch");
|
||||||
|
SUPERVERBOSE(",%s %s",
|
||||||
|
tal_hexstr(tmpctx, a->u.u8, sizeof(a->u.u8)),
|
||||||
|
tal_hexstr(tmpctx, b->u.u8, sizeof(b->u.u8)));
|
||||||
|
sha256_update(&sctx, a->u.u8, sizeof(a->u.u8));
|
||||||
|
sha256_update(&sctx, b->u.u8, sizeof(b->u.u8));
|
||||||
|
|
||||||
|
res = tal(ctx, struct sha256);
|
||||||
|
sha256_done(&sctx, res);
|
||||||
|
SUPERVERBOSE(") -> %s\n", type_to_string(tmpctx, struct sha256, res));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sha256 merkle_recurse(const struct sha256 *arr, size_t len)
|
static const struct sha256 *merkle_recurse(const struct sha256 **base,
|
||||||
|
const struct sha256 **arr, size_t len)
|
||||||
{
|
{
|
||||||
|
const struct sha256 *left, *right;
|
||||||
if (len == 1)
|
if (len == 1)
|
||||||
return arr[0];
|
return arr[0];
|
||||||
|
|
||||||
return merkle_pair(merkle_recurse(arr, len / 2),
|
SUPERVERBOSE("Merkle recurse [%zu - %zu] and [%zu - %zu]\n",
|
||||||
merkle_recurse(arr + len / 2, len - len / 2));
|
arr - base, arr + len / 2 - 1 - base,
|
||||||
|
arr + len / 2 - base, arr + len - base);
|
||||||
|
left = merkle_recurse(base, arr, len / 2);
|
||||||
|
right = merkle_recurse(base, arr + len / 2, len / 2);
|
||||||
|
/* left is never NULL if right is not NULL */
|
||||||
|
if (!right)
|
||||||
|
return left;
|
||||||
|
return merkle_pair(base, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is not the fastest way, but it is the most intuitive. */
|
||||||
void merkle_tlv(const struct tlv_field *fields, struct sha256 *merkle)
|
void merkle_tlv(const struct tlv_field *fields, struct sha256 *merkle)
|
||||||
{
|
{
|
||||||
struct sha256 lnall, *arr;
|
struct sha256 **arr;
|
||||||
|
struct sha256_ctx lnall_ctx;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
calc_lnall(fields, &lnall);
|
SUPERVERBOSE("nonce tag:");
|
||||||
arr = tal_arr(NULL, struct sha256, tal_count(fields));
|
h_lnall_ctx(&lnall_ctx, fields);
|
||||||
|
/* NULL-pad to next power of 2 */
|
||||||
|
arr = tal_arrz(NULL, struct sha256 *,
|
||||||
|
1ULL << (ilog64(tal_count(fields)) + 1));
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (size_t i = 0; i < tal_count(fields); i++) {
|
for (size_t i = 0; i < tal_count(fields); i++) {
|
||||||
struct sha256 s;
|
struct sha256 leaf, nonce;
|
||||||
if (is_signature_field(&fields[i]))
|
if (is_signature_field(&fields[i]))
|
||||||
continue;
|
continue;
|
||||||
calc_lnleaf(&fields[i], &s);
|
calc_lnleaf(&fields[i], &leaf);
|
||||||
arr[n++] = merkle_pair(s, lnall);
|
calc_nonce(&lnall_ctx, &fields[i], &nonce);
|
||||||
|
arr[n++] = merkle_pair(arr, &leaf, &nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This should never happen, but define it as lnall in this case */
|
/* This should never happen, but define it a distinctive all-zeroes */
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
*merkle = lnall;
|
memset(merkle, 0, sizeof(*merkle));
|
||||||
else
|
else
|
||||||
*merkle = merkle_recurse(arr, n);
|
*merkle = *merkle_recurse(cast_const2(const struct sha256 **, arr),
|
||||||
|
cast_const2(const struct sha256 **, arr),
|
||||||
|
tal_count(arr));
|
||||||
tal_free(arr);
|
tal_free(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BOLT-offers #12:
|
/* BOLT-offers #12:
|
||||||
* All signatures are created as per
|
* All signatures are created as per
|
||||||
* [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki),
|
* [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki),
|
||||||
* and tagged as recommended there. Thus to sign a message `msg` with
|
* and tagged as recommended there. Thus we define H(`tag`,`msg`) as
|
||||||
* `tag`, `m` is SHA256(SHA256(`tag`) || SHA256(`tag`) || `msg`). The
|
* SHA256(SHA256(`tag`) || SHA256(`tag`) || `msg`), and SIG(`tag`,`msg`,`key`)
|
||||||
* notation used here is `SIG(tag,msg,key)`.
|
* as the signature of H(`tag`,`msg`) using `key`.
|
||||||
*
|
*
|
||||||
* Each form is signed using one or more TLV signature elements; TLV
|
* Each form is signed using one or more TLV signature elements; TLV
|
||||||
* types 240 through 1000 are considered signature elements. For these
|
* types 240 through 1000 are considered signature elements. For these
|
||||||
|
@ -50,4 +50,19 @@ common/test/run-gossmap_local: \
|
|||||||
wire/peer$(EXP)_wiregen.o \
|
wire/peer$(EXP)_wiregen.o \
|
||||||
wire/towire.o
|
wire/towire.o
|
||||||
|
|
||||||
|
common/test/run-bolt12_merkle: \
|
||||||
|
common/amount.o \
|
||||||
|
common/bigsize.o \
|
||||||
|
common/bech32.o \
|
||||||
|
common/bech32_util.o \
|
||||||
|
common/bolt12.o \
|
||||||
|
common/node_id.o \
|
||||||
|
common/type_to_string.o \
|
||||||
|
wire/bolt12$(EXP)_wiregen.o \
|
||||||
|
wire/fromwire.o \
|
||||||
|
wire/tlvstream.o \
|
||||||
|
wire/peer$(EXP)_wiregen.o \
|
||||||
|
wire/towire.o
|
||||||
|
|
||||||
|
|
||||||
check-units: $(COMMON_TEST_PROGRAMS:%=unittest/%)
|
check-units: $(COMMON_TEST_PROGRAMS:%=unittest/%)
|
||||||
|
404
common/test/run-bolt12_merkle.c
Normal file
404
common/test/run-bolt12_merkle.c
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
#define SUPERVERBOSE printf
|
||||||
|
/* 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 <ccan/cast/cast.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
|
#include <common/features.h>
|
||||||
|
#include <common/setup.h>
|
||||||
|
#include <stdarg.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_channel_id */
|
||||||
|
void 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 fromwire_onionmsg_path */
|
||||||
|
struct onionmsg_path *fromwire_onionmsg_path(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
|
||||||
|
{ fprintf(stderr, "fromwire_onionmsg_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(); }
|
||||||
|
/* Generated stub for towire_onionmsg_path */
|
||||||
|
void towire_onionmsg_path(u8 **p UNNEEDED, const struct onionmsg_path *onionmsg_path UNNEEDED)
|
||||||
|
{ fprintf(stderr, "towire_onionmsg_path 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_n1(&v, n1);
|
||||||
|
|
||||||
|
len = tal_bytelen(v);
|
||||||
|
tmp = tlv_n1_new(tmpctx);
|
||||||
|
if (!fromwire_n1(cast_const2(const u8 **, &v), &len, tmp))
|
||||||
|
abort();
|
||||||
|
assert(len == 0);
|
||||||
|
|
||||||
|
merkle_tlv(tmp->fields, test_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As a bonus, you get the merkle-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, *LnAll, *LnLeaf;
|
||||||
|
u8 *tlv1, *tlv2, *tlv3, *all;
|
||||||
|
struct tlv_n1 *n1;
|
||||||
|
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);
|
||||||
|
LnAll = tal_dup_arr(tmpctx, char, "LnAll", strlen("LnAll"), 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. */
|
||||||
|
all = tlv1;
|
||||||
|
json_out("\"all-tlvs\": \"%s\",", tal_hex(tmpctx, all));
|
||||||
|
json_out("\"leaves\": [");
|
||||||
|
|
||||||
|
leaf[0] = H(LnBranch,
|
||||||
|
ordered(H(LnLeaf, tlv1),
|
||||||
|
H(concat(LnAll, all), tlv1)));
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv1)\": \"%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(LnAll, all), 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("},");
|
||||||
|
|
||||||
|
printf("n1 = %s, merkle = %s\n",
|
||||||
|
tal_hex(tmpctx, all),
|
||||||
|
type_to_string(tmpctx, struct sha256, m));
|
||||||
|
|
||||||
|
/* 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\",");
|
||||||
|
all = concat(tlv1, tlv2);
|
||||||
|
|
||||||
|
json_out("\"all-tlvs\": \"%s\",", tal_hex(tmpctx, all));
|
||||||
|
json_out("\"leaves\": [");
|
||||||
|
|
||||||
|
leaf[0] = H(LnBranch, ordered(H(LnLeaf, tlv1),
|
||||||
|
H(concat(LnAll, all), tlv1)));
|
||||||
|
leaf[1] = H(LnBranch, ordered(H(LnLeaf, tlv2),
|
||||||
|
H(concat(LnAll, all), tlv2)));
|
||||||
|
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv1)\": \"%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(LnAll, all), tlv1)),
|
||||||
|
type_to_string(tmpctx, struct sha256, leaf[0]));
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv2)\": \"%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(LnAll, all), 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("},");
|
||||||
|
|
||||||
|
printf("n1 = %s, merkle = %s\n",
|
||||||
|
tal_hex(tmpctx, all),
|
||||||
|
type_to_string(tmpctx, struct sha256, m));
|
||||||
|
|
||||||
|
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\",");
|
||||||
|
all = concat(tlv1, tlv2, tlv3);
|
||||||
|
json_out("\"all-tlvs\": \"%s\",", tal_hex(tmpctx, all));
|
||||||
|
json_out("\"leaves\": [");
|
||||||
|
|
||||||
|
leaf[0] = H(LnBranch, ordered(H(LnLeaf, tlv1),
|
||||||
|
H(concat(LnAll, all), tlv1)));
|
||||||
|
leaf[1] = H(LnBranch, ordered(H(LnLeaf, tlv2),
|
||||||
|
H(concat(LnAll, all), tlv2)));
|
||||||
|
leaf[2] = H(LnBranch, ordered(H(LnLeaf, tlv3),
|
||||||
|
H(concat(LnAll, all), tlv3)));
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv1)\": \"%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(LnAll, all), tlv1)),
|
||||||
|
type_to_string(tmpctx, struct sha256, leaf[0]));
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv2)\": \"%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(LnAll, all), tlv2)),
|
||||||
|
type_to_string(tmpctx, struct sha256, leaf[1]));
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv3)\": \"%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(LnAll, all), 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("},");
|
||||||
|
|
||||||
|
printf("n1 = %s, merkle = %s\n",
|
||||||
|
tal_hex(tmpctx, all),
|
||||||
|
type_to_string(tmpctx, struct sha256, m));
|
||||||
|
|
||||||
|
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 actual offer, with 6 fields. */
|
||||||
|
struct tlv_offer *offer = offer_decode(tmpctx,
|
||||||
|
"lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczs",
|
||||||
|
strlen("lno1qcp4256ypqpq86q2pucnq42ngssx2an9wfujqerp0y2pqun4wd68jtn00fkxzcnn9ehhyec6qgqsz83qfwdpl28qqmc78ymlvhmxcsywdk5wrjnj36jryg488qwlrnzyjczs"),
|
||||||
|
NULL, NULL, &fail);
|
||||||
|
|
||||||
|
assert(tal_count(offer->fields) == 6);
|
||||||
|
u8 *fieldwires[6];
|
||||||
|
|
||||||
|
/* currency: USD */
|
||||||
|
fieldwires[0] = tlv(6, "USD", strlen("USD"));
|
||||||
|
/* amount: 1000 */
|
||||||
|
fieldwires[1] = tlv(8, "\x03\xe8", 2);
|
||||||
|
/* description: 10USD every day */
|
||||||
|
fieldwires[2] = tlv(10, "10USD every day", strlen("10USD every day"));
|
||||||
|
/* vendor: rusty.ozlabs.org */
|
||||||
|
fieldwires[3] = tlv(20, "rusty.ozlabs.org", strlen("rusty.ozlabs.org"));
|
||||||
|
/* recurrence: time_unit = 1, period = 1 */
|
||||||
|
fieldwires[4] = tlv(26, "\x01\x01", 2);
|
||||||
|
/* node_id: 4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605 */
|
||||||
|
fieldwires[5] = tlv(30, "\x4b\x9a\x1f\xa8\xe0\x06\xf1\xe3\x93\x7f\x65\xf6\x6c\x40\x8e\x6d\xa8\xe1\xca\x72\x8e\xa4\x32\x22\xa7\x38\x1d\xf1\xcc\x44\x96\x05", 32);
|
||||||
|
|
||||||
|
json_out("{\"comment\": \"offer test, currency = USD, amount = 1000, description = 10USD every day, vendor = rusty.ozlabs.org, recurrence = time_unit = 1, period = 1, node_id = 4b9a1fa8e006f1e3937f65f66c408e6da8e1ca728ea43222a7381df1cc449605\",");
|
||||||
|
json_out("\"tlv\": \"offer\",");
|
||||||
|
|
||||||
|
all = concat(fieldwires[0], fieldwires[1], fieldwires[2],
|
||||||
|
fieldwires[3], fieldwires[4], fieldwires[5]);
|
||||||
|
json_out("\"all-tlvs\": \"%s\",", tal_hex(tmpctx, all));
|
||||||
|
|
||||||
|
json_out("\"leaves\": [");
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(fieldwires); i++) {
|
||||||
|
leaf[i] = H(LnBranch,
|
||||||
|
ordered(H(LnLeaf, fieldwires[i]),
|
||||||
|
H(concat(LnAll, all), fieldwires[i])));
|
||||||
|
json_out("{ \"H(`LnLeaf`,%s)\": \"%s\", \"H(`LnAll`|all-tlvs,tlv)\": \"%s\", \"H(`LnBranch`,leaf+nonce)\": \"%s\" }%s",
|
||||||
|
tal_hex(tmpctx, fieldwires[i]),
|
||||||
|
type_to_string(tmpctx, struct sha256,
|
||||||
|
H(LnLeaf, fieldwires[i])),
|
||||||
|
type_to_string(tmpctx, struct sha256,
|
||||||
|
H(concat(LnAll, all), fieldwires[0])),
|
||||||
|
type_to_string(tmpctx, struct sha256, leaf[i]),
|
||||||
|
i == ARRAY_SIZE(fieldwires) - 1 ? "" : ",");
|
||||||
|
}
|
||||||
|
json_out("],");
|
||||||
|
|
||||||
|
json_out("\"branches\": [");
|
||||||
|
json_out("{ \"desc\": \"1: currency+nonce and amount+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: description+nonce and vendor+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: recurrence+nonce and node_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]))))));
|
||||||
|
json_out("],");
|
||||||
|
json_out("\"merkle\": \"%s\"",
|
||||||
|
type_to_string(tmpctx, struct sha256, m));
|
||||||
|
json_out("}]");
|
||||||
|
|
||||||
|
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]))));
|
||||||
|
printf("offer = %s, merkle = %s\n",
|
||||||
|
tal_hex(tmpctx, all),
|
||||||
|
type_to_string(tmpctx, struct sha256, m));
|
||||||
|
|
||||||
|
merkle_tlv(offer->fields, &test_m);
|
||||||
|
assert(sha256_eq(&test_m, m));
|
||||||
|
|
||||||
|
common_shutdown();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user