Skip to content

Commit 4502d21

Browse files
chore(utxo-lib): removed functions as class methods and became util func
TICKET: BTC-2183
1 parent e40a0e2 commit 4502d21

File tree

7 files changed

+168
-205
lines changed

7 files changed

+168
-205
lines changed

modules/utxo-lib/src/bitgo/Musig2.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,8 @@ import { Tuple } from './types';
1212
import { calculateTapTweak, tapTweakPubkey } from '../taproot';
1313
import { Transaction } from '../index';
1414
import { PsbtInput } from 'bip174/src/lib/interfaces';
15-
import {
16-
getPsbtInputProprietaryKeyVals,
17-
ProprietaryKeySubtype,
18-
ProprietaryKeyValue,
19-
PSBT_PROPRIETARY_IDENTIFIER,
20-
} from './PsbtUtil';
15+
import { getPsbtInputProprietaryKeyVals, ProprietaryKeySubtype, PSBT_PROPRIETARY_IDENTIFIER } from './PsbtUtil';
16+
import { ProprietaryKeyValue } from './ProprietaryKeyValUtils';
2117

2218
/**
2319
* Participant key value object.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { KeyValue } from 'bip174/src/lib/interfaces';
2+
import { decodeProprietaryKey, encodeProprietaryKey, ProprietaryKey } from 'bip174/src/lib/proprietaryKeyVal';
3+
import { UtxoPsbt } from './UtxoPsbt';
4+
5+
/**
6+
* Psbt proprietary keydata object search fields.
7+
* <compact size uint identifier length> <bytes identifier> <compact size uint subtype> <bytes subkeydata>
8+
*/
9+
export interface ProprietaryKeySearch {
10+
identifier: string;
11+
subtype?: number;
12+
keydata?: Buffer;
13+
identifierEncoding?: BufferEncoding;
14+
}
15+
/**
16+
* Psbt proprietary keydata object.
17+
* <compact size uint identifier length> <bytes identifier> <compact size uint subtype> <bytes subkeydata>
18+
* => <bytes valuedata>
19+
*/
20+
export interface ProprietaryKeyValue {
21+
key: ProprietaryKey;
22+
value: Buffer;
23+
}
24+
25+
export interface WithUnknownKeyValues {
26+
unknownKeyVals?: KeyValue[];
27+
}
28+
29+
export function getProprietaryKeyValuesFromUnknownKeyValues(
30+
psbtField: WithUnknownKeyValues,
31+
keySearch?: ProprietaryKeySearch
32+
): ProprietaryKeyValue[] {
33+
if (!psbtField.unknownKeyVals?.length) {
34+
return [];
35+
}
36+
37+
if (keySearch && keySearch.subtype === undefined && Buffer.isBuffer(keySearch.keydata)) {
38+
throw new Error('invalid proprietary key search filter combination. subtype is required');
39+
}
40+
const keyVals = psbtField.unknownKeyVals.map(({ key, value }, i) => {
41+
return { key: decodeProprietaryKey(key), value };
42+
});
43+
return keyVals.filter((keyVal) => {
44+
return (
45+
keySearch === undefined ||
46+
(keySearch.identifier === keyVal.key.identifier &&
47+
(keySearch.subtype === undefined ||
48+
(keySearch.subtype === keyVal.key.subtype &&
49+
(!Buffer.isBuffer(keySearch.keydata) || keySearch.keydata.equals(keyVal.key.keydata)))))
50+
);
51+
});
52+
}
53+
54+
export function deleteProprietaryKeyValuesFromUnknownKeyValues(
55+
psbtField: WithUnknownKeyValues,
56+
keysToDelete?: ProprietaryKeySearch
57+
): void {
58+
if (!psbtField.unknownKeyVals?.length) {
59+
return;
60+
}
61+
62+
if (keysToDelete && keysToDelete.subtype === undefined && Buffer.isBuffer(keysToDelete.keydata)) {
63+
throw new Error('invalid proprietary key search filter combination. subtype is required');
64+
}
65+
psbtField.unknownKeyVals = psbtField.unknownKeyVals.filter((keyValue, i) => {
66+
const key = decodeProprietaryKey(keyValue.key);
67+
return !(
68+
keysToDelete === undefined ||
69+
(keysToDelete.identifier === key.identifier &&
70+
(keysToDelete.subtype === undefined ||
71+
(keysToDelete.subtype === key.subtype &&
72+
(!Buffer.isBuffer(keysToDelete.keydata) || keysToDelete.keydata.equals(key.keydata)))))
73+
);
74+
});
75+
}
76+
77+
export function updateProprietaryKeyValuesToUnknownKeyValues(
78+
keyValueData: ProprietaryKeyValue,
79+
psbtField: WithUnknownKeyValues
80+
): void {
81+
if (!psbtField.unknownKeyVals?.length) {
82+
return;
83+
}
84+
85+
const key = encodeProprietaryKey(keyValueData.key);
86+
const { value } = keyValueData;
87+
const ukvIndex = psbtField.unknownKeyVals.findIndex((ukv) => ukv.key.equals(key));
88+
if (ukvIndex <= -1) {
89+
throw new Error(`The Key-Value pair does not exist within the PSBT.`);
90+
}
91+
psbtField.unknownKeyVals[ukvIndex] = { key, value };
92+
}
93+
94+
export function addProprietaryKeyValuesToUnknownKeyValues(
95+
psbt: UtxoPsbt,
96+
entry: string,
97+
index: number,
98+
keyValueData: ProprietaryKeyValue
99+
): void {
100+
if (index < 0) {
101+
throw new Error('Not a valid index within the PSBT to add proprietary key value.');
102+
}
103+
if (entry === 'input') {
104+
psbt.addUnknownKeyValToInput(index, {
105+
key: encodeProprietaryKey(keyValueData.key),
106+
value: keyValueData.value,
107+
});
108+
} else if (entry === 'output') {
109+
psbt.addUnknownKeyValToOutput(index, {
110+
key: encodeProprietaryKey(keyValueData.key),
111+
value: keyValueData.value,
112+
});
113+
} else {
114+
throw new Error("Not a valid PSBT entry, only valid for 'input' or 'output'.");
115+
}
116+
}

modules/utxo-lib/src/bitgo/PsbtUtil.ts

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import { ProprietaryKey } from 'bip174/src/lib/proprietaryKeyVal';
21
import { PsbtInput, PsbtOutput } from 'bip174/src/lib/interfaces';
32
import { Psbt } from 'bitcoinjs-lib/src/psbt';
4-
import { getProprietaryKeyValuesFromUnknownKeyValues } from './psbt/ProprietaryKeyValUtils';
3+
4+
import {
5+
getProprietaryKeyValuesFromUnknownKeyValues,
6+
ProprietaryKeySearch,
7+
ProprietaryKeyValue,
8+
} from './ProprietaryKeyValUtils';
59

610
/**
711
* bitgo proprietary key identifier
@@ -18,27 +22,6 @@ export enum ProprietaryKeySubtype {
1822
MUSIG2_PARTIAL_SIG = 0x03,
1923
}
2024

21-
/**
22-
* Psbt proprietary keydata object.
23-
* <compact size uint identifier length> <bytes identifier> <compact size uint subtype> <bytes subkeydata>
24-
* => <bytes valuedata>
25-
*/
26-
export interface ProprietaryKeyValue {
27-
key: ProprietaryKey;
28-
value: Buffer;
29-
}
30-
31-
/**
32-
* Psbt proprietary keydata object search fields.
33-
* <compact size uint identifier length> <bytes identifier> <compact size uint subtype> <bytes subkeydata>
34-
*/
35-
export interface ProprietaryKeySearch {
36-
identifier: string;
37-
subtype?: number;
38-
keydata?: Buffer;
39-
identifierEncoding?: BufferEncoding;
40-
}
41-
4225
/**
4326
* Search any data from psbt proprietary key value against keydata.
4427
* Default identifierEncoding is utf-8 for identifier.
@@ -50,7 +33,7 @@ export function getPsbtInputProprietaryKeyVals(
5033
if (!input.unknownKeyVals?.length) {
5134
return [];
5235
}
53-
return getProprietaryKeyValuesFromUnknownKeyValues(input.unknownKeyVals, keySearch);
36+
return getProprietaryKeyValuesFromUnknownKeyValues(input, keySearch);
5437
}
5538

5639
export function getPsbtOutputProprietaryKeyVals(
@@ -60,7 +43,7 @@ export function getPsbtOutputProprietaryKeyVals(
6043
if (!output.unknownKeyVals?.length) {
6144
return [];
6245
}
63-
return getProprietaryKeyValuesFromUnknownKeyValues(output.unknownKeyVals, keySearch);
46+
return getProprietaryKeyValuesFromUnknownKeyValues(output, keySearch);
6447
}
6548

6649
/**
@@ -79,12 +62,14 @@ export function getPsbtInputSignatureCount(input: PsbtInput): number {
7962
}).length
8063
);
8164
}
65+
8266
/**
8367
* @return true iff PSBT input is finalized
8468
*/
8569
export function isPsbtInputFinalized(input: PsbtInput): boolean {
8670
return Buffer.isBuffer(input.finalScriptSig) || Buffer.isBuffer(input.finalScriptWitness);
8771
}
72+
8873
/**
8974
* @return true iff data starts with magic PSBT byte sequence
9075
* @param data byte array or hex string
@@ -100,6 +85,7 @@ export function isPsbt(data: Buffer | string): boolean {
10085
}
10186
return 5 <= data.length && data.readUInt32BE(0) === 0x70736274 && data.readUInt8(4) === 0xff;
10287
}
88+
10389
/**
10490
* First checks if the input is already a buffer that starts with the magic PSBT byte sequence.
10591
* If not, it checks if the input is a base64- or hex-encoded string that starts with PSBT header.
@@ -117,9 +103,11 @@ export function toPsbtBuffer(data: Buffer | string): Buffer {
117103
if (isPsbt(data)) {
118104
return data;
119105
}
106+
120107
// we could be dealing with a buffer that could be a hex or base64 encoded psbt
121108
data = data.toString('ascii');
122109
}
110+
123111
if (typeof data === 'string') {
124112
const encodings = ['hex', 'base64'] as const;
125113
for (const encoding of encodings) {
@@ -133,10 +121,13 @@ export function toPsbtBuffer(data: Buffer | string): Buffer {
133121
return buffer;
134122
}
135123
}
124+
136125
throw new Error(`data is not in any of the following formats: ${encodings.join(', ')}`);
137126
}
127+
138128
throw new Error('data must be a buffer or a string');
139129
}
130+
140131
/**
141132
* This function allows signing or validating a psbt with non-segwit inputs those do not contain nonWitnessUtxo.
142133
*/

modules/utxo-lib/src/bitgo/UtxoPsbt.ts

Lines changed: 2 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
Transaction as ITransaction,
88
TransactionFromBuffer,
99
} from 'bip174/src/lib/interfaces';
10-
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
10+
import { checkForInput } from 'bip174/src/lib/utils';
1111
import { BufferWriter, varuint } from 'bitcoinjs-lib/src/bufferutils';
1212
import { SessionKey } from '@brandonblack/musig';
1313
import { BIP32Factory, BIP32Interface } from 'bip32';
@@ -57,17 +57,10 @@ import { getTaprootOutputKey } from '../taproot';
5757
import {
5858
getPsbtInputProprietaryKeyVals,
5959
getPsbtInputSignatureCount,
60-
getPsbtOutputProprietaryKeyVals,
61-
ProprietaryKeySearch,
6260
ProprietaryKeySubtype,
63-
ProprietaryKeyValue,
6461
PSBT_PROPRIETARY_IDENTIFIER,
6562
} from './PsbtUtil';
66-
import {
67-
deleteProprietaryKeyValuesFromUnknownKeyValues,
68-
UnknownKeyValsType,
69-
updateProprietaryKeyValuesToUnknownKeyValues,
70-
} from './psbt/ProprietaryKeyValUtils';
63+
import { ProprietaryKeySearch, ProprietaryKeyValue } from './ProprietaryKeyValUtils';
7164

7265
type SignatureParams = {
7366
/** When true, and add the second (last) nonce and signature for a taproot key
@@ -1158,96 +1151,6 @@ export class UtxoPsbt<Tx extends UtxoTransaction<bigint> = UtxoTransaction<bigin
11581151
return this;
11591152
}
11601153

1161-
addProprietaryKeyValues(type: UnknownKeyValsType, index: number, keyValueData: ProprietaryKeyValue): this {
1162-
switch (type) {
1163-
case 'input':
1164-
const input = checkForInput(this.data.inputs, index);
1165-
assert(input);
1166-
return this.addUnknownKeyValToInput(index, {
1167-
key: encodeProprietaryKey(keyValueData.key),
1168-
value: keyValueData.value,
1169-
});
1170-
case 'output':
1171-
const output = checkForOutput(this.data.outputs, index);
1172-
assert(output);
1173-
return this.addUnknownKeyValToOutput(index, {
1174-
key: encodeProprietaryKey(keyValueData.key),
1175-
value: keyValueData.value,
1176-
});
1177-
default:
1178-
throw new Error('There is no such type, something went wrong.');
1179-
}
1180-
}
1181-
1182-
addOrUpdateProprietaryKeyValues(type: UnknownKeyValsType, index: number, keyValueData: ProprietaryKeyValue): this {
1183-
const key = encodeProprietaryKey(keyValueData.key);
1184-
const { value } = keyValueData;
1185-
switch (type) {
1186-
case 'output':
1187-
const output = checkForOutput(this.data.outputs, index);
1188-
assert(output);
1189-
if (output.unknownKeyVals?.length) {
1190-
updateProprietaryKeyValuesToUnknownKeyValues(keyValueData, output.unknownKeyVals);
1191-
return this;
1192-
}
1193-
return this.addUnknownKeyValToOutput(index, {
1194-
key,
1195-
value,
1196-
});
1197-
case 'input':
1198-
const input = checkForInput(this.data.inputs, index);
1199-
assert(input);
1200-
if (input.unknownKeyVals?.length) {
1201-
updateProprietaryKeyValuesToUnknownKeyValues(keyValueData, input.unknownKeyVals);
1202-
return this;
1203-
}
1204-
return this.addUnknownKeyValToInput(index, {
1205-
key,
1206-
value,
1207-
});
1208-
default:
1209-
throw new Error('There is no such type. Something went wrong.');
1210-
}
1211-
}
1212-
1213-
getProprietaryKeyValues(
1214-
type: UnknownKeyValsType,
1215-
index: number,
1216-
keySearch?: ProprietaryKeySearch
1217-
): ProprietaryKeyValue[] {
1218-
switch (type) {
1219-
case 'input':
1220-
const input = checkForInput(this.data.inputs, index);
1221-
return getPsbtInputProprietaryKeyVals(input, keySearch);
1222-
case 'output':
1223-
const output = checkForOutput(this.data.outputs, index);
1224-
return getPsbtOutputProprietaryKeyVals(output, keySearch);
1225-
default:
1226-
throw new Error('There is no such type. Something went wrong.');
1227-
}
1228-
}
1229-
1230-
deleteProprietaryKeyValues(type: UnknownKeyValsType, index: number, keysToDelete?: ProprietaryKeySearch): this {
1231-
switch (type) {
1232-
case 'input':
1233-
const input = checkForInput(this.data.inputs, index);
1234-
if (!input.unknownKeyVals?.length) {
1235-
return this;
1236-
}
1237-
input.unknownKeyVals = deleteProprietaryKeyValuesFromUnknownKeyValues(input.unknownKeyVals, keysToDelete);
1238-
return this;
1239-
case 'output':
1240-
const output = checkForOutput(this.data.outputs, index);
1241-
if (!output.unknownKeyVals?.length) {
1242-
return this;
1243-
}
1244-
output.unknownKeyVals = deleteProprietaryKeyValuesFromUnknownKeyValues(output.unknownKeyVals, keysToDelete);
1245-
return this;
1246-
default:
1247-
throw new Error('There is no such type. Something went wrong.');
1248-
}
1249-
}
1250-
12511154
private createMusig2NonceForInput(
12521155
inputIndex: number,
12531156
keyPair: BIP32Interface,

modules/utxo-lib/src/bitgo/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export * from './zcash';
2121
export * from './tnumber';
2222
export * from './litecoin';
2323
export * from './PsbtUtil';
24+
export * from './ProprietaryKeyValUtils';
2425

2526
import { PsbtInput } from 'bip174/src/lib/interfaces';
2627
/**

0 commit comments

Comments
 (0)