Skip to content

Commit 5500d1c

Browse files
committed
Add silent payment psbt fields
1 parent 0aac96f commit 5500d1c

29 files changed

+1100
-9
lines changed

src/cjs/lib/converter/index.cjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,22 @@ const tapLeafScript = __importStar(require('./input/tapLeafScript.cjs'));
2727
const tapMerkleRoot = __importStar(require('./input/tapMerkleRoot.cjs'));
2828
const tapScriptSig = __importStar(require('./input/tapScriptSig.cjs'));
2929
const witnessUtxo = __importStar(require('./input/witnessUtxo.cjs'));
30+
const silentPaymentOutputLabel = __importStar(
31+
require('./output/silentPaymentOutputLabel.cjs'),
32+
);
33+
const silentPaymentV0Info = __importStar(
34+
require('./output/silentPaymentV0Info.cjs'),
35+
);
3036
const tapTree = __importStar(require('./output/tapTree.cjs'));
3137
const bip32Derivation = __importStar(require('./shared/bip32Derivation.cjs'));
3238
const checkPubkey = __importStar(require('./shared/checkPubkey.cjs'));
3339
const redeemScript = __importStar(require('./shared/redeemScript.cjs'));
40+
const silentPaymentDleq = __importStar(
41+
require('./shared/silentPaymentDleq.cjs'),
42+
);
43+
const silentPaymentEcdhShare = __importStar(
44+
require('./shared/silentPaymentEcdhShare.cjs'),
45+
);
3446
const tapBip32Derivation = __importStar(
3547
require('./shared/tapBip32Derivation.cjs'),
3648
);
@@ -41,6 +53,12 @@ const globals = {
4153
globalXpub,
4254
// pass an Array of key bytes that require pubkey beside the key
4355
checkPubkey: checkPubkey.makeChecker([]),
56+
silentPaymentEcdhShare: silentPaymentEcdhShare.makeConverter(
57+
typeFields_js_1.GlobalTypes.GLOBAL_SP_ECDH_SHARE,
58+
),
59+
silentPaymentDleq: silentPaymentDleq.makeConverter(
60+
typeFields_js_1.GlobalTypes.GLOBAL_SP_DLEQ,
61+
),
4462
};
4563
exports.globals = globals;
4664
const inputs = {
@@ -74,6 +92,12 @@ const inputs = {
7492
typeFields_js_1.InputTypes.TAP_INTERNAL_KEY,
7593
),
7694
tapMerkleRoot,
95+
silentPaymentEcdhShare: silentPaymentEcdhShare.makeConverter(
96+
typeFields_js_1.InputTypes.SP_ECDH_SHARE,
97+
),
98+
silentPaymentDleq: silentPaymentDleq.makeConverter(
99+
typeFields_js_1.InputTypes.SP_DLEQ,
100+
),
77101
};
78102
exports.inputs = inputs;
79103
const outputs = {
@@ -96,5 +120,7 @@ const outputs = {
96120
tapInternalKey: tapInternalKey.makeConverter(
97121
typeFields_js_1.OutputTypes.TAP_INTERNAL_KEY,
98122
),
123+
silentPaymentV0Info,
124+
silentPaymentOutputLabel,
99125
};
100126
exports.outputs = outputs;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
var __importStar =
3+
(this && this.__importStar) ||
4+
function(mod) {
5+
if (mod && mod.__esModule) return mod;
6+
var result = {};
7+
if (mod != null)
8+
for (var k in mod)
9+
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
10+
result['default'] = mod;
11+
return result;
12+
};
13+
Object.defineProperty(exports, '__esModule', { value: true });
14+
const typeFields_js_1 = require('../../typeFields.cjs');
15+
const tools = __importStar(require('uint8array-tools'));
16+
function decode(keyVal) {
17+
if (keyVal.key[0] !== typeFields_js_1.OutputTypes.SP_V0_LABEL) {
18+
throw new Error(
19+
'Decode Error: could not decode silentPaymentOutputLabel with key 0x' +
20+
tools.toHex(keyVal.key),
21+
);
22+
}
23+
return Number(tools.readUInt32(keyVal.value, 0, 'LE'));
24+
}
25+
exports.decode = decode;
26+
function encode(data) {
27+
const key = Uint8Array.from([typeFields_js_1.OutputTypes.SP_V0_LABEL]);
28+
const value = new Uint8Array(4);
29+
tools.writeUInt32(value, 0, data, 'LE');
30+
return {
31+
key,
32+
value,
33+
};
34+
}
35+
exports.encode = encode;
36+
exports.expected = 'number';
37+
function check(data) {
38+
return typeof data === 'number';
39+
}
40+
exports.check = check;
41+
function canAdd(currentData, newData) {
42+
return (
43+
!!currentData &&
44+
!!newData &&
45+
currentData.silentPaymentOutputLabel === undefined
46+
);
47+
}
48+
exports.canAdd = canAdd;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'use strict';
2+
var __importStar =
3+
(this && this.__importStar) ||
4+
function(mod) {
5+
if (mod && mod.__esModule) return mod;
6+
var result = {};
7+
if (mod != null)
8+
for (var k in mod)
9+
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
10+
result['default'] = mod;
11+
return result;
12+
};
13+
Object.defineProperty(exports, '__esModule', { value: true });
14+
const typeFields_js_1 = require('../../typeFields.cjs');
15+
const tools = __importStar(require('uint8array-tools'));
16+
const isValidPubKey = pubkey =>
17+
pubkey.length === 33 && [2, 3].includes(pubkey[0]);
18+
function decode(keyVal) {
19+
if (keyVal.key[0] !== typeFields_js_1.OutputTypes.SP_V0_INFO) {
20+
throw new Error(
21+
'Decode Error: could not decode silentPaymentV0Info with key 0x' +
22+
tools.toHex(keyVal.key),
23+
);
24+
}
25+
if (keyVal.value.length !== 66) {
26+
throw new Error('Decode Error: SP_V0_INFO is not proper length');
27+
}
28+
const scanKey = keyVal.value.slice(0, 33);
29+
if (!isValidPubKey(scanKey)) {
30+
throw new Error('Decode Error: SP_V0_INFO scanKey is not a valid pubkey');
31+
}
32+
const spendKey = keyVal.value.slice(33);
33+
if (!isValidPubKey(spendKey)) {
34+
throw new Error('Decode Error: SP_V0_INFO spendKey is not a valid pubkey');
35+
}
36+
return {
37+
scanKey,
38+
spendKey,
39+
};
40+
}
41+
exports.decode = decode;
42+
function encode(data) {
43+
const key = new Uint8Array([typeFields_js_1.OutputTypes.SP_V0_INFO]);
44+
return {
45+
key,
46+
value: Uint8Array.from([...data.scanKey, ...data.spendKey]),
47+
};
48+
}
49+
exports.encode = encode;
50+
exports.expected = '{ scanKey: Uint8Array; spendKey: Uint8Array; }';
51+
function check(data) {
52+
return (
53+
data.scanKey instanceof Uint8Array &&
54+
data.spendKey instanceof Uint8Array &&
55+
isValidPubKey(data.scanKey) &&
56+
isValidPubKey(data.spendKey)
57+
);
58+
}
59+
exports.check = check;
60+
function canAdd(currentData, newData) {
61+
return (
62+
!!currentData && !!newData && currentData.silentPaymentV0Info === undefined
63+
);
64+
}
65+
exports.canAdd = canAdd;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
'use strict';
2+
var __importStar =
3+
(this && this.__importStar) ||
4+
function(mod) {
5+
if (mod && mod.__esModule) return mod;
6+
var result = {};
7+
if (mod != null)
8+
for (var k in mod)
9+
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
10+
result['default'] = mod;
11+
return result;
12+
};
13+
Object.defineProperty(exports, '__esModule', { value: true });
14+
const tools = __importStar(require('uint8array-tools'));
15+
const isValidPubKey = pubkey =>
16+
pubkey.length === 33 && [2, 3].includes(pubkey[0]);
17+
function makeConverter(TYPE_BYTE, isValidPubkey = isValidPubKey) {
18+
function decode(keyVal) {
19+
if (keyVal.key[0] !== TYPE_BYTE) {
20+
throw new Error(
21+
'Decode Error: could not decode silentPaymentDleq with key 0x' +
22+
tools.toHex(keyVal.key),
23+
);
24+
}
25+
const scanKey = keyVal.key.slice(1);
26+
if (!isValidPubkey(scanKey)) {
27+
throw new Error(
28+
'Decode Error: silentPaymentDleq has invalid scanKey in key 0x' +
29+
tools.toHex(keyVal.key),
30+
);
31+
}
32+
if (keyVal.value.length !== 64) {
33+
throw new Error('Decode Error: silentPaymentDleq not a 64-byte proof');
34+
}
35+
return {
36+
scanKey,
37+
proof: keyVal.value,
38+
};
39+
}
40+
function encode(data) {
41+
const head = Uint8Array.from([TYPE_BYTE]);
42+
const key = tools.concat([head, data.scanKey]);
43+
return {
44+
key,
45+
value: data.proof,
46+
};
47+
}
48+
const expected = '{ scanKey: Uint8Array; proof: Uint8Array; }';
49+
function check(data) {
50+
return (
51+
data.scanKey instanceof Uint8Array &&
52+
data.proof instanceof Uint8Array &&
53+
isValidPubkey(data.scanKey) &&
54+
data.proof.length === 64
55+
);
56+
}
57+
function canAddToArray(array, item, dupeSet) {
58+
const dupeString = tools.toHex(item.scanKey);
59+
if (dupeSet.has(dupeString)) return false;
60+
dupeSet.add(dupeString);
61+
return (
62+
array.filter(v => tools.compare(v.scanKey, item.scanKey) === 0).length ===
63+
0
64+
);
65+
}
66+
return {
67+
decode,
68+
encode,
69+
check,
70+
expected,
71+
canAddToArray,
72+
};
73+
}
74+
exports.makeConverter = makeConverter;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
'use strict';
2+
var __importStar =
3+
(this && this.__importStar) ||
4+
function(mod) {
5+
if (mod && mod.__esModule) return mod;
6+
var result = {};
7+
if (mod != null)
8+
for (var k in mod)
9+
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
10+
result['default'] = mod;
11+
return result;
12+
};
13+
Object.defineProperty(exports, '__esModule', { value: true });
14+
const tools = __importStar(require('uint8array-tools'));
15+
const isValidDERKey = pubkey =>
16+
(pubkey.length === 33 && [2, 3].includes(pubkey[0])) ||
17+
(pubkey.length === 65 && 4 === pubkey[0]);
18+
function makeConverter(TYPE_BYTE, isValidPubkey = isValidDERKey) {
19+
function decode(keyVal) {
20+
if (keyVal.key[0] !== TYPE_BYTE) {
21+
throw new Error(
22+
'Decode Error: could not decode silentPaymentEcdhShare with key 0x' +
23+
tools.toHex(keyVal.key),
24+
);
25+
}
26+
const scanKey = keyVal.key.slice(1);
27+
if (!isValidPubkey(scanKey)) {
28+
throw new Error(
29+
'Decode Error: silentPaymentEcdhShare has invalid scanKey in key 0x' +
30+
tools.toHex(keyVal.key),
31+
);
32+
}
33+
if (!isValidPubkey(keyVal.value)) {
34+
throw new Error(
35+
'Decode Error: silentPaymentEcdhShare not a 33-byte pubkey',
36+
);
37+
}
38+
return {
39+
scanKey,
40+
share: keyVal.value,
41+
};
42+
}
43+
function encode(data) {
44+
const head = Uint8Array.from([TYPE_BYTE]);
45+
const key = tools.concat([head, data.scanKey]);
46+
return {
47+
key,
48+
value: data.share,
49+
};
50+
}
51+
const expected = '{ scanKey: Uint8Array; share: Uint8Array; }';
52+
function check(data) {
53+
return (
54+
data.scanKey instanceof Uint8Array &&
55+
data.share instanceof Uint8Array &&
56+
isValidPubkey(data.scanKey) &&
57+
isValidPubkey(data.share)
58+
);
59+
}
60+
function canAddToArray(array, item, dupeSet) {
61+
const dupeString = tools.toHex(item.scanKey);
62+
if (dupeSet.has(dupeString)) return false;
63+
dupeSet.add(dupeString);
64+
return (
65+
array.filter(v => tools.compare(v.scanKey, item.scanKey) === 0).length ===
66+
0
67+
);
68+
}
69+
return {
70+
decode,
71+
encode,
72+
check,
73+
expected,
74+
canAddToArray,
75+
};
76+
}
77+
exports.makeConverter = makeConverter;

src/cjs/lib/parser/fromBuffer.cjs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,22 @@ function psbtFromKeyVals(
172172
}
173173
globalMap.globalXpub.push(convert.globals.globalXpub.decode(keyVal));
174174
break;
175+
case typeFields_js_1.GlobalTypes.GLOBAL_SP_ECDH_SHARE:
176+
if (globalMap.silentPaymentEcdhShare === undefined) {
177+
globalMap.silentPaymentEcdhShare = [];
178+
}
179+
globalMap.silentPaymentEcdhShare.push(
180+
convert.globals.silentPaymentEcdhShare.decode(keyVal),
181+
);
182+
break;
183+
case typeFields_js_1.GlobalTypes.GLOBAL_SP_DLEQ:
184+
if (globalMap.silentPaymentDleq === undefined) {
185+
globalMap.silentPaymentDleq = [];
186+
}
187+
globalMap.silentPaymentDleq.push(
188+
convert.globals.silentPaymentDleq.decode(keyVal),
189+
);
190+
break;
175191
default:
176192
// This will allow inclusion during serialization.
177193
if (!globalMap.unknownKeyVals) globalMap.unknownKeyVals = [];
@@ -330,6 +346,22 @@ function psbtFromKeyVals(
330346
);
331347
input.tapMerkleRoot = convert.inputs.tapMerkleRoot.decode(keyVal);
332348
break;
349+
case typeFields_js_1.InputTypes.SP_ECDH_SHARE:
350+
if (input.silentPaymentEcdhShare === undefined) {
351+
input.silentPaymentEcdhShare = [];
352+
}
353+
input.silentPaymentEcdhShare.push(
354+
convert.inputs.silentPaymentEcdhShare.decode(keyVal),
355+
);
356+
break;
357+
case typeFields_js_1.InputTypes.SP_DLEQ:
358+
if (input.silentPaymentDleq === undefined) {
359+
input.silentPaymentDleq = [];
360+
}
361+
input.silentPaymentDleq.push(
362+
convert.inputs.silentPaymentDleq.decode(keyVal),
363+
);
364+
break;
333365
default:
334366
// This will allow inclusion during serialization.
335367
if (!input.unknownKeyVals) input.unknownKeyVals = [];
@@ -397,6 +429,26 @@ function psbtFromKeyVals(
397429
convert.outputs.tapBip32Derivation.decode(keyVal),
398430
);
399431
break;
432+
case typeFields_js_1.OutputTypes.SP_V0_INFO:
433+
checkKeyBuffer(
434+
'output',
435+
keyVal.key,
436+
typeFields_js_1.OutputTypes.SP_V0_INFO,
437+
);
438+
output.silentPaymentV0Info = convert.outputs.silentPaymentV0Info.decode(
439+
keyVal,
440+
);
441+
break;
442+
case typeFields_js_1.OutputTypes.SP_V0_LABEL:
443+
checkKeyBuffer(
444+
'output',
445+
keyVal.key,
446+
typeFields_js_1.OutputTypes.SP_V0_LABEL,
447+
);
448+
output.silentPaymentOutputLabel = convert.outputs.silentPaymentOutputLabel.decode(
449+
keyVal,
450+
);
451+
break;
400452
default:
401453
if (!output.unknownKeyVals) output.unknownKeyVals = [];
402454
output.unknownKeyVals.push(keyVal);

0 commit comments

Comments
 (0)