bolt12-utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/bech32.d.ts +31 -0
  2. package/dist/bech32.d.ts.map +1 -0
  3. package/dist/bech32.js +161 -0
  4. package/dist/bech32.js.map +1 -0
  5. package/dist/bigsize.d.ts +22 -0
  6. package/dist/bigsize.d.ts.map +1 -0
  7. package/dist/bigsize.js +87 -0
  8. package/dist/bigsize.js.map +1 -0
  9. package/dist/fields.d.ts +61 -0
  10. package/dist/fields.d.ts.map +1 -0
  11. package/dist/fields.js +99 -0
  12. package/dist/fields.js.map +1 -0
  13. package/dist/generated.d.ts +179 -0
  14. package/dist/generated.d.ts.map +1 -0
  15. package/dist/generated.js +565 -0
  16. package/dist/generated.js.map +1 -0
  17. package/dist/index.d.ts +47 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +125 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/merkle.d.ts +55 -0
  22. package/dist/merkle.d.ts.map +1 -0
  23. package/dist/merkle.js +144 -0
  24. package/dist/merkle.js.map +1 -0
  25. package/dist/offer.d.ts +45 -0
  26. package/dist/offer.d.ts.map +1 -0
  27. package/dist/offer.js +288 -0
  28. package/dist/offer.js.map +1 -0
  29. package/dist/payer_proof.d.ts +89 -0
  30. package/dist/payer_proof.d.ts.map +1 -0
  31. package/dist/payer_proof.js +576 -0
  32. package/dist/payer_proof.js.map +1 -0
  33. package/dist/tlv.d.ts +26 -0
  34. package/dist/tlv.d.ts.map +1 -0
  35. package/dist/tlv.js +65 -0
  36. package/dist/tlv.js.map +1 -0
  37. package/dist/utils.d.ts +12 -0
  38. package/dist/utils.d.ts.map +1 -0
  39. package/dist/utils.js +52 -0
  40. package/dist/utils.js.map +1 -0
  41. package/package.json +47 -0
  42. package/src/bech32.ts +187 -0
  43. package/src/bigsize.ts +97 -0
  44. package/src/fields.ts +147 -0
  45. package/src/generated.ts +697 -0
  46. package/src/index.ts +132 -0
  47. package/src/merkle.ts +163 -0
  48. package/src/offer.ts +328 -0
  49. package/src/payer_proof.ts +727 -0
  50. package/src/tlv.ts +75 -0
  51. package/src/utils.ts +49 -0
package/dist/index.js ADDED
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * bolt12-decoder: Pure JS/TS BOLT12 implementation.
4
+ *
5
+ * Supports decoding and validating BOLT12 offers, invoice requests,
6
+ * and invoices using only pure JavaScript dependencies:
7
+ * - @noble/curves for secp256k1/schnorr
8
+ * - @noble/hashes for SHA256
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.INVOICE_CREATED_AT = exports.INVOICE_BLINDEDPAY = exports.INVOICE_PATHS = exports.SIGNATURE = exports.INVREQ_BIP_353_NAME = exports.INVREQ_PATHS = exports.INVREQ_PAYER_NOTE = exports.INVREQ_PAYER_ID = exports.INVREQ_QUANTITY = exports.INVREQ_FEATURES = exports.INVREQ_AMOUNT = exports.INVREQ_CHAIN = exports.INVREQ_METADATA = exports.OFFER_ISSUER_ID = exports.OFFER_QUANTITY_MAX = exports.OFFER_ISSUER = exports.OFFER_PATHS = exports.OFFER_ABSOLUTE_EXPIRY = exports.OFFER_FEATURES = exports.OFFER_DESCRIPTION = exports.OFFER_AMOUNT = exports.OFFER_CURRENCY = exports.OFFER_METADATA = exports.OFFER_CHAINS = exports.INVOICE_ERROR_TLV_NAMES = exports.KNOWN_INVOICE_ERROR_TYPES = exports.extractInvoiceErrorFields = exports.INVOICE_TLV_NAMES = exports.KNOWN_INVOICE_TYPES = exports.extractInvoiceFields = exports.INVOICE_REQUEST_TLV_NAMES = exports.KNOWN_INVOICE_REQUEST_TYPES = exports.extractInvoiceRequestFields = exports.OFFER_TLV_NAMES = exports.KNOWN_OFFER_TYPES = exports.extractGeneratedOfferFields = exports.createPayerProof = exports.verifyPayerProof = exports.reconstructMerkleRoot = exports.parsePayerProof = exports.extractOfferFields = exports.validateOffer = exports.verifySignature = exports.taggedHash = exports.computeMerkleRoot = exports.parseTlvStream = exports.writeBigSize = exports.readBigSize = exports.encodeBolt12 = exports.decodeBolt12 = void 0;
12
+ exports.INVOICE_NODE_ID = exports.INVOICE_FEATURES = exports.INVOICE_FALLBACKS = exports.INVOICE_AMOUNT = exports.INVOICE_PAYMENT_HASH = exports.INVOICE_RELATIVE_EXPIRY = void 0;
13
+ exports.decodeOffer = decodeOffer;
14
+ exports.decodePayerProof = decodePayerProof;
15
+ var bech32_js_1 = require("./bech32.js");
16
+ Object.defineProperty(exports, "decodeBolt12", { enumerable: true, get: function () { return bech32_js_1.decodeBolt12; } });
17
+ Object.defineProperty(exports, "encodeBolt12", { enumerable: true, get: function () { return bech32_js_1.encodeBolt12; } });
18
+ var bigsize_js_1 = require("./bigsize.js");
19
+ Object.defineProperty(exports, "readBigSize", { enumerable: true, get: function () { return bigsize_js_1.readBigSize; } });
20
+ Object.defineProperty(exports, "writeBigSize", { enumerable: true, get: function () { return bigsize_js_1.writeBigSize; } });
21
+ var tlv_js_1 = require("./tlv.js");
22
+ Object.defineProperty(exports, "parseTlvStream", { enumerable: true, get: function () { return tlv_js_1.parseTlvStream; } });
23
+ var merkle_js_1 = require("./merkle.js");
24
+ Object.defineProperty(exports, "computeMerkleRoot", { enumerable: true, get: function () { return merkle_js_1.computeMerkleRoot; } });
25
+ Object.defineProperty(exports, "taggedHash", { enumerable: true, get: function () { return merkle_js_1.taggedHash; } });
26
+ Object.defineProperty(exports, "verifySignature", { enumerable: true, get: function () { return merkle_js_1.verifySignature; } });
27
+ var offer_js_1 = require("./offer.js");
28
+ Object.defineProperty(exports, "validateOffer", { enumerable: true, get: function () { return offer_js_1.validateOffer; } });
29
+ /**
30
+ * @deprecated Use `extractGeneratedOfferFields` and `GeneratedOfferFields` from
31
+ * the auto-generated module instead. These hand-written exports use non-spec
32
+ * field names (e.g. `description` instead of `offer_description`) and only
33
+ * cover offers — the generated module covers all BOLT12 message types.
34
+ */
35
+ var fields_js_1 = require("./fields.js");
36
+ Object.defineProperty(exports, "extractOfferFields", { enumerable: true, get: function () { return fields_js_1.extractOfferFields; } });
37
+ var payer_proof_js_1 = require("./payer_proof.js");
38
+ Object.defineProperty(exports, "parsePayerProof", { enumerable: true, get: function () { return payer_proof_js_1.parsePayerProof; } });
39
+ Object.defineProperty(exports, "reconstructMerkleRoot", { enumerable: true, get: function () { return payer_proof_js_1.reconstructMerkleRoot; } });
40
+ Object.defineProperty(exports, "verifyPayerProof", { enumerable: true, get: function () { return payer_proof_js_1.verifyPayerProof; } });
41
+ Object.defineProperty(exports, "createPayerProof", { enumerable: true, get: function () { return payer_proof_js_1.createPayerProof; } });
42
+ // Auto-generated types and extractors from BOLT12 spec CSV
43
+ var generated_js_1 = require("./generated.js");
44
+ Object.defineProperty(exports, "extractGeneratedOfferFields", { enumerable: true, get: function () { return generated_js_1.extractOfferFields; } });
45
+ Object.defineProperty(exports, "KNOWN_OFFER_TYPES", { enumerable: true, get: function () { return generated_js_1.KNOWN_OFFER_TYPES; } });
46
+ Object.defineProperty(exports, "OFFER_TLV_NAMES", { enumerable: true, get: function () { return generated_js_1.OFFER_TLV_NAMES; } });
47
+ Object.defineProperty(exports, "extractInvoiceRequestFields", { enumerable: true, get: function () { return generated_js_1.extractInvoiceRequestFields; } });
48
+ Object.defineProperty(exports, "KNOWN_INVOICE_REQUEST_TYPES", { enumerable: true, get: function () { return generated_js_1.KNOWN_INVOICE_REQUEST_TYPES; } });
49
+ Object.defineProperty(exports, "INVOICE_REQUEST_TLV_NAMES", { enumerable: true, get: function () { return generated_js_1.INVOICE_REQUEST_TLV_NAMES; } });
50
+ Object.defineProperty(exports, "extractInvoiceFields", { enumerable: true, get: function () { return generated_js_1.extractInvoiceFields; } });
51
+ Object.defineProperty(exports, "KNOWN_INVOICE_TYPES", { enumerable: true, get: function () { return generated_js_1.KNOWN_INVOICE_TYPES; } });
52
+ Object.defineProperty(exports, "INVOICE_TLV_NAMES", { enumerable: true, get: function () { return generated_js_1.INVOICE_TLV_NAMES; } });
53
+ Object.defineProperty(exports, "extractInvoiceErrorFields", { enumerable: true, get: function () { return generated_js_1.extractInvoiceErrorFields; } });
54
+ Object.defineProperty(exports, "KNOWN_INVOICE_ERROR_TYPES", { enumerable: true, get: function () { return generated_js_1.KNOWN_INVOICE_ERROR_TYPES; } });
55
+ Object.defineProperty(exports, "INVOICE_ERROR_TLV_NAMES", { enumerable: true, get: function () { return generated_js_1.INVOICE_ERROR_TLV_NAMES; } });
56
+ // Constants (all)
57
+ Object.defineProperty(exports, "OFFER_CHAINS", { enumerable: true, get: function () { return generated_js_1.OFFER_CHAINS; } });
58
+ Object.defineProperty(exports, "OFFER_METADATA", { enumerable: true, get: function () { return generated_js_1.OFFER_METADATA; } });
59
+ Object.defineProperty(exports, "OFFER_CURRENCY", { enumerable: true, get: function () { return generated_js_1.OFFER_CURRENCY; } });
60
+ Object.defineProperty(exports, "OFFER_AMOUNT", { enumerable: true, get: function () { return generated_js_1.OFFER_AMOUNT; } });
61
+ Object.defineProperty(exports, "OFFER_DESCRIPTION", { enumerable: true, get: function () { return generated_js_1.OFFER_DESCRIPTION; } });
62
+ Object.defineProperty(exports, "OFFER_FEATURES", { enumerable: true, get: function () { return generated_js_1.OFFER_FEATURES; } });
63
+ Object.defineProperty(exports, "OFFER_ABSOLUTE_EXPIRY", { enumerable: true, get: function () { return generated_js_1.OFFER_ABSOLUTE_EXPIRY; } });
64
+ Object.defineProperty(exports, "OFFER_PATHS", { enumerable: true, get: function () { return generated_js_1.OFFER_PATHS; } });
65
+ Object.defineProperty(exports, "OFFER_ISSUER", { enumerable: true, get: function () { return generated_js_1.OFFER_ISSUER; } });
66
+ Object.defineProperty(exports, "OFFER_QUANTITY_MAX", { enumerable: true, get: function () { return generated_js_1.OFFER_QUANTITY_MAX; } });
67
+ Object.defineProperty(exports, "OFFER_ISSUER_ID", { enumerable: true, get: function () { return generated_js_1.OFFER_ISSUER_ID; } });
68
+ Object.defineProperty(exports, "INVREQ_METADATA", { enumerable: true, get: function () { return generated_js_1.INVREQ_METADATA; } });
69
+ Object.defineProperty(exports, "INVREQ_CHAIN", { enumerable: true, get: function () { return generated_js_1.INVREQ_CHAIN; } });
70
+ Object.defineProperty(exports, "INVREQ_AMOUNT", { enumerable: true, get: function () { return generated_js_1.INVREQ_AMOUNT; } });
71
+ Object.defineProperty(exports, "INVREQ_FEATURES", { enumerable: true, get: function () { return generated_js_1.INVREQ_FEATURES; } });
72
+ Object.defineProperty(exports, "INVREQ_QUANTITY", { enumerable: true, get: function () { return generated_js_1.INVREQ_QUANTITY; } });
73
+ Object.defineProperty(exports, "INVREQ_PAYER_ID", { enumerable: true, get: function () { return generated_js_1.INVREQ_PAYER_ID; } });
74
+ Object.defineProperty(exports, "INVREQ_PAYER_NOTE", { enumerable: true, get: function () { return generated_js_1.INVREQ_PAYER_NOTE; } });
75
+ Object.defineProperty(exports, "INVREQ_PATHS", { enumerable: true, get: function () { return generated_js_1.INVREQ_PATHS; } });
76
+ Object.defineProperty(exports, "INVREQ_BIP_353_NAME", { enumerable: true, get: function () { return generated_js_1.INVREQ_BIP_353_NAME; } });
77
+ Object.defineProperty(exports, "SIGNATURE", { enumerable: true, get: function () { return generated_js_1.SIGNATURE; } });
78
+ Object.defineProperty(exports, "INVOICE_PATHS", { enumerable: true, get: function () { return generated_js_1.INVOICE_PATHS; } });
79
+ Object.defineProperty(exports, "INVOICE_BLINDEDPAY", { enumerable: true, get: function () { return generated_js_1.INVOICE_BLINDEDPAY; } });
80
+ Object.defineProperty(exports, "INVOICE_CREATED_AT", { enumerable: true, get: function () { return generated_js_1.INVOICE_CREATED_AT; } });
81
+ Object.defineProperty(exports, "INVOICE_RELATIVE_EXPIRY", { enumerable: true, get: function () { return generated_js_1.INVOICE_RELATIVE_EXPIRY; } });
82
+ Object.defineProperty(exports, "INVOICE_PAYMENT_HASH", { enumerable: true, get: function () { return generated_js_1.INVOICE_PAYMENT_HASH; } });
83
+ Object.defineProperty(exports, "INVOICE_AMOUNT", { enumerable: true, get: function () { return generated_js_1.INVOICE_AMOUNT; } });
84
+ Object.defineProperty(exports, "INVOICE_FALLBACKS", { enumerable: true, get: function () { return generated_js_1.INVOICE_FALLBACKS; } });
85
+ Object.defineProperty(exports, "INVOICE_FEATURES", { enumerable: true, get: function () { return generated_js_1.INVOICE_FEATURES; } });
86
+ Object.defineProperty(exports, "INVOICE_NODE_ID", { enumerable: true, get: function () { return generated_js_1.INVOICE_NODE_ID; } });
87
+ const bech32_js_2 = require("./bech32.js");
88
+ const tlv_js_2 = require("./tlv.js");
89
+ const merkle_js_2 = require("./merkle.js");
90
+ const offer_js_2 = require("./offer.js");
91
+ const fields_js_2 = require("./fields.js");
92
+ const payer_proof_js_2 = require("./payer_proof.js");
93
+ /**
94
+ * Decode and validate a BOLT12 offer string.
95
+ *
96
+ * Returns typed fields directly:
97
+ * const { description, amount, issuer_id, offer_id } = decodeOffer(str);
98
+ */
99
+ function decodeOffer(bolt12String) {
100
+ const { hrp, data } = (0, bech32_js_2.decodeBolt12)(bolt12String);
101
+ if (hrp !== 'lno') {
102
+ throw new Error(`Expected offer (lno), got ${hrp}`);
103
+ }
104
+ const records = (0, tlv_js_2.parseTlvStream)(data);
105
+ // Validate offer semantics
106
+ (0, offer_js_2.validateOffer)(records);
107
+ // Extract typed fields
108
+ const fields = (0, fields_js_2.extractOfferFields)(records);
109
+ // Compute offer_id (merkle root of all TLVs)
110
+ const offer_id = (0, merkle_js_2.computeMerkleRoot)(records);
111
+ return { ...fields, hrp, offer_id };
112
+ }
113
+ /**
114
+ * Decode and validate a BOLT12 payer proof string (experimental, PR #1295).
115
+ */
116
+ function decodePayerProof(bolt12String) {
117
+ const { hrp, data } = (0, bech32_js_2.decodeBolt12)(bolt12String);
118
+ if (hrp !== 'lnp') {
119
+ throw new Error(`Expected payer proof (lnp), got ${hrp}`);
120
+ }
121
+ const records = (0, tlv_js_2.parseTlvStream)(data);
122
+ const proof = (0, payer_proof_js_2.parsePayerProof)(records);
123
+ return { hrp, records, proof };
124
+ }
125
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;AAmFH,kCAmBC;AAWD,4CAWC;AA1HD,yCAAyD;AAAhD,yGAAA,YAAY,OAAA;AAAE,yGAAA,YAAY,OAAA;AACnC,2CAAyD;AAAhD,yGAAA,WAAW,OAAA;AAAE,0GAAA,YAAY,OAAA;AAClC,mCAA0D;AAAjD,wGAAA,cAAc,OAAA;AACvB,yCAA6E;AAApE,8GAAA,iBAAiB,OAAA;AAAE,uGAAA,UAAU,OAAA;AAAE,4GAAA,eAAe,OAAA;AACvD,uCAA2C;AAAlC,yGAAA,aAAa,OAAA;AACtB;;;;;GAKG;AACH,yCAIqB;AAHnB,+GAAA,kBAAkB,OAAA;AAIpB,mDAQ0B;AAPxB,iHAAA,eAAe,OAAA;AACf,uHAAA,qBAAqB,OAAA;AACrB,kHAAA,gBAAgB,OAAA;AAChB,kHAAA,gBAAgB,OAAA;AAMlB,2DAA2D;AAC3D,+CAkCwB;AA/BtB,2HAAA,kBAAkB,OAA+B;AACjD,iHAAA,iBAAiB,OAAA;AACjB,+GAAA,eAAe,OAAA;AAGf,2HAAA,2BAA2B,OAAA;AAC3B,2HAAA,2BAA2B,OAAA;AAC3B,yHAAA,yBAAyB,OAAA;AAGzB,oHAAA,oBAAoB,OAAA;AACpB,mHAAA,mBAAmB,OAAA;AACnB,iHAAA,iBAAiB,OAAA;AAGjB,yHAAA,yBAAyB,OAAA;AACzB,yHAAA,yBAAyB,OAAA;AACzB,uHAAA,uBAAuB,OAAA;AAIvB,kBAAkB;AAClB,4GAAA,YAAY,OAAA;AAAE,8GAAA,cAAc,OAAA;AAAE,8GAAA,cAAc,OAAA;AAAE,4GAAA,YAAY,OAAA;AAC1D,iHAAA,iBAAiB,OAAA;AAAE,8GAAA,cAAc,OAAA;AAAE,qHAAA,qBAAqB,OAAA;AACxD,2GAAA,WAAW,OAAA;AAAE,4GAAA,YAAY,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AAAE,+GAAA,eAAe,OAAA;AAC9D,+GAAA,eAAe,OAAA;AAAE,4GAAA,YAAY,OAAA;AAAE,6GAAA,aAAa,OAAA;AAAE,+GAAA,eAAe,OAAA;AAC7D,+GAAA,eAAe,OAAA;AAAE,+GAAA,eAAe,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AAAE,4GAAA,YAAY,OAAA;AACjE,mHAAA,mBAAmB,OAAA;AAAE,yGAAA,SAAS,OAAA;AAC9B,6GAAA,aAAa,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AAAE,kHAAA,kBAAkB,OAAA;AACrD,uHAAA,uBAAuB,OAAA;AAAE,oHAAA,oBAAoB,OAAA;AAAE,8GAAA,cAAc,OAAA;AAC7D,iHAAA,iBAAiB,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AAAE,+GAAA,eAAe,OAAA;AAGtD,2CAA2D;AAC3D,qCAA0D;AAC1D,2CAAiE;AACjE,yCAA2C;AAC3C,2CAAmE;AACnE,qDAAsJ;AAOtJ;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,YAAoB;IAC9C,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAA,wBAAY,EAAC,YAAY,CAAC,CAAC;IAEjD,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,uBAAc,EAAC,IAAI,CAAC,CAAC;IAErC,2BAA2B;IAC3B,IAAA,wBAAa,EAAC,OAAO,CAAC,CAAC;IAEvB,uBAAuB;IACvB,MAAM,MAAM,GAAG,IAAA,8BAAkB,EAAC,OAAO,CAAC,CAAC;IAE3C,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,IAAA,6BAAiB,EAAC,OAAO,CAAC,CAAC;IAE5C,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;AACtC,CAAC;AAQD;;GAEG;AACH,SAAgB,gBAAgB,CAAC,YAAoB;IACnD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,IAAA,wBAAY,EAAC,YAAY,CAAC,CAAC;IAEjD,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,uBAAc,EAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,IAAA,gCAAe,EAAC,OAAO,CAAC,CAAC;IAEvC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Merkle tree computation for BOLT12 signature verification.
3
+ *
4
+ * Each TLV record is paired with a nonce derived from the first TLV:
5
+ * leaf = H("LnLeaf", tlv_bytes)
6
+ * nonce = H(SHA256("LnNonce" || first_tlv_bytes), type_bytes)
7
+ * branch = H("LnBranch", sorted(leaf, nonce))
8
+ *
9
+ * These branches are then paired up in a binary tree:
10
+ * parent = H("LnBranch", sorted(left, right))
11
+ *
12
+ * The root of the tree is the merkle root (offer_id for offers).
13
+ *
14
+ * Signature verification uses:
15
+ * msg = H("lightning" || messagename || "signature", merkle_root)
16
+ */
17
+ import type { TlvRecord } from './tlv.js';
18
+ /**
19
+ * Tagged hash: H(tag, msg) = SHA256(SHA256(tag) || SHA256(tag) || msg)
20
+ */
21
+ export declare function taggedHash(tag: Uint8Array, msg: Uint8Array): Uint8Array;
22
+ /**
23
+ * Serialize a single TLV record to its wire format (type + length + value).
24
+ */
25
+ export declare function tlvToBytes(record: TlvRecord): Uint8Array;
26
+ /**
27
+ * Compute a branch from a pair of nodes, ordering them lexicographically.
28
+ */
29
+ export declare function branchHash(a: Uint8Array, b: Uint8Array): Uint8Array;
30
+ /**
31
+ * Compute per-TLV branch hashes (leaf+nonce combined).
32
+ * Returns the branch hash for each non-signature TLV, and the nonce tag hash.
33
+ */
34
+ export declare function computePerTlvBranches(records: TlvRecord[]): {
35
+ branches: Uint8Array[];
36
+ nonceTagHash: Uint8Array;
37
+ leafTagHash: Uint8Array;
38
+ branchTagHash: Uint8Array;
39
+ };
40
+ /**
41
+ * Compute the merkle root from an array of TLV records.
42
+ *
43
+ * Excludes signature TLVs (types 240-1000) from the tree.
44
+ */
45
+ export declare function computeMerkleRoot(records: TlvRecord[]): Uint8Array;
46
+ /**
47
+ * Compute the signature verification message.
48
+ * tag = "lightning" + messagename + "signature"
49
+ */
50
+ export declare function signatureTag(messageName: string): Uint8Array;
51
+ /**
52
+ * Verify a BIP340 Schnorr signature on a BOLT12 message.
53
+ */
54
+ export declare function verifySignature(messageName: string, merkleRoot: Uint8Array, pubkey32: Uint8Array, signature: Uint8Array): boolean;
55
+ //# sourceMappingURL=merkle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.d.ts","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAM1C;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAGvE;AASD;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,UAAU,CAIxD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAInE;AAOD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG;IAC3D,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,YAAY,EAAE,UAAU,CAAC;IACzB,WAAW,EAAE,UAAU,CAAC;IACxB,aAAa,EAAE,UAAU,CAAC;CAC3B,CA0BA;AA6BD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,CAGlE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAE5D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,UAAU,EACpB,SAAS,EAAE,UAAU,GACpB,OAAO,CAQT"}
package/dist/merkle.js ADDED
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ /**
3
+ * Merkle tree computation for BOLT12 signature verification.
4
+ *
5
+ * Each TLV record is paired with a nonce derived from the first TLV:
6
+ * leaf = H("LnLeaf", tlv_bytes)
7
+ * nonce = H(SHA256("LnNonce" || first_tlv_bytes), type_bytes)
8
+ * branch = H("LnBranch", sorted(leaf, nonce))
9
+ *
10
+ * These branches are then paired up in a binary tree:
11
+ * parent = H("LnBranch", sorted(left, right))
12
+ *
13
+ * The root of the tree is the merkle root (offer_id for offers).
14
+ *
15
+ * Signature verification uses:
16
+ * msg = H("lightning" || messagename || "signature", merkle_root)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.taggedHash = taggedHash;
20
+ exports.tlvToBytes = tlvToBytes;
21
+ exports.branchHash = branchHash;
22
+ exports.computePerTlvBranches = computePerTlvBranches;
23
+ exports.computeMerkleRoot = computeMerkleRoot;
24
+ exports.signatureTag = signatureTag;
25
+ exports.verifySignature = verifySignature;
26
+ const sha2_1 = require("@noble/hashes/sha2");
27
+ const utils_1 = require("@noble/hashes/utils");
28
+ const secp256k1_1 = require("@noble/curves/secp256k1");
29
+ const bigsize_js_1 = require("./bigsize.js");
30
+ const utils_js_1 = require("./utils.js");
31
+ const encoder = new TextEncoder();
32
+ /**
33
+ * Tagged hash: H(tag, msg) = SHA256(SHA256(tag) || SHA256(tag) || msg)
34
+ */
35
+ function taggedHash(tag, msg) {
36
+ const tagHash = (0, sha2_1.sha256)(tag);
37
+ return (0, sha2_1.sha256)((0, utils_1.concatBytes)(tagHash, tagHash, msg));
38
+ }
39
+ /**
40
+ * Tagged hash using a pre-computed tag hash.
41
+ */
42
+ function taggedHashWithHash(tagHash, msg) {
43
+ return (0, sha2_1.sha256)((0, utils_1.concatBytes)(tagHash, tagHash, msg));
44
+ }
45
+ /**
46
+ * Serialize a single TLV record to its wire format (type + length + value).
47
+ */
48
+ function tlvToBytes(record) {
49
+ const typeBytes = (0, bigsize_js_1.writeBigSize)(record.type);
50
+ const lengthBytes = (0, bigsize_js_1.writeBigSize)(record.length);
51
+ return (0, utils_1.concatBytes)(typeBytes, lengthBytes, record.value);
52
+ }
53
+ /**
54
+ * Compute a branch from a pair of nodes, ordering them lexicographically.
55
+ */
56
+ function branchHash(a, b) {
57
+ const branchTagHash = (0, sha2_1.sha256)(encoder.encode('LnBranch'));
58
+ const [smaller, larger] = (0, utils_js_1.compareBytes)(a, b) < 0 ? [a, b] : [b, a];
59
+ return taggedHashWithHash(branchTagHash, (0, utils_1.concatBytes)(smaller, larger));
60
+ }
61
+ /** Signature TLV type range (240-1000 inclusive). */
62
+ function isSignatureType(type) {
63
+ return type >= 240n && type <= 1000n;
64
+ }
65
+ /**
66
+ * Compute per-TLV branch hashes (leaf+nonce combined).
67
+ * Returns the branch hash for each non-signature TLV, and the nonce tag hash.
68
+ */
69
+ function computePerTlvBranches(records) {
70
+ const nonSig = records.filter(r => !isSignatureType(r.type));
71
+ if (nonSig.length === 0) {
72
+ throw new Error('Cannot compute merkle root of empty TLV set');
73
+ }
74
+ // Nonce tag: SHA256("LnNonce" || first_record_bytes)
75
+ const firstRecBytes = tlvToBytes(nonSig[0]);
76
+ const nonceTagHash = (0, sha2_1.sha256)((0, utils_1.concatBytes)(encoder.encode('LnNonce'), firstRecBytes));
77
+ const leafTagHash = (0, sha2_1.sha256)(encoder.encode('LnLeaf'));
78
+ const branchTagHash = (0, sha2_1.sha256)(encoder.encode('LnBranch'));
79
+ const branches = nonSig.map((record) => {
80
+ const recBytes = tlvToBytes(record);
81
+ const typeBytes = (0, bigsize_js_1.writeBigSize)(record.type);
82
+ const leaf = taggedHashWithHash(leafTagHash, recBytes);
83
+ const nonce = taggedHashWithHash(nonceTagHash, typeBytes);
84
+ // Combine leaf and nonce with lexicographic ordering
85
+ const [smaller, larger] = (0, utils_js_1.compareBytes)(leaf, nonce) < 0 ? [leaf, nonce] : [nonce, leaf];
86
+ return taggedHashWithHash(branchTagHash, (0, utils_1.concatBytes)(smaller, larger));
87
+ });
88
+ return { branches, nonceTagHash, leafTagHash, branchTagHash };
89
+ }
90
+ /**
91
+ * Build merkle tree from per-TLV branch hashes, bottom-up.
92
+ */
93
+ function buildMerkleTree(nodes) {
94
+ const branchTagHash = (0, sha2_1.sha256)(encoder.encode('LnBranch'));
95
+ while (nodes.length > 1) {
96
+ const parents = [];
97
+ let i = 0;
98
+ while (i < nodes.length) {
99
+ if (i + 1 < nodes.length) {
100
+ const [smaller, larger] = (0, utils_js_1.compareBytes)(nodes[i], nodes[i + 1]) < 0
101
+ ? [nodes[i], nodes[i + 1]]
102
+ : [nodes[i + 1], nodes[i]];
103
+ parents.push(taggedHashWithHash(branchTagHash, (0, utils_1.concatBytes)(smaller, larger)));
104
+ i += 2;
105
+ }
106
+ else {
107
+ parents.push(nodes[i]);
108
+ i += 1;
109
+ }
110
+ }
111
+ nodes = parents;
112
+ }
113
+ return nodes[0];
114
+ }
115
+ /**
116
+ * Compute the merkle root from an array of TLV records.
117
+ *
118
+ * Excludes signature TLVs (types 240-1000) from the tree.
119
+ */
120
+ function computeMerkleRoot(records) {
121
+ const { branches } = computePerTlvBranches(records);
122
+ return buildMerkleTree([...branches]);
123
+ }
124
+ /**
125
+ * Compute the signature verification message.
126
+ * tag = "lightning" + messagename + "signature"
127
+ */
128
+ function signatureTag(messageName) {
129
+ return encoder.encode(`lightning${messageName}signature`);
130
+ }
131
+ /**
132
+ * Verify a BIP340 Schnorr signature on a BOLT12 message.
133
+ */
134
+ function verifySignature(messageName, merkleRoot, pubkey32, signature) {
135
+ const tag = signatureTag(messageName);
136
+ const msg = taggedHash(tag, merkleRoot);
137
+ try {
138
+ return secp256k1_1.schnorr.verify(signature, msg, pubkey32);
139
+ }
140
+ catch {
141
+ return false;
142
+ }
143
+ }
144
+ //# sourceMappingURL=merkle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merkle.js","sourceRoot":"","sources":["../src/merkle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * BOLT12 Offer validation.
3
+ *
4
+ * An offer is a TLV stream encoded with the "lno" prefix.
5
+ * This module validates the semantic rules for offers as specified
6
+ * in BOLT 12.
7
+ *
8
+ * Offer TLV types (from the spec):
9
+ * 2 - offer_chains (array of 32-byte chain_hashes)
10
+ * 4 - offer_metadata (arbitrary bytes)
11
+ * 6 - offer_currency (UTF-8 ISO 4217 code)
12
+ * 8 - offer_amount (tu64 msat or currency units)
13
+ * 10 - offer_description (UTF-8 string)
14
+ * 12 - offer_features (feature bits)
15
+ * 14 - offer_absolute_expiry (tu64 seconds since epoch)
16
+ * 16 - offer_paths (blinded_path array)
17
+ * 18 - offer_issuer (UTF-8 string)
18
+ * 20 - offer_quantity_max (tu64)
19
+ * 22 - offer_issuer_id (point, 33 bytes)
20
+ */
21
+ import type { TlvRecord } from './tlv.js';
22
+ export declare const OFFER_CHAINS = 2n;
23
+ export declare const OFFER_METADATA = 4n;
24
+ export declare const OFFER_CURRENCY = 6n;
25
+ export declare const OFFER_AMOUNT = 8n;
26
+ export declare const OFFER_DESCRIPTION = 10n;
27
+ export declare const OFFER_FEATURES = 12n;
28
+ export declare const OFFER_ABSOLUTE_EXPIRY = 14n;
29
+ export declare const OFFER_PATHS = 16n;
30
+ export declare const OFFER_ISSUER = 18n;
31
+ export declare const OFFER_QUANTITY_MAX = 20n;
32
+ export declare const OFFER_ISSUER_ID = 22n;
33
+ export interface ValidatedOffer {
34
+ records: TlvRecord[];
35
+ hasDescription: boolean;
36
+ hasAmount: boolean;
37
+ hasCurrency: boolean;
38
+ hasIssuerId: boolean;
39
+ hasPaths: boolean;
40
+ }
41
+ /**
42
+ * Validate an offer's TLV records according to BOLT12 semantic rules.
43
+ */
44
+ export declare function validateOffer(records: TlvRecord[]): ValidatedOffer;
45
+ //# sourceMappingURL=offer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"offer.d.ts","sourceRoot":"","sources":["../src/offer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAI1C,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,WAAW,MAAM,CAAC;AAC/B,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,eAAe,MAAM,CAAC;AAgMnC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,cAAc,CAuFlE"}