/* Generate BOLT 12 payer proof test vectors with full intermediate steps.
 * Output is JSON - pipe through jq for pretty-printing.
 */
#include "config.h"
#include <ccan/err/err.h>
#include <stdio.h>
#include "../bech32.c"
#include "../bech32_util.c"
#include "../bolt12_merkle.c"
#include "../bolt12_proof.c"
#include "../features.c"
#include <ccan/array_size/array_size.h>
#include <ccan/str/str.h>
#include <common/features.h>
#include <common/setup.h>
#include <secp256k1_schnorrsig.h>

/* AUTOGENERATED MOCKS START */
/* Generated stub for pubkey_from_node_id */
bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); }
/* Generated stub for siphash_seed */
const struct siphash_seed *siphash_seed(void)
{ fprintf(stderr, "siphash_seed called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */

static struct pubkey *pubkey_for_letter(const tal_t *ctx, char letter, const char *name)
{
	struct secret secret;
	struct pubkey *pk;

	pk = tal(ctx, struct pubkey);
	memset(&secret, letter, sizeof(secret));
	assert(pubkey_from_secret(&secret, pk));

	if (name) {
		printf("\"%s\":{\"secret\":\"%s\",\"pubkey\":\"%s\"}",
		       name,
		       tal_hexstr(tmpctx, secret.data, sizeof(secret.data)),
		       fmt_pubkey(tmpctx, pk));
	}
	return pk;
}

static secp256k1_keypair keypair_for_letter(char letter)
{
	struct secret secret;
	secp256k1_keypair kp;

	memset(&secret, letter, sizeof(secret));
	if (secp256k1_keypair_create(secp256k1_ctx, &kp, secret.data) != 1)
		abort();
	return kp;
}

static struct bip340sig *invoice_signature(const tal_t *ctx,
					   struct tlv_invoice *inv,
					   char letter)
{
	struct sha256 merkle, sha;
	struct bip340sig *sig;
	secp256k1_keypair kp = keypair_for_letter(letter);

	tlv_update_fields(inv, tlv_invoice, &inv->fields);
	merkle_tlv(inv->fields, &merkle);
	inv->signature = tal(inv, struct bip340sig);
	sighash_from_merkle("invoice", "signature", &merkle, &sha);

	sig = tal(ctx, struct bip340sig);
	assert(secp256k1_schnorrsig_sign32(secp256k1_ctx, sig->u8,
					   sha.u.u8, &kp, NULL) == 1);
	return sig;
}

static bool sign_payer(const char *messagename UNNEEDED,
		       const char *fieldname UNNEEDED,
		       const struct sha256 *msg,
		       struct bip340sig *sig,
		       secp256k1_keypair *kp)
{
	struct sha256 shash;
	sighash_from_merkle("payer_proof", "proof_signature", msg, &shash);
	return secp256k1_schnorrsig_sign32(secp256k1_ctx, sig->u8,
					   shash.u.u8, kp, NULL) == 1;
}

/* include_all: include every non-signature field (type 0 cannot be in payer proof TLV) */
static bool include_all(const struct tlv_field *f, void *arg UNNEEDED)
{
	return f->numtype != 0;
}

/* include_minimal: only invreq_payer_id, invoice_payment_hash, invoice_node_id */
static bool include_minimal(const struct tlv_field *f, void *arg UNNEEDED)
{
	return f->numtype == TLV_PAYER_PROOF_INVREQ_PAYER_ID
		|| f->numtype == TLV_PAYER_PROOF_INVOICE_PAYMENT_HASH
		|| f->numtype == TLV_PAYER_PROOF_INVOICE_FEATURES
		|| f->numtype == TLV_PAYER_PROOF_INVOICE_NODE_ID;
}

/* include_amount: invreq_payer_id, invoice_payment_hash, invoice_node_id
 * *and* invoice_amount.  This demonstrates the case where
 * proof_missing_hashes are NOT in ascending-type order: the left pair
 * [type0,type22] is entirely omitted, so its subtree hash is appended *after*
 * the hash for type82 (which shares the same 4-leaf subtree).  The DFS
 * traversal resolves the right child (type82) before bubbling up to resolve
 * the left (type0+22).
 */
static bool include_amount(const struct tlv_field *f, void *arg UNNEEDED)
{
	return include_minimal(f, arg)
		|| f->numtype == TLV_PAYER_PROOF_INVOICE_AMOUNT;
}

static void print_fields_json(const struct tlv_field *fields, size_t n,
			      bool (*include_field)(const struct tlv_field *, void *),
			      void *arg)
{
	for (size_t i = 0; i < n; i++) {
		const struct tlv_field *f = &fields[i];
		if (include_field != NULL) {
			bool included = !is_tlv_signature_field(f)
				&& include_field(f, arg);
			printf("{\"type\":%"PRIu64",\"len\":%zu,\"hex\":\"%s\",\"included\":%s}%s\n",
			       f->numtype, f->length,
			       tal_hexstr(tmpctx, f->value, f->length),
			       included ? "true" : "false",
			       i + 1 < n ? "," : "");
		} else {
			printf("{\"type\":%"PRIu64",\"len\":%zu,\"hex\":\"%s\"}%s\n",
			       f->numtype, f->length,
			       tal_hexstr(tmpctx, f->value, f->length),
			       i + 1 < n ? "," : "");
		}
	}
}

static void print_hashes_json(const struct sha256 *hashes, size_t n)
{
	for (size_t i = 0; i < n; i++) {
		printf("\"%s\"%s\n",
		       fmt_sha256(tmpctx, &hashes[i]),
		       i + 1 < n ? "," : "");
	}
}

static void print_bigsize_array(const bigsize_t *arr, size_t n)
{
	for (size_t i = 0; i < n; i++) {
		printf("%"PRIu64"%s\n", arr[i], i + 1 < n ? "," : "");
	}
}

static void generate_valid_vector(const char *name,
				  struct tlv_invoice *inv,
				  const struct preimage *preimage,
				  char payer_letter,
				  const char *note,
				  bool (*include_field)(const struct tlv_field *, void *),
				  bool explicit_empty_omitted)
{
	struct sha256 mroot, pproot, shash;
	struct tlv_payer_proof *proof;
	secp256k1_keypair kp = keypair_for_letter(payer_letter);
	u8 *invoice_wire;

	invoice_wire = tal_arr(tmpctx, u8, 0);
	towire_tlv_invoice(&invoice_wire, inv);

	merkle_tlv(inv->fields, &mroot);
	sighash_from_merkle("invoice", "signature", &mroot, &shash);
	proof = make_unsigned_proof(tmpctx, inv, preimage, note, include_field, NULL);
	/* Force proof_omitted_tlvs to be present-but-empty rather than absent,
	 * then refresh fields so payer_proof_signature signs the updated merkle. */
	if (explicit_empty_omitted) {
		proof->proof_omitted_tlvs = tal_arr(proof, bigsize_t, 0);
		tlv_update_fields(proof, tlv_payer_proof, &proof->fields);
	}
	proof->proof_signature = payer_proof_signature(proof, proof, sign_payer, &kp);
	assert(proof->proof_signature);
	/* Refresh fields to include proof_signature */
	tlv_update_fields(proof, tlv_payer_proof, &proof->fields);

	bolt12_payer_proof_merkle(proof, &pproot);

	printf("{\n");
	printf("\"name\":\"%s\",\n", name);

	printf("\"input\":{\n");
	printf("\"invoice\":\"%s\",\n", invoice_encode(tmpctx, inv));
	printf("\"invoice_hex\":\"%s\",\n",
	       tal_hexstr(tmpctx, invoice_wire, tal_bytelen(invoice_wire)));
	printf("\"preimage\":\"%s\",\n",
	       tal_hexstr(tmpctx, preimage->r, sizeof(preimage->r)));
	if (note)
		printf("\"note\":\"%s\",\n", note);
	printf("\"invoice_fields\":[\n");
	print_fields_json(inv->fields, tal_count(inv->fields), include_field, NULL);
	printf("]\n");
	printf("},\n");

	printf("\"working\":{\n");
	printf("\"invoice_merkle_root\":\"%s\",\n", fmt_sha256(tmpctx, &mroot));
	printf("\"invoice_sighash\":\"%s\",\n", fmt_sha256(tmpctx, &shash));
	printf("\"invoice_signature\":\"%s\",\n",
	       tal_hexstr(tmpctx, inv->signature->u8, sizeof(inv->signature->u8)));
	printf("\"proof_merkle_root\":\"%s\",\n", fmt_sha256(tmpctx, &pproot));
	printf("\"proof_leaf_hashes\":[\n");
	print_hashes_json(proof->proof_leaf_hashes, tal_count(proof->proof_leaf_hashes));
	printf("],\n");
	printf("\"proof_omitted_tlvs\":[\n");
	print_bigsize_array(proof->proof_omitted_tlvs, tal_count(proof->proof_omitted_tlvs));
	printf("],\n");
	printf("\"proof_missing_hashes\":[\n");
	print_hashes_json(proof->proof_missing_hashes, tal_count(proof->proof_missing_hashes));
	printf("]\n");
	printf("},\n");

	printf("\"result\":{\n");
	printf("\"payer_sig\":\"%s\",\n",
	       fmt_bip340sig(tmpctx, proof->proof_signature));
	printf("\"proof_fields\":[\n");
	print_fields_json(proof->fields, tal_count(proof->fields), NULL, NULL);
	printf("],\n");
	const char *bech32 = payer_proof_encode(tmpctx, proof);
	printf("\"bech32\":\"%s\"\n", bech32);
	printf("}\n");

	/* Verify round-trip: decode calls check_payer_proof internally */
	{
		const char *fail;
		if (!payer_proof_decode(tmpctx, bech32, strlen(bech32), &fail))
			abort();
	}

	printf("}");
}

/* Build a fresh minimal proof (used as base for invalid vectors). */
static struct tlv_payer_proof *make_minimal_proof(struct tlv_invoice *inv,
						  const struct preimage *preimage)
{
	return make_unsigned_proof(tmpctx, inv, preimage, NULL,
				    include_minimal, NULL);
}

static void emit_invalid(bool *first, const char *reason,
			 secp256k1_keypair *kp,
			 struct tlv_payer_proof *proof)
{
	if (!*first)
		printf(",\n");
	*first = false;
	/* Signature should be valid (we omit it for one test though) */
	if (kp) {
		proof->proof_signature = payer_proof_signature(proof, proof,
							       sign_payer, kp);
		assert(proof->proof_signature);
	}
	printf("{\"reason\":\"%s\",\"bech32\":\"%s\"}",
	       reason, payer_proof_encode(tmpctx, proof));
}

static void generate_invalid_vectors(struct tlv_invoice *inv,
				     const struct preimage *preimage)
{
	struct tlv_payer_proof *proof;
	secp256k1_keypair kp = keypair_for_letter('B');
	bool first = true;
	struct sha256 zero_hash;

	memset(&zero_hash, 0, sizeof(zero_hash));

/* Fresh minimal proof, then apply corruption before signing. */
#define CORRUPT(reason, ...) do {			\
	proof = make_minimal_proof(inv, preimage);	\
	{ __VA_ARGS__ }					\
	emit_invalid(&first, reason, &kp, proof);	\
} while(0)

/* Fresh minimal proof, then apply corruption after signing. */
#define CORRUPT_AFTER_SIG(reason, ...) do {				\
	proof = make_minimal_proof(inv, preimage);			\
	proof->proof_signature = payer_proof_signature(proof, proof,	\
						       sign_payer, &kp); \
	assert(proof->proof_signature);					\
	{ __VA_ARGS__ }							\
	emit_invalid(&first, reason, NULL, proof);			\
} while(0)

	/* BOLT-payer_proof #12: MUST reject the payer_proof if:
	 * - `invreq_payer_id`, `invoice_payment_hash`, `invoice_node_id`,
         *   `signature`, `proof_preimage`, `proof_missing_hashes`,
         *   `proof_leaf_hashes` or `proof_signature` are missing.
	 */
	CORRUPT_AFTER_SIG("missing_invreq_payer_id",
			  proof->invreq_payer_id = NULL;);
	CORRUPT("missing_invoice_payment_hash",
		proof->invoice_payment_hash = NULL;);
	CORRUPT("missing_invoice_node_id",
		proof->invoice_node_id = NULL;);
	CORRUPT("missing_signature",
		proof->signature = NULL;);
	CORRUPT("missing_proof_preimage",
		proof->proof_preimage = NULL;);
	CORRUPT("missing_proof_missing_hashes",
		proof->proof_missing_hashes = NULL;);
	CORRUPT("missing_proof_leaf_hashes",
		proof->proof_leaf_hashes = NULL;);
	CORRUPT_AFTER_SIG("missing_proof_signature",
			  proof->proof_signature = NULL;);

	/* BOLT-payer_proof #12:
	 * ... - SHA256(`proof_preimage`) does not equal `invoice_payment_hash`. */
	CORRUPT("wrong_proof_preimage", {
		proof->proof_preimage = talz(proof, struct preimage);
	});

	/* BOLT-payer_proof #12:
	 * ... - `proof_omitted_tlvs` are not in strict ascending order (no duplicates). */
	CORRUPT("proof_omitted_tlvs_not_ascending", {
		/* Swap last two entries: [1,2,89,90,91,169] -> [1,2,89,90,169,91] */
		size_t n = tal_count(proof->proof_omitted_tlvs);
		assert(n >= 2);
		bigsize_t tmp = proof->proof_omitted_tlvs[n-1];
		proof->proof_omitted_tlvs[n-1] = proof->proof_omitted_tlvs[n-2];
		proof->proof_omitted_tlvs[n-2] = tmp;
	});

	/* BOLT-payer_proof #12:
	 * ... - `proof_omitted_tlvs` contains 0.
	 */
	CORRUPT("proof_omitted_tlvs_contains_zero", {
		size_t n = tal_count(proof->proof_omitted_tlvs);
		bigsize_t *new = tal_arr(proof, bigsize_t, n + 1);
		new[0] = 0;
		memcpy(new + 1, proof->proof_omitted_tlvs, n * sizeof(bigsize_t));
		proof->proof_omitted_tlvs = new;
	});

	/* BOLT-payer_proof #12:
	 *... - `proof_omitted_tlvs` contains number outside both ranges 1 to
	 *       239 and 1000000000 to 3999999999. */
	CORRUPT("proof_omitted_tlvs_contains_signature_field",
		/* Append 241 (a signature field); sig-field check precedes sequential check */
		tal_arr_expand(&proof->proof_omitted_tlvs, 241););
	CORRUPT("proof_omitted_tlvs_contains_proof_field",
		/* Append 1001 (a proof field); sig-field check precedes sequential check */
		tal_arr_expand(&proof->proof_omitted_tlvs, 1001););
	CORRUPT("proof_omitted_tlvs_contains_high_field",
		/* Append 1001 (a proof field); sig-field check precedes sequential check */
		tal_arr_expand(&proof->proof_omitted_tlvs, 4000000000ULL););

	/* BOLT-payer_proof #12:
	 *... - `proof_omitted_tlvs` contains the number of an included TLV field.
	 */
	CORRUPT("proof_omitted_tlvs_contains_included_tlv_field",
		/* invreq_payer_id (88) is included; omitted_tlvs[2]=89 > 88 */
		assert(proof->invreq_payer_id);
		assert(proof->proof_omitted_tlvs[2] > TLV_PAYER_PROOF_INVREQ_PAYER_ID);
		tal_arr_insert(&proof->proof_omitted_tlvs, 2, TLV_PAYER_PROOF_INVREQ_PAYER_ID););


	/* BOLT-payer_proof #12:
	 * ...
	 *  - `proof_omitted_tlvs` is not one greater than:
	 *     - an included TLV number, or
	 *     - the previous `proof_omitted_tlvs` or 0 if it is the first number.
	 */
	CORRUPT("proof_omitted_tlvs_not_sequential", {
		/* Replace 91 with 100: [1,2,89,90,100,169]; 100 != 90+1 and 99 not included */
		size_t n = tal_count(proof->proof_omitted_tlvs);
		assert(n >= 5);
		proof->proof_omitted_tlvs[n-3] = 100;
		/* Also fix up subsequent entry to maintain ascending order */
		proof->proof_omitted_tlvs[n-2] = 101;
		proof->proof_omitted_tlvs[n-1] = 102;
	});

	/* BOLT-payer_proof #12:
	 *...
	 * - `proof_leaf_hashes` does not contain exactly one hash for each
	 *    non-signature TLV field.
	 */
	CORRUPT("proof_leaf_hashes_too_few", {
		size_t n = tal_count(proof->proof_leaf_hashes);
		assert(n >= 1);
		tal_resize(&proof->proof_leaf_hashes, n - 1);
	});
	CORRUPT("proof_leaf_hashes_too_many",
		tal_arr_expand(&proof->proof_leaf_hashes, zero_hash););

	/* BOLT-payer_proof #12:
	 * ...
	 * - There are not exactly enough `proof_missing_hashes` to
         *   reconstruct the merkle tree root using the `proof_omitted_tlvs`
         *   values (with `0` implied as the first omitted TLV).
	 */
	CORRUPT("proof_missing_hashes_too_few", {
		size_t n = tal_count(proof->proof_missing_hashes);
		assert(n >= 1);
		tal_resize(&proof->proof_missing_hashes, n - 1);
	});
	CORRUPT("proof_missing_hashes_too_many",
		tal_arr_expand(&proof->proof_missing_hashes, zero_hash););

	/* BOLT-payer_proof #12:
	 * ...
	 * - `signature` is not a valid signature using `invoice_node_id` as
	 *   described in [Signature Calculation](#signature-calculation) (with
	 *   `messagename` "invoice") of the reconstructed merkle-root of the
	 *   invoice (i.e. without fields 1001 through 999999999 inclusive).
	 */
	CORRUPT("wrong_invoice_signature",
		proof->signature->u8[0] ^= 1;);

	/* BOLT-payer_proof #12:
	 * ...
	 * - `proof_signature` is not a valid signature using
	 *   `invreq_payer_id` as described in [Signature
	 *   Calculation](#signature-calculation), using `msg` merkle-root and
	 *   a `first_tlv` value of 0x0000 (i.e. type 0, length 0).
	 */
	CORRUPT_AFTER_SIG("wrong_proof_signature",
			  proof->proof_signature->u8[0] ^= 1;);

	/* BOLT-payer_proof #12:
	 * A writer of a payer_proof:
	 * - MUST NOT include `invreq_metadata`.
	 */
	/* This is not an explicit reader requirement: it comes under the
	 * "unknown even" rule */
	{
		const char *fail;
		const u8 *data;
		size_t dlen;
		u8 *wire;
		struct tlv_payer_proof *p = make_minimal_proof(inv, preimage);
		p->proof_signature = payer_proof_signature(p, p, sign_payer, &kp);
		assert(p->proof_signature);
		/* Prepend a type-0 TLV (type=0, len=1, value=0x42) to the wire. */
		wire = tal_arr(tmpctx, u8, 0);
		towire_bigsize(&wire, 0);
		towire_bigsize(&wire, 1);
		towire(&wire, (u8[]){0x42}, 1);
		data = b12_string_to_data(tmpctx, payer_proof_encode(tmpctx, p),
					  strlen(payer_proof_encode(tmpctx, p)),
					  "lnp", &dlen, &fail);
		assert(data);
		towire(&wire, data, dlen);
		if (!first)
			printf(",\n");
		first = false;
		printf("{\"reason\":\"contains_invreq_metadata\",\"bech32\":\"%s\"}",
		       to_bech32_charset(tmpctx, "lnp", wire));
	}

#undef CORRUPT
}

int main(int argc, char *argv[])
{
	struct tlv_invoice *inv;
	struct preimage preimage;
	const char *invstr, *fail;

	common_setup(argv[0]);

	memset(&preimage, 0x1, sizeof(preimage));

	printf("{\n");
	printf("\"payer_secret\":\"%s\",\n",
	       tal_hexstr(tmpctx, (u8[32]){[0 ... 31] = 'B'}, 32));

	/* Build a minimal invoice with known keys (letters A-F).
	 * offer_issuer_id must equal invoice_node_id (both use key 'F'). */
	inv = tlv_invoice_new(tmpctx);
	inv->invreq_metadata = tal_arrz(inv, u8, 16);
	printf("\"keys\":{");
	inv->offer_issuer_id = pubkey_for_letter(inv, 'F', "offer_issuer_id");
	printf(",");
	inv->invreq_amount = tal(inv, u64);
	*inv->invreq_amount = 1000;
	inv->invreq_payer_id = pubkey_for_letter(inv, 'B', "invreq_payer_id");
	printf(",");

	inv->invoice_paths = tal_arr(inv, struct blinded_path *, 1);
	inv->invoice_paths[0] = tal(inv->invoice_paths, struct blinded_path);
	sciddir_or_pubkey_from_pubkey(&inv->invoice_paths[0]->first_node_id,
				      pubkey_for_letter(tmpctx, 'C', "first_node_id"));
	printf(",");
	inv->invoice_paths[0]->first_path_key = *pubkey_for_letter(tmpctx, 'D', "first_path_key");
	printf(",");
	inv->invoice_paths[0]->path = tal_arr(inv->invoice_paths[0],
					      struct blinded_path_hop *, 1);
	inv->invoice_paths[0]->path[0] = tal(inv->invoice_paths[0]->path,
					     struct blinded_path_hop);
	inv->invoice_paths[0]->path[0]->blinded_node_id = *pubkey_for_letter(tmpctx, 'E', "blinded_node_id");
	printf(",");
	inv->invoice_paths[0]->path[0]->encrypted_recipient_data =
		tal_arrz(inv->invoice_paths[0]->path[0], u8, 16);
	inv->invoice_blindedpay = tal_arr(inv, struct blinded_payinfo *, 1);
	inv->invoice_blindedpay[0] = tal(inv->invoice_blindedpay, struct blinded_payinfo);
	inv->invoice_blindedpay[0]->fee_base_msat = 1;
	inv->invoice_blindedpay[0]->fee_proportional_millionths = 2;
	inv->invoice_blindedpay[0]->cltv_expiry_delta = 3;
	inv->invoice_blindedpay[0]->htlc_minimum_msat = AMOUNT_MSAT(4);
	inv->invoice_blindedpay[0]->htlc_maximum_msat = AMOUNT_MSAT(5);
	inv->invoice_blindedpay[0]->features = NULL;

	inv->invoice_created_at = tal(inv, u64);
	*inv->invoice_created_at = 1733458312;
	inv->invoice_payment_hash = tal(inv, struct sha256);
	sha256(inv->invoice_payment_hash, &preimage, sizeof(preimage));
	inv->invoice_amount = tal(inv, u64);
	*inv->invoice_amount = 1000;
	/* invoice_features present (undefined bit 99) to exercise the include_all
	 * path and the "must include if present" writer requirement. */
	inv->invoice_features = tal_arr(inv, u8, 0);
	set_feature_bit(&inv->invoice_features, 99);
	inv->invoice_node_id = pubkey_for_letter(inv, 'F', "invoice_node_id");
	printf("},\n");

	/* Add experimental field type 3000000001 (non-signature, ignorable). */
	{
		struct tlv_field f;
		f.meta = NULL;
		f.numtype = 3000000001ULL;
		f.value = tal_arr(inv, u8, 1);
		f.value[0] = 0x42;
		f.length = 1;
		tlv_update_fields(inv, tlv_invoice, &inv->fields);
		tal_arr_expand(&inv->fields, f);
	}

	inv->signature = invoice_signature(inv, inv, 'F');

	/* Canonicalize via encode/decode */
	invstr = invoice_encode(tmpctx, inv);
	inv = invoice_decode(tmpctx, invstr, strlen(invstr), NULL, NULL, &fail);
	assert(inv);

	printf("\"valid_vectors\":[\n");
	generate_valid_vector("full_disclosure", inv, &preimage, 'B', NULL, include_all, false);
	printf(",\n");
	/* For the rest, remove features and experimental field: keep it vanilla */
	inv->invoice_features = tal_free(inv->invoice_features);
	tal_arr_remove(&inv->fields, tal_count(inv->fields)-1);

	/* Re-sign (invoice_signature calls tlv_update_fields, dropping the
	 * now-absent features and experimental entries) then canonicalize. */
	inv->signature = invoice_signature(inv, inv, 'F');
	invstr = invoice_encode(tmpctx, inv);
	inv = invoice_decode(tmpctx, invstr, strlen(invstr), NULL, NULL, &fail);
	assert(inv);

	generate_valid_vector("minimal_disclosure", inv, &preimage, 'B', NULL,
			      include_minimal, false);
	printf(",\n");
	generate_valid_vector("with_note", inv, &preimage, 'B', "test note",
			      include_minimal, false);
	printf(",\n");
	/* This vector demonstrates that proof_missing_hashes are in DFS (left-to-right
	 * tree traversal) order, NOT ascending by TLV type.  The pair [type0,type22]
	 * is entirely omitted, so its subtree hash appears in proof_missing_hashes AFTER
	 * the hash for the adjacent type82 leaf (which shares the same 4-leaf subtree
	 * and is resolved first during DFS). */
	generate_valid_vector("left_subtree_omitted", inv, &preimage, 'B', NULL,
			      include_amount, false);
	printf(",\n");
	/* This vector demonstrates that proof_omitted_tlvs present with length 0 is
	 * accepted identically to the field being absent.  The spec says writers MAY
	 * omit the field when empty, so readers must accept both forms. */
	generate_valid_vector("empty_proof_omitted_tlvs_explicit", inv, &preimage, 'B', NULL,
			      include_all, true);
	printf("\n],\n");

	printf("\"invalid_vectors\":[\n");
	generate_invalid_vectors(inv, &preimage);
	printf("\n]\n");

	printf("}\n");

	common_shutdown();
	return 0;
}
