@bitgo/wasm-utxo 1.29.0 → 1.31.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.
@@ -62,6 +62,14 @@ export declare class BIP32 implements BIP32Interface {
62
62
  * @returns A BIP32 instance
63
63
  */
64
64
  static fromSeed(seed: Uint8Array, network?: string | null): BIP32;
65
+ /**
66
+ * Create a BIP32 master key from a string by hashing it with SHA256.
67
+ * Useful for deterministic test key generation.
68
+ * @param seedString - The seed string to hash
69
+ * @param network - Optional network string
70
+ * @returns A BIP32 instance
71
+ */
72
+ static fromSeedSha256(seedString: string, network?: string | null): BIP32;
65
73
  /**
66
74
  * Get the chain code as a Uint8Array
67
75
  */
@@ -63,6 +63,17 @@ class BIP32 {
63
63
  const wasm = wasm_utxo_js_1.WasmBIP32.from_seed(seed, network);
64
64
  return new BIP32(wasm);
65
65
  }
66
+ /**
67
+ * Create a BIP32 master key from a string by hashing it with SHA256.
68
+ * Useful for deterministic test key generation.
69
+ * @param seedString - The seed string to hash
70
+ * @param network - Optional network string
71
+ * @returns A BIP32 instance
72
+ */
73
+ static fromSeedSha256(seedString, network) {
74
+ const wasm = wasm_utxo_js_1.WasmBIP32.from_seed_sha256(seedString, network);
75
+ return new BIP32(wasm);
76
+ }
66
77
  /**
67
78
  * Get the chain code as a Uint8Array
68
79
  */
@@ -543,4 +543,30 @@ export declare class BitGoPsbt {
543
543
  * @throws Error if the PSBT is not fully finalized or extraction fails
544
544
  */
545
545
  extractTransaction(): Uint8Array;
546
+ /**
547
+ * Extract a half-signed transaction in legacy format for p2ms-based script types.
548
+ *
549
+ * This method extracts a transaction where each input has exactly one signature,
550
+ * formatted in the legacy style used by utxo-lib and bitcoinjs-lib. The legacy
551
+ * format places signatures in the correct position (0, 1, or 2) based on which
552
+ * key signed, with empty placeholders for unsigned positions.
553
+ *
554
+ * Requirements:
555
+ * - All inputs must be p2ms-based (p2sh, p2shP2wsh, or p2wsh)
556
+ * - Each input must have exactly 1 partial signature
557
+ *
558
+ * @returns The serialized half-signed transaction bytes
559
+ * @throws Error if any input is not a p2ms type (Taproot, replay protection, etc.)
560
+ * @throws Error if any input has 0 or more than 1 partial signature
561
+ *
562
+ * @example
563
+ * ```typescript
564
+ * // Sign with user key only
565
+ * psbt.sign(userXpriv);
566
+ *
567
+ * // Extract half-signed transaction in legacy format
568
+ * const halfSignedTx = psbt.getHalfSignedLegacyFormat();
569
+ * ```
570
+ */
571
+ getHalfSignedLegacyFormat(): Uint8Array;
546
572
  }
@@ -497,5 +497,33 @@ class BitGoPsbt {
497
497
  extractTransaction() {
498
498
  return this._wasm.extract_transaction();
499
499
  }
500
+ /**
501
+ * Extract a half-signed transaction in legacy format for p2ms-based script types.
502
+ *
503
+ * This method extracts a transaction where each input has exactly one signature,
504
+ * formatted in the legacy style used by utxo-lib and bitcoinjs-lib. The legacy
505
+ * format places signatures in the correct position (0, 1, or 2) based on which
506
+ * key signed, with empty placeholders for unsigned positions.
507
+ *
508
+ * Requirements:
509
+ * - All inputs must be p2ms-based (p2sh, p2shP2wsh, or p2wsh)
510
+ * - Each input must have exactly 1 partial signature
511
+ *
512
+ * @returns The serialized half-signed transaction bytes
513
+ * @throws Error if any input is not a p2ms type (Taproot, replay protection, etc.)
514
+ * @throws Error if any input has 0 or more than 1 partial signature
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * // Sign with user key only
519
+ * psbt.sign(userXpriv);
520
+ *
521
+ * // Extract half-signed transaction in legacy format
522
+ * const halfSignedTx = psbt.getHalfSignedLegacyFormat();
523
+ * ```
524
+ */
525
+ getHalfSignedLegacyFormat() {
526
+ return this._wasm.extract_half_signed_legacy_tx();
527
+ }
500
528
  }
501
529
  exports.BitGoPsbt = BitGoPsbt;
@@ -6,6 +6,7 @@ export * as utxolibCompat from "./utxolibCompat.js";
6
6
  export * as fixedScriptWallet from "./fixedScriptWallet/index.js";
7
7
  export * as bip32 from "./bip32.js";
8
8
  export * as ecpair from "./ecpair.js";
9
+ export * as testutils from "./testutils/index.js";
9
10
  export { ECPair } from "./ecpair.js";
10
11
  export { BIP32 } from "./bip32.js";
11
12
  export { Dimensions } from "./fixedScriptWallet/Dimensions.js";
@@ -38,9 +39,24 @@ declare module "./wasm/wasm_utxo.js" {
38
39
  interface WrapPsbt {
39
40
  signWithXprv(this: WrapPsbt, xprv: string): SignPsbtResult;
40
41
  signWithPrv(this: WrapPsbt, prv: Uint8Array): SignPsbtResult;
42
+ signAll(this: WrapPsbt, key: WasmBIP32): SignPsbtResult;
43
+ signAllWithEcpair(this: WrapPsbt, key: WasmECPair): SignPsbtResult;
44
+ inputCount(): number;
45
+ outputCount(): number;
46
+ getPartialSignatures(inputIndex: number): Array<{
47
+ pubkey: Uint8Array;
48
+ signature: Uint8Array;
49
+ }>;
50
+ hasPartialSignatures(inputIndex: number): boolean;
51
+ validateSignatureAtInput(inputIndex: number, pubkey: Uint8Array): boolean;
52
+ verifySignatureWithKey(inputIndex: number, key: WasmBIP32): boolean;
53
+ unsignedTxId(): string;
54
+ lockTime(): number;
55
+ version(): number;
41
56
  }
42
57
  }
43
58
  export { WrapDescriptor as Descriptor } from "./wasm/wasm_utxo.js";
44
59
  export { WrapMiniscript as Miniscript } from "./wasm/wasm_utxo.js";
45
60
  export { WrapPsbt as Psbt } from "./wasm/wasm_utxo.js";
46
61
  export { DashTransaction, Transaction, ZcashTransaction } from "./transaction.js";
62
+ export { hasPsbtMagic } from "./psbt.js";
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.ZcashTransaction = exports.Transaction = exports.DashTransaction = exports.Psbt = exports.Miniscript = exports.Descriptor = exports.Dimensions = exports.BIP32 = exports.ECPair = exports.ecpair = exports.bip32 = exports.fixedScriptWallet = exports.utxolibCompat = exports.inscriptions = exports.bip322 = exports.ast = exports.address = void 0;
36
+ exports.hasPsbtMagic = exports.ZcashTransaction = exports.Transaction = exports.DashTransaction = exports.Psbt = exports.Miniscript = exports.Descriptor = exports.Dimensions = exports.BIP32 = exports.ECPair = exports.testutils = exports.ecpair = exports.bip32 = exports.fixedScriptWallet = exports.utxolibCompat = exports.inscriptions = exports.bip322 = exports.ast = exports.address = void 0;
37
37
  const wasm = __importStar(require("./wasm/wasm_utxo.js"));
38
38
  // we need to access the wasm module here, otherwise webpack gets all weird
39
39
  // and forgets to include it in the bundle
@@ -48,6 +48,7 @@ exports.utxolibCompat = __importStar(require("./utxolibCompat.js"));
48
48
  exports.fixedScriptWallet = __importStar(require("./fixedScriptWallet/index.js"));
49
49
  exports.bip32 = __importStar(require("./bip32.js"));
50
50
  exports.ecpair = __importStar(require("./ecpair.js"));
51
+ exports.testutils = __importStar(require("./testutils/index.js"));
51
52
  // Only the most commonly used classes and types are exported at the top level for convenience
52
53
  var ecpair_js_1 = require("./ecpair.js");
53
54
  Object.defineProperty(exports, "ECPair", { enumerable: true, get: function () { return ecpair_js_1.ECPair; } });
@@ -65,3 +66,5 @@ var transaction_js_1 = require("./transaction.js");
65
66
  Object.defineProperty(exports, "DashTransaction", { enumerable: true, get: function () { return transaction_js_1.DashTransaction; } });
66
67
  Object.defineProperty(exports, "Transaction", { enumerable: true, get: function () { return transaction_js_1.Transaction; } });
67
68
  Object.defineProperty(exports, "ZcashTransaction", { enumerable: true, get: function () { return transaction_js_1.ZcashTransaction; } });
69
+ var psbt_js_1 = require("./psbt.js");
70
+ Object.defineProperty(exports, "hasPsbtMagic", { enumerable: true, get: function () { return psbt_js_1.hasPsbtMagic; } });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Check if a byte array has the PSBT magic bytes
3
+ *
4
+ * PSBTs start with the magic bytes "psbt" (0x70 0x73 0x62 0x74) followed by a separator 0xff.
5
+ * This method checks if the given bytes start with these 5 magic bytes.
6
+ *
7
+ * @param bytes - The byte array to check
8
+ * @returns true if the bytes start with PSBT magic, false otherwise
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { hasPsbtMagic } from "@bitgo/wasm-utxo";
13
+ *
14
+ * if (hasPsbtMagic(data)) {
15
+ * const psbt = BitGoPsbt.fromBytes(data, network);
16
+ * }
17
+ * ```
18
+ */
19
+ export declare function hasPsbtMagic(bytes: Uint8Array): boolean;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasPsbtMagic = hasPsbtMagic;
4
+ /** PSBT magic bytes: "psbt" (0x70 0x73 0x62 0x74) followed by separator 0xff */
5
+ const PSBT_MAGIC = new Uint8Array([0x70, 0x73, 0x62, 0x74, 0xff]);
6
+ /**
7
+ * Check if a byte array has the PSBT magic bytes
8
+ *
9
+ * PSBTs start with the magic bytes "psbt" (0x70 0x73 0x62 0x74) followed by a separator 0xff.
10
+ * This method checks if the given bytes start with these 5 magic bytes.
11
+ *
12
+ * @param bytes - The byte array to check
13
+ * @returns true if the bytes start with PSBT magic, false otherwise
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { hasPsbtMagic } from "@bitgo/wasm-utxo";
18
+ *
19
+ * if (hasPsbtMagic(data)) {
20
+ * const psbt = BitGoPsbt.fromBytes(data, network);
21
+ * }
22
+ * ```
23
+ */
24
+ function hasPsbtMagic(bytes) {
25
+ if (bytes.length < PSBT_MAGIC.length) {
26
+ return false;
27
+ }
28
+ for (let i = 0; i < PSBT_MAGIC.length; i++) {
29
+ if (bytes[i] !== PSBT_MAGIC[i]) {
30
+ return false;
31
+ }
32
+ }
33
+ return true;
34
+ }
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.getKey = getKey;
37
4
  exports.getKeyTriple = getKeyTriple;
@@ -39,7 +6,6 @@ exports.getWalletKeysForSeed = getWalletKeysForSeed;
39
6
  exports.getDefaultWalletKeys = getDefaultWalletKeys;
40
7
  exports.getKeyName = getKeyName;
41
8
  exports.getDefaultCosigner = getDefaultCosigner;
42
- const crypto = __importStar(require("crypto"));
43
9
  const bip32_js_1 = require("../bip32.js");
44
10
  const RootWalletKeys_js_1 = require("../fixedScriptWallet/RootWalletKeys.js");
45
11
  /**
@@ -56,7 +22,7 @@ const RootWalletKeys_js_1 = require("../fixedScriptWallet/RootWalletKeys.js");
56
22
  * ```
57
23
  */
58
24
  function getKey(seed) {
59
- return bip32_js_1.BIP32.fromSeed(crypto.createHash("sha256").update(seed).digest());
25
+ return bip32_js_1.BIP32.fromSeedSha256(seed);
60
26
  }
61
27
  /**
62
28
  * Generate a triple of BIP32 keys for a 2-of-3 multisig wallet.
@@ -537,6 +537,27 @@ export class BitGoPsbt {
537
537
  * - `Err(WasmUtxoError)` if signing fails
538
538
  */
539
539
  sign_single_input_with_xpriv(input_index: number, xpriv: WasmBIP32): void;
540
+ /**
541
+ * Extract a half-signed transaction in legacy format for p2ms-based script types.
542
+ *
543
+ * This method extracts a transaction where each input has exactly one signature,
544
+ * formatted in the legacy style used by utxo-lib and bitcoinjs-lib. The legacy
545
+ * format places signatures in the correct position (0, 1, or 2) based on which
546
+ * key signed, with empty placeholders for unsigned positions.
547
+ *
548
+ * # Requirements
549
+ * - All inputs must be p2ms-based (p2sh, p2shP2wsh, or p2wsh)
550
+ * - Each input must have exactly 1 partial signature
551
+ *
552
+ * # Returns
553
+ * - `Ok(Vec<u8>)` containing the serialized half-signed transaction bytes
554
+ * - `Err(WasmUtxoError)` if validation fails or extraction fails
555
+ *
556
+ * # Errors
557
+ * - Returns error if any input is not a p2ms type (Taproot, replay protection, etc.)
558
+ * - Returns error if any input has 0 or more than 1 partial signature
559
+ */
560
+ extract_half_signed_legacy_tx(): Uint8Array;
540
561
  /**
541
562
  * Sign all replay protection inputs with a raw private key.
542
563
  *
@@ -772,6 +793,11 @@ export class WasmBIP32 {
772
793
  * Derive a hardened child key (only works for private keys)
773
794
  */
774
795
  derive_hardened(index: number): WasmBIP32;
796
+ /**
797
+ * Create a BIP32 master key from a string by hashing it with SHA256.
798
+ * This is useful for deterministic test key generation.
799
+ */
800
+ static from_seed_sha256(seed_string: string, network?: string | null): WasmBIP32;
775
801
  /**
776
802
  * Create a BIP32 key from a BIP32Interface JavaScript object properties
777
803
  * Expects an object with: network.bip32.public, depth, parentFingerprint,
@@ -1160,9 +1186,21 @@ export class WrapPsbt {
1160
1186
  */
1161
1187
  addOutput(script: Uint8Array, value: bigint): number;
1162
1188
  static deserialize(psbt: Uint8Array): WrapPsbt;
1189
+ /**
1190
+ * Get the number of inputs in the PSBT
1191
+ */
1192
+ inputCount(): number;
1163
1193
  finalize(): void;
1194
+ /**
1195
+ * Get the number of outputs in the PSBT
1196
+ */
1197
+ outputCount(): number;
1164
1198
  signWithPrv(prv: Uint8Array): any;
1165
1199
  signWithXprv(xprv: string): any;
1200
+ /**
1201
+ * Get the unsigned transaction ID as a hex string
1202
+ */
1203
+ unsignedTxId(): string;
1166
1204
  /**
1167
1205
  * Get the unsigned transaction bytes
1168
1206
  *
@@ -1170,6 +1208,53 @@ export class WrapPsbt {
1170
1208
  * The serialized unsigned transaction
1171
1209
  */
1172
1210
  getUnsignedTx(): Uint8Array;
1211
+ /**
1212
+ * Sign all inputs with a WasmECPair key
1213
+ *
1214
+ * This method signs all inputs using the private key from the ECPair.
1215
+ * Returns a map of input indices to the public keys that were signed.
1216
+ *
1217
+ * # Arguments
1218
+ * * `key` - The WasmECPair key to sign with
1219
+ *
1220
+ * # Returns
1221
+ * A SigningKeysMap converted to JsValue (object mapping input indices to signing keys)
1222
+ */
1223
+ signAllWithEcpair(key: WasmECPair): any;
1224
+ /**
1225
+ * Get partial signatures for an input
1226
+ * Returns array of { pubkey: Uint8Array, signature: Uint8Array }
1227
+ */
1228
+ getPartialSignatures(input_index: number): any;
1229
+ /**
1230
+ * Check if an input has any partial signatures
1231
+ */
1232
+ hasPartialSignatures(input_index: number): boolean;
1233
+ /**
1234
+ * Verify a signature at a specific input using a WasmBIP32 key
1235
+ *
1236
+ * This method verifies if a valid signature exists for the given BIP32 key at the specified input.
1237
+ * It handles both ECDSA (legacy/SegWit) and Schnorr (Taproot) signatures.
1238
+ *
1239
+ * Note: This method checks if the key's public key matches any signature in the input.
1240
+ * For proper BIP32 verification, the key should be derived to the correct path first.
1241
+ *
1242
+ * # Arguments
1243
+ * * `input_index` - The index of the input to check
1244
+ * * `key` - The WasmBIP32 key to verify against
1245
+ *
1246
+ * # Returns
1247
+ * `true` if a valid signature exists for the key, `false` otherwise
1248
+ */
1249
+ verifySignatureWithKey(input_index: number, key: WasmBIP32): boolean;
1250
+ /**
1251
+ * Validate a signature at a specific input against a pubkey
1252
+ * Returns true if the signature is valid
1253
+ *
1254
+ * This method handles both ECDSA (legacy/SegWit) and Schnorr (Taproot) signatures.
1255
+ * The pubkey should be provided as bytes (33 bytes for compressed ECDSA, 32 bytes for x-only Schnorr).
1256
+ */
1257
+ validateSignatureAtInput(input_index: number, pubkey: Uint8Array): boolean;
1173
1258
  updateInputWithDescriptor(input_index: number, descriptor: WrapDescriptor): void;
1174
1259
  updateOutputWithDescriptor(output_index: number, descriptor: WrapDescriptor): void;
1175
1260
  /**
@@ -1181,6 +1266,23 @@ export class WrapPsbt {
1181
1266
  */
1182
1267
  constructor(version?: number | null, lock_time?: number | null);
1183
1268
  clone(): WrapPsbt;
1269
+ /**
1270
+ * Get the transaction version
1271
+ */
1272
+ version(): number;
1273
+ /**
1274
+ * Sign all inputs with a WasmBIP32 key
1275
+ *
1276
+ * This method signs all inputs that match the BIP32 derivation paths in the PSBT.
1277
+ * Returns a map of input indices to the public keys that were signed.
1278
+ *
1279
+ * # Arguments
1280
+ * * `key` - The WasmBIP32 key to sign with
1281
+ *
1282
+ * # Returns
1283
+ * A SigningKeysMap converted to JsValue (object mapping input indices to signing keys)
1284
+ */
1285
+ signAll(key: WasmBIP32): any;
1184
1286
  /**
1185
1287
  * Add an input to the PSBT
1186
1288
  *
@@ -1195,5 +1297,9 @@ export class WrapPsbt {
1195
1297
  * The index of the newly added input
1196
1298
  */
1197
1299
  addInput(txid: string, vout: number, value: bigint, script: Uint8Array, sequence?: number | null): number;
1300
+ /**
1301
+ * Get the transaction lock time
1302
+ */
1303
+ lockTime(): number;
1198
1304
  serialize(): Uint8Array;
1199
1305
  }