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.
- package/dist/bech32.d.ts +31 -0
- package/dist/bech32.d.ts.map +1 -0
- package/dist/bech32.js +161 -0
- package/dist/bech32.js.map +1 -0
- package/dist/bigsize.d.ts +22 -0
- package/dist/bigsize.d.ts.map +1 -0
- package/dist/bigsize.js +87 -0
- package/dist/bigsize.js.map +1 -0
- package/dist/fields.d.ts +61 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +99 -0
- package/dist/fields.js.map +1 -0
- package/dist/generated.d.ts +179 -0
- package/dist/generated.d.ts.map +1 -0
- package/dist/generated.js +565 -0
- package/dist/generated.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/merkle.d.ts +55 -0
- package/dist/merkle.d.ts.map +1 -0
- package/dist/merkle.js +144 -0
- package/dist/merkle.js.map +1 -0
- package/dist/offer.d.ts +45 -0
- package/dist/offer.d.ts.map +1 -0
- package/dist/offer.js +288 -0
- package/dist/offer.js.map +1 -0
- package/dist/payer_proof.d.ts +89 -0
- package/dist/payer_proof.d.ts.map +1 -0
- package/dist/payer_proof.js +576 -0
- package/dist/payer_proof.js.map +1 -0
- package/dist/tlv.d.ts +26 -0
- package/dist/tlv.d.ts.map +1 -0
- package/dist/tlv.js +65 -0
- package/dist/tlv.js.map +1 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +52 -0
- package/dist/utils.js.map +1 -0
- package/package.json +47 -0
- package/src/bech32.ts +187 -0
- package/src/bigsize.ts +97 -0
- package/src/fields.ts +147 -0
- package/src/generated.ts +697 -0
- package/src/index.ts +132 -0
- package/src/merkle.ts +163 -0
- package/src/offer.ts +328 -0
- package/src/payer_proof.ts +727 -0
- package/src/tlv.ts +75 -0
- package/src/utils.ts +49 -0
package/dist/offer.js
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BOLT12 Offer validation.
|
|
4
|
+
*
|
|
5
|
+
* An offer is a TLV stream encoded with the "lno" prefix.
|
|
6
|
+
* This module validates the semantic rules for offers as specified
|
|
7
|
+
* in BOLT 12.
|
|
8
|
+
*
|
|
9
|
+
* Offer TLV types (from the spec):
|
|
10
|
+
* 2 - offer_chains (array of 32-byte chain_hashes)
|
|
11
|
+
* 4 - offer_metadata (arbitrary bytes)
|
|
12
|
+
* 6 - offer_currency (UTF-8 ISO 4217 code)
|
|
13
|
+
* 8 - offer_amount (tu64 msat or currency units)
|
|
14
|
+
* 10 - offer_description (UTF-8 string)
|
|
15
|
+
* 12 - offer_features (feature bits)
|
|
16
|
+
* 14 - offer_absolute_expiry (tu64 seconds since epoch)
|
|
17
|
+
* 16 - offer_paths (blinded_path array)
|
|
18
|
+
* 18 - offer_issuer (UTF-8 string)
|
|
19
|
+
* 20 - offer_quantity_max (tu64)
|
|
20
|
+
* 22 - offer_issuer_id (point, 33 bytes)
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
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 = void 0;
|
|
24
|
+
exports.validateOffer = validateOffer;
|
|
25
|
+
const secp256k1_1 = require("@noble/curves/secp256k1");
|
|
26
|
+
const utils_js_1 = require("./utils.js");
|
|
27
|
+
// Offer TLV type numbers
|
|
28
|
+
exports.OFFER_CHAINS = 2n;
|
|
29
|
+
exports.OFFER_METADATA = 4n;
|
|
30
|
+
exports.OFFER_CURRENCY = 6n;
|
|
31
|
+
exports.OFFER_AMOUNT = 8n;
|
|
32
|
+
exports.OFFER_DESCRIPTION = 10n;
|
|
33
|
+
exports.OFFER_FEATURES = 12n;
|
|
34
|
+
exports.OFFER_ABSOLUTE_EXPIRY = 14n;
|
|
35
|
+
exports.OFFER_PATHS = 16n;
|
|
36
|
+
exports.OFFER_ISSUER = 18n;
|
|
37
|
+
exports.OFFER_QUANTITY_MAX = 20n;
|
|
38
|
+
exports.OFFER_ISSUER_ID = 22n;
|
|
39
|
+
const KNOWN_OFFER_TYPES = new Set([
|
|
40
|
+
exports.OFFER_CHAINS,
|
|
41
|
+
exports.OFFER_METADATA,
|
|
42
|
+
exports.OFFER_CURRENCY,
|
|
43
|
+
exports.OFFER_AMOUNT,
|
|
44
|
+
exports.OFFER_DESCRIPTION,
|
|
45
|
+
exports.OFFER_FEATURES,
|
|
46
|
+
exports.OFFER_ABSOLUTE_EXPIRY,
|
|
47
|
+
exports.OFFER_PATHS,
|
|
48
|
+
exports.OFFER_ISSUER,
|
|
49
|
+
exports.OFFER_QUANTITY_MAX,
|
|
50
|
+
exports.OFFER_ISSUER_ID,
|
|
51
|
+
]);
|
|
52
|
+
/**
|
|
53
|
+
* Check if a type is in the valid offer range.
|
|
54
|
+
* Offers may contain types 1-79 and 1000000000-1999999999.
|
|
55
|
+
*/
|
|
56
|
+
function isValidOfferType(type) {
|
|
57
|
+
if (type >= 1n && type <= 79n) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
if (type >= 1000000000n && type <= 1999999999n) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validate UTF-8 encoding of a byte array.
|
|
67
|
+
* Returns the decoded string or throws if invalid.
|
|
68
|
+
*/
|
|
69
|
+
function validateUtf8(data, fieldName) {
|
|
70
|
+
const decoder = new TextDecoder('utf-8', { fatal: true });
|
|
71
|
+
try {
|
|
72
|
+
return decoder.decode(data);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
throw new Error(`Invalid UTF-8 in ${fieldName}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Validate a compressed public key (33 bytes, valid point on secp256k1).
|
|
80
|
+
*/
|
|
81
|
+
function validatePoint(data, fieldName) {
|
|
82
|
+
if (data.length !== 33) {
|
|
83
|
+
throw new Error(`Invalid ${fieldName}: expected 33 bytes, got ${data.length}`);
|
|
84
|
+
}
|
|
85
|
+
if (data[0] !== 0x02 && data[0] !== 0x03) {
|
|
86
|
+
throw new Error(`Invalid ${fieldName}: must start with 02 or 03`);
|
|
87
|
+
}
|
|
88
|
+
// Validate the point is actually on the secp256k1 curve
|
|
89
|
+
try {
|
|
90
|
+
secp256k1_1.secp256k1.ProjectivePoint.fromHex(data);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
throw new Error(`Invalid ${fieldName}: not a valid point on secp256k1`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate offer_chains field: must be a multiple of 32 bytes, and non-empty.
|
|
98
|
+
*/
|
|
99
|
+
function validateChains(data) {
|
|
100
|
+
if (data.length === 0 || data.length % 32 !== 0) {
|
|
101
|
+
throw new Error('Invalid offer_chains: length must be a non-zero multiple of 32');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Validate blinded paths (offer_paths field, type 16).
|
|
106
|
+
*
|
|
107
|
+
* Format:
|
|
108
|
+
* For each path:
|
|
109
|
+
* first_node_id: either 33-byte point OR 9-byte sciddir (if first byte 0x00 or 0x01)
|
|
110
|
+
* path_key: 33-byte point (compressed pubkey)
|
|
111
|
+
* num_hops: u8 (must be > 0)
|
|
112
|
+
* For each hop:
|
|
113
|
+
* blinded_node_id: 33-byte point
|
|
114
|
+
* enclen: u16
|
|
115
|
+
* encrypted_recipient_data: enclen bytes
|
|
116
|
+
*/
|
|
117
|
+
function validateBlindedPaths(data) {
|
|
118
|
+
let offset = 0;
|
|
119
|
+
// We need to parse all paths in the single offer_paths TLV value
|
|
120
|
+
let pathCount = 0;
|
|
121
|
+
while (offset < data.length) {
|
|
122
|
+
pathCount++;
|
|
123
|
+
// first_node_id: check if it's a sciddir (starts with 0x00 or 0x01) or regular point
|
|
124
|
+
if (offset >= data.length) {
|
|
125
|
+
throw new Error('Truncated offer_paths: missing first_node_id');
|
|
126
|
+
}
|
|
127
|
+
const firstByte = data[offset];
|
|
128
|
+
let firstNodeIdLen;
|
|
129
|
+
if (firstByte === 0x00 || firstByte === 0x01) {
|
|
130
|
+
// sciddir: 1 byte direction + 8 byte short_channel_id = 9 bytes
|
|
131
|
+
firstNodeIdLen = 9;
|
|
132
|
+
}
|
|
133
|
+
else if (firstByte === 0x02 || firstByte === 0x03) {
|
|
134
|
+
// Regular compressed point: 33 bytes
|
|
135
|
+
firstNodeIdLen = 33;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
throw new Error('Invalid first_node_id in blinded path: bad prefix byte');
|
|
139
|
+
}
|
|
140
|
+
if (offset + firstNodeIdLen > data.length) {
|
|
141
|
+
throw new Error('Truncated offer_paths: first_node_id truncated');
|
|
142
|
+
}
|
|
143
|
+
offset += firstNodeIdLen;
|
|
144
|
+
// path_key: 33-byte compressed point
|
|
145
|
+
if (offset + 33 > data.length) {
|
|
146
|
+
throw new Error('Truncated offer_paths: missing path_key');
|
|
147
|
+
}
|
|
148
|
+
const pathKeyPrefix = data[offset];
|
|
149
|
+
if (pathKeyPrefix !== 0x02 && pathKeyPrefix !== 0x03) {
|
|
150
|
+
throw new Error('Invalid path_key in blinded path: must start with 02 or 03');
|
|
151
|
+
}
|
|
152
|
+
offset += 33;
|
|
153
|
+
// num_hops: u8
|
|
154
|
+
if (offset >= data.length) {
|
|
155
|
+
throw new Error('Truncated offer_paths: missing num_hops');
|
|
156
|
+
}
|
|
157
|
+
const numHops = data[offset];
|
|
158
|
+
offset += 1;
|
|
159
|
+
if (numHops === 0) {
|
|
160
|
+
throw new Error('Invalid blinded path: num_hops must be > 0');
|
|
161
|
+
}
|
|
162
|
+
// Parse each hop
|
|
163
|
+
for (let h = 0; h < numHops; h++) {
|
|
164
|
+
// blinded_node_id: 33-byte point
|
|
165
|
+
if (offset + 33 > data.length) {
|
|
166
|
+
throw new Error('Truncated onionmsg_hop: missing blinded_node_id');
|
|
167
|
+
}
|
|
168
|
+
const blindedPrefix = data[offset];
|
|
169
|
+
if (blindedPrefix !== 0x02 && blindedPrefix !== 0x03) {
|
|
170
|
+
throw new Error('Invalid blinded_node_id: must start with 02 or 03');
|
|
171
|
+
}
|
|
172
|
+
offset += 33;
|
|
173
|
+
// enclen: u16
|
|
174
|
+
if (offset + 2 > data.length) {
|
|
175
|
+
throw new Error('Truncated onionmsg_hop: missing enclen');
|
|
176
|
+
}
|
|
177
|
+
const enclen = (data[offset] << 8) | data[offset + 1];
|
|
178
|
+
offset += 2;
|
|
179
|
+
// encrypted_recipient_data
|
|
180
|
+
if (offset + enclen > data.length) {
|
|
181
|
+
throw new Error('Truncated onionmsg_hop: encrypted_data truncated');
|
|
182
|
+
}
|
|
183
|
+
offset += enclen;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Must have at least one path
|
|
187
|
+
if (pathCount === 0) {
|
|
188
|
+
throw new Error('offer_paths must contain at least one path');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Validate feature bits. Per the spec, unknown even feature bits must
|
|
193
|
+
* cause rejection. Odd bits are always safe to ignore.
|
|
194
|
+
*/
|
|
195
|
+
function validateFeatures(data) {
|
|
196
|
+
for (let byteIdx = 0; byteIdx < data.length; byteIdx++) {
|
|
197
|
+
const byte = data[byteIdx];
|
|
198
|
+
if (byte === 0) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
// Position from the right (LSB of last byte = bit 0)
|
|
202
|
+
const bitOffset = (data.length - 1 - byteIdx) * 8;
|
|
203
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
204
|
+
if (byte & (1 << bit)) {
|
|
205
|
+
const featureBit = bitOffset + bit;
|
|
206
|
+
if (featureBit % 2 === 0) {
|
|
207
|
+
throw new Error(`Unknown even feature bit ${featureBit}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Validate an offer's TLV records according to BOLT12 semantic rules.
|
|
215
|
+
*/
|
|
216
|
+
function validateOffer(records) {
|
|
217
|
+
let hasDescription = false;
|
|
218
|
+
let hasAmount = false;
|
|
219
|
+
let hasCurrency = false;
|
|
220
|
+
let hasIssuerId = false;
|
|
221
|
+
let hasPaths = false;
|
|
222
|
+
for (const record of records) {
|
|
223
|
+
const type = record.type;
|
|
224
|
+
// Check type is in valid offer range
|
|
225
|
+
if (!isValidOfferType(type)) {
|
|
226
|
+
if (type % 2n === 0n) {
|
|
227
|
+
throw new Error(`Invalid: unknown even field type ${type} outside offer range`);
|
|
228
|
+
}
|
|
229
|
+
// This type is out of range but odd - still invalid for offers
|
|
230
|
+
throw new Error(`Invalid: field type ${type} outside valid offer range`);
|
|
231
|
+
}
|
|
232
|
+
// Unknown even types must be rejected
|
|
233
|
+
if (!KNOWN_OFFER_TYPES.has(type) && type % 2n === 0n) {
|
|
234
|
+
throw new Error(`Unknown even TLV type ${type}`);
|
|
235
|
+
}
|
|
236
|
+
// Validate specific fields
|
|
237
|
+
switch (type) {
|
|
238
|
+
case exports.OFFER_CHAINS:
|
|
239
|
+
validateChains(record.value);
|
|
240
|
+
break;
|
|
241
|
+
case exports.OFFER_CURRENCY:
|
|
242
|
+
validateUtf8(record.value, 'offer_currency');
|
|
243
|
+
hasCurrency = true;
|
|
244
|
+
break;
|
|
245
|
+
case exports.OFFER_AMOUNT: {
|
|
246
|
+
const amount = (0, utils_js_1.readTruncatedUint)(record.value);
|
|
247
|
+
if (amount === 0n) {
|
|
248
|
+
throw new Error('Invalid: zero offer_amount');
|
|
249
|
+
}
|
|
250
|
+
hasAmount = true;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case exports.OFFER_DESCRIPTION:
|
|
254
|
+
validateUtf8(record.value, 'offer_description');
|
|
255
|
+
hasDescription = true;
|
|
256
|
+
break;
|
|
257
|
+
case exports.OFFER_FEATURES:
|
|
258
|
+
validateFeatures(record.value);
|
|
259
|
+
break;
|
|
260
|
+
case exports.OFFER_PATHS:
|
|
261
|
+
validateBlindedPaths(record.value);
|
|
262
|
+
hasPaths = true;
|
|
263
|
+
break;
|
|
264
|
+
case exports.OFFER_ISSUER:
|
|
265
|
+
validateUtf8(record.value, 'offer_issuer');
|
|
266
|
+
break;
|
|
267
|
+
case exports.OFFER_ISSUER_ID:
|
|
268
|
+
validatePoint(record.value, 'offer_issuer_id');
|
|
269
|
+
hasIssuerId = true;
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Semantic validation rules:
|
|
274
|
+
// An offer with amount but no description is invalid
|
|
275
|
+
if (hasAmount && !hasDescription) {
|
|
276
|
+
throw new Error('Missing offer_description with offer_amount');
|
|
277
|
+
}
|
|
278
|
+
// Currency requires amount
|
|
279
|
+
if (hasCurrency && !hasAmount) {
|
|
280
|
+
throw new Error('Missing offer_amount with offer_currency');
|
|
281
|
+
}
|
|
282
|
+
// Must have either issuer_id or paths (or both)
|
|
283
|
+
if (!hasIssuerId && !hasPaths) {
|
|
284
|
+
throw new Error('Missing offer_issuer_id and no offer_paths');
|
|
285
|
+
}
|
|
286
|
+
return { records, hasDescription, hasAmount, hasCurrency, hasIssuerId, hasPaths };
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=offer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offer.js","sourceRoot":"","sources":["../src/offer.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AA6NH,sCAuFC;AAlTD,uDAAoD;AAEpD,yCAA+C;AAE/C,yBAAyB;AACZ,QAAA,YAAY,GAAG,EAAE,CAAC;AAClB,QAAA,cAAc,GAAG,EAAE,CAAC;AACpB,QAAA,cAAc,GAAG,EAAE,CAAC;AACpB,QAAA,YAAY,GAAG,EAAE,CAAC;AAClB,QAAA,iBAAiB,GAAG,GAAG,CAAC;AACxB,QAAA,cAAc,GAAG,GAAG,CAAC;AACrB,QAAA,qBAAqB,GAAG,GAAG,CAAC;AAC5B,QAAA,WAAW,GAAG,GAAG,CAAC;AAClB,QAAA,YAAY,GAAG,GAAG,CAAC;AACnB,QAAA,kBAAkB,GAAG,GAAG,CAAC;AACzB,QAAA,eAAe,GAAG,GAAG,CAAC;AAEnC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,oBAAY;IACZ,sBAAc;IACd,sBAAc;IACd,oBAAY;IACZ,yBAAiB;IACjB,sBAAc;IACd,6BAAqB;IACrB,mBAAW;IACX,oBAAY;IACZ,0BAAkB;IAClB,uBAAe;CAChB,CAAC,CAAC;AAEH;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,IAAI,WAAW,IAAI,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,IAAgB,EAAE,SAAiB;IACvD,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,oBAAoB,SAAS,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,IAAgB,EAAE,SAAiB;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,4BAA4B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,4BAA4B,CAAC,CAAC;IACpE,CAAC;IACD,wDAAwD;IACxD,IAAI,CAAC;QACH,qBAAS,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,kCAAkC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,IAAgB;IACtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,oBAAoB,CAAC,IAAgB;IAC5C,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,iEAAiE;IACjE,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,SAAS,EAAE,CAAC;QAEZ,qFAAqF;QACrF,IAAI,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,cAAsB,CAAC;QAC3B,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YAC7C,gEAAgE;YAChE,cAAc,GAAG,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACpD,qCAAqC;YACrC,cAAc,GAAG,EAAE,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,MAAM,GAAG,cAAc,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,IAAI,cAAc,CAAC;QAEzB,qCAAqC;QACrC,IAAI,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,IAAI,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QACD,MAAM,IAAI,EAAE,CAAC;QAEb,eAAe;QACf,IAAI,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,MAAM,IAAI,CAAC,CAAC;QAEZ,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAChE,CAAC;QAED,iBAAiB;QACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YACjC,iCAAiC;YACjC,IAAI,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;YACrE,CAAC;YACD,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;YACvE,CAAC;YACD,MAAM,IAAI,EAAE,CAAC;YAEb,cAAc;YACd,IAAI,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC5D,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACtD,MAAM,IAAI,CAAC,CAAC;YAEZ,2BAA2B;YAC3B,IAAI,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBAClC,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;YACtE,CAAC;YACD,MAAM,IAAI,MAAM,CAAC;QACnB,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAgB;IACxC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QAED,qDAAqD;QACrD,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAElD,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;YACjC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,UAAU,GAAG,SAAS,GAAG,GAAG,CAAC;gBACnC,IAAI,UAAU,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,UAAU,EAAE,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAWD;;GAEG;AACH,SAAgB,aAAa,CAAC,OAAoB;IAChD,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAEzB,qCAAqC;QACrC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,IAAI,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,sBAAsB,CAAC,CAAC;YAClF,CAAC;YACD,+DAA+D;YAC/D,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,4BAA4B,CAAC,CAAC;QAC3E,CAAC;QAED,sCAAsC;QACtC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,2BAA2B;QAC3B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,oBAAY;gBACf,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC7B,MAAM;YAER,KAAK,sBAAc;gBACjB,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;gBAC7C,WAAW,GAAG,IAAI,CAAC;gBACnB,MAAM;YAER,KAAK,oBAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,MAAM,GAAG,IAAA,4BAAiB,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC/C,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;gBAChD,CAAC;gBACD,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR,CAAC;YAED,KAAK,yBAAiB;gBACpB,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;gBAChD,cAAc,GAAG,IAAI,CAAC;gBACtB,MAAM;YAER,KAAK,sBAAc;gBACjB,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC/B,MAAM;YAER,KAAK,mBAAW;gBACd,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACnC,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YAER,KAAK,oBAAY;gBACf,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;gBAC3C,MAAM;YAER,KAAK,uBAAe;gBAClB,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;gBAC/C,WAAW,GAAG,IAAI,CAAC;gBACnB,MAAM;QACV,CAAC;IACH,CAAC;IAED,6BAA6B;IAE7B,qDAAqD;IACrD,IAAI,SAAS,IAAI,CAAC,cAAc,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,2BAA2B;IAC3B,IAAI,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,gDAAgD;IAChD,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOLT12 Payer Proof (experimental, PR #1295).
|
|
3
|
+
*
|
|
4
|
+
* A payer proof is a proof of invoice payment, encoded with the "lnp" prefix.
|
|
5
|
+
* It contains a subset of the invoice's TLV fields, allowing the payer to
|
|
6
|
+
* prove they paid a specific invoice while selectively disclosing only
|
|
7
|
+
* certain fields for privacy.
|
|
8
|
+
*
|
|
9
|
+
* New TLV types:
|
|
10
|
+
* 242 - preimage (32-byte payment preimage)
|
|
11
|
+
* 244 - omitted_tlvs (array of bigsize marker numbers)
|
|
12
|
+
* 246 - missing_hashes (array of sha256 hashes for merkle reconstruction)
|
|
13
|
+
* 248 - leaf_hashes (array of sha256 nonce hashes for included TLVs)
|
|
14
|
+
* 250 - payer_signature (bip340sig + optional UTF-8 note)
|
|
15
|
+
*/
|
|
16
|
+
import type { TlvRecord } from './tlv.js';
|
|
17
|
+
export declare const PP_PREIMAGE = 242n;
|
|
18
|
+
export declare const PP_OMITTED_TLVS = 244n;
|
|
19
|
+
export declare const PP_MISSING_HASHES = 246n;
|
|
20
|
+
export declare const PP_LEAF_HASHES = 248n;
|
|
21
|
+
export declare const PP_PAYER_SIGNATURE = 250n;
|
|
22
|
+
export interface PayerProofFields {
|
|
23
|
+
/** Included TLV records (non-signature, non-payer-proof-specific) */
|
|
24
|
+
includedRecords: TlvRecord[];
|
|
25
|
+
/** The invoice signature (type 240) */
|
|
26
|
+
signature: Uint8Array;
|
|
27
|
+
/** Payment preimage (type 242, 32 bytes) */
|
|
28
|
+
preimage: Uint8Array | undefined;
|
|
29
|
+
/** Marker numbers for omitted TLVs (type 244) */
|
|
30
|
+
omittedTlvs: bigint[];
|
|
31
|
+
/** Missing merkle branch hashes (type 246) */
|
|
32
|
+
missingHashes: Uint8Array[];
|
|
33
|
+
/** Nonce hashes for included non-signature TLVs (type 248) */
|
|
34
|
+
leafHashes: Uint8Array[];
|
|
35
|
+
/** Payer signature (type 250) */
|
|
36
|
+
payerSignature: Uint8Array;
|
|
37
|
+
/** Optional note from payer_signature (type 250) */
|
|
38
|
+
payerNote: string;
|
|
39
|
+
/** invoice_payment_hash for preimage verification */
|
|
40
|
+
invoicePaymentHash: Uint8Array;
|
|
41
|
+
/** invoice_node_id for signature verification */
|
|
42
|
+
invoiceNodeId: Uint8Array;
|
|
43
|
+
/** invreq_payer_id for payer_signature verification */
|
|
44
|
+
payerId: Uint8Array;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse and validate a payer proof's TLV records.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parsePayerProof(records: TlvRecord[]): PayerProofFields;
|
|
50
|
+
/**
|
|
51
|
+
* Reconstruct the Merkle root from a payer proof.
|
|
52
|
+
*
|
|
53
|
+
* The tree has N positions: 1 implicit (type 0) + omitted markers + included records.
|
|
54
|
+
* Uses recursive DFS tree building to consume missing_hashes in the correct order.
|
|
55
|
+
*/
|
|
56
|
+
export declare function reconstructMerkleRoot(proof: PayerProofFields): Uint8Array;
|
|
57
|
+
/**
|
|
58
|
+
* Verify a payer proof's signatures.
|
|
59
|
+
*/
|
|
60
|
+
export declare function verifyPayerProof(proof: PayerProofFields): {
|
|
61
|
+
valid: boolean;
|
|
62
|
+
merkleRoot: Uint8Array;
|
|
63
|
+
error?: string;
|
|
64
|
+
};
|
|
65
|
+
export interface CreatePayerProofParams {
|
|
66
|
+
/** Hex-encoded invoice TLV stream */
|
|
67
|
+
invoiceHex: string;
|
|
68
|
+
/** Hex-encoded 32-byte payment preimage */
|
|
69
|
+
preimageHex: string;
|
|
70
|
+
/** Hex-encoded 32-byte payer secret key (for BIP-340 signing) */
|
|
71
|
+
payerSecretKeyHex: string;
|
|
72
|
+
/** Additional TLV types to include beyond the required ones */
|
|
73
|
+
includedTlvTypes?: number[];
|
|
74
|
+
/** Optional payer note (UTF-8) */
|
|
75
|
+
note?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface CreatePayerProofResult {
|
|
78
|
+
/** Hex-encoded proof TLV stream */
|
|
79
|
+
proofHex: string;
|
|
80
|
+
/** Bech32-encoded proof with "lnp" prefix */
|
|
81
|
+
proofBech32: string;
|
|
82
|
+
/** 32-byte merkle root */
|
|
83
|
+
merkleRoot: Uint8Array;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create a BOLT12 payer proof from an invoice, preimage, and payer secret key.
|
|
87
|
+
*/
|
|
88
|
+
export declare function createPayerProof(params: CreatePayerProofParams): CreatePayerProofResult;
|
|
89
|
+
//# sourceMappingURL=payer_proof.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payer_proof.d.ts","sourceRoot":"","sources":["../src/payer_proof.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAgB1C,eAAO,MAAM,WAAW,OAAO,CAAC;AAChC,eAAO,MAAM,eAAe,OAAO,CAAC;AACpC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,cAAc,OAAO,CAAC;AACnC,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAwDvC,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,eAAe,EAAE,SAAS,EAAE,CAAC;IAC7B,uCAAuC;IACvC,SAAS,EAAE,UAAU,CAAC;IACtB,4CAA4C;IAC5C,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,iDAAiD;IACjD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,8CAA8C;IAC9C,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,8DAA8D;IAC9D,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,iCAAiC;IACjC,cAAc,EAAE,UAAU,CAAC;IAC3B,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,kBAAkB,EAAE,UAAU,CAAC;IAC/B,iDAAiD;IACjD,aAAa,EAAE,UAAU,CAAC;IAC1B,uDAAuD;IACvD,OAAO,EAAE,UAAU,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,gBAAgB,CA+HtE;AAiHD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,gBAAgB,GAAG,UAAU,CA0CzE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAqCA;AAID,MAAM,WAAW,sBAAsB;IACrC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,UAAU,EAAE,UAAU,CAAC;CACxB;AAuHD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,sBAAsB,CA2HvF"}
|