@scure/btc-signer 1.0.1 → 1.1.1

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/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { secp256k1 as _secp, schnorr } from '@noble/curves/secp256k1';
3
3
  import { sha256 } from '@noble/hashes/sha256';
4
4
  import { ripemd160 } from '@noble/hashes/ripemd160';
5
- import { hex, base58, base58check as _b58, bech32, bech32m } from '@scure/base';
5
+ import { hex, createBase58check, bech32, bech32m } from '@scure/base';
6
6
  import type { Coder } from '@scure/base';
7
7
  import * as P from 'micro-packed';
8
8
 
@@ -24,7 +24,7 @@ const hash160 = (msg: Bytes) => ripemd160(sha256(msg));
24
24
  const sha256x2 = (...msgs: Bytes[]) => sha256(sha256(concat(...msgs)));
25
25
  const concat = P.concatBytes;
26
26
  // Make base58check work
27
- export const base58check = _b58(sha256);
27
+ export const base58check = createBase58check(sha256);
28
28
 
29
29
  export function cloneDeep<T>(obj: T): T {
30
30
  if (Array.isArray(obj)) return obj.map((i) => cloneDeep(i)) as unknown as T;
@@ -327,6 +327,7 @@ export function OpToNum(op: ScriptOP, bytesLimit = 4, forceMinimal = true) {
327
327
  return;
328
328
  }
329
329
  }
330
+ return;
330
331
  }
331
332
 
332
333
  // BTC specific variable length integer encoding
@@ -680,8 +681,8 @@ const PSBTInputCoder = P.validate(PSBTKeyMap(PSBTInput), (i) => {
680
681
  throw new Error('validateInput: wmpty finalScriptWitness');
681
682
  //if (i.finalScriptSig && !i.finalScriptSig.length) throw new Error('validateInput: empty finalScriptSig');
682
683
  if (i.partialSig && !i.partialSig.length) throw new Error('Empty partialSig');
683
- if (i.partialSig) for (const [k, v] of i.partialSig) validatePubkey(k, PubT.ecdsa);
684
- if (i.bip32Derivation) for (const [k, v] of i.bip32Derivation) validatePubkey(k, PubT.ecdsa);
684
+ if (i.partialSig) for (const [k] of i.partialSig) validatePubkey(k, PubT.ecdsa);
685
+ if (i.bip32Derivation) for (const [k] of i.bip32Derivation) validatePubkey(k, PubT.ecdsa);
685
686
  // Locktime = unsigned little endian integer greater than or equal to 500000000 representing
686
687
  if (i.requiredTimeLocktime !== undefined && i.requiredTimeLocktime < 500000000)
687
688
  throw new Error(`validateInput: wrong timeLocktime=${i.requiredTimeLocktime}`);
@@ -724,7 +725,7 @@ const PSBTInputCoder = P.validate(PSBTKeyMap(PSBTInput), (i) => {
724
725
  });
725
726
 
726
727
  const PSBTOutputCoder = P.validate(PSBTKeyMap(PSBTOutput), (o) => {
727
- if (o.bip32Derivation) for (const [k, v] of o.bip32Derivation) validatePubkey(k, PubT.ecdsa);
728
+ if (o.bip32Derivation) for (const [k] of o.bip32Derivation) validatePubkey(k, PubT.ecdsa);
728
729
  return o;
729
730
  });
730
731
 
@@ -906,7 +907,7 @@ const TxHashIdx = P.struct({ txid: P.bytes(32, true), index: P.U32LE });
906
907
  // - generate input script
907
908
  // - generate address/output/redeem from user input
908
909
  // P2ret represents generic interface for all p2* methods
909
- type P2Ret = {
910
+ export type P2Ret = {
910
911
  type: string;
911
912
  script: Bytes;
912
913
  address?: string;
@@ -929,7 +930,9 @@ const OutPK: Coder<OptScript, OutPKType | undefined> = {
929
930
  },
930
931
  decode: (to: OutPKType): OptScript => (to.type === 'pk' ? [to.pubkey, 'CHECKSIG'] : undefined),
931
932
  };
933
+ // @ts-ignore
932
934
  export const p2pk = (pubkey: Bytes, network = NETWORK): P2Ret => {
935
+ // network is unused
933
936
  if (!isValidPubkey(pubkey, PubT.ecdsa)) throw new Error('P2PK: invalid publicKey');
934
937
  return {
935
938
  type: 'pk',
@@ -937,7 +940,7 @@ export const p2pk = (pubkey: Bytes, network = NETWORK): P2Ret => {
937
940
  };
938
941
  };
939
942
 
940
- // Publick Key Hash (P2PKH)
943
+ // Public Key Hash (P2PKH)
941
944
  type OutPKHType = { type: 'pkh'; hash: Bytes };
942
945
  const OutPKH: Coder<OptScript, OutPKHType | undefined> = {
943
946
  encode(from: ScriptType): OutPKHType | undefined {
@@ -1094,32 +1097,51 @@ export function taprootListToTree(taprootList: TaprootScriptList): TaprootScript
1094
1097
  return (last?.childs || last) as TaprootScriptTree;
1095
1098
  }
1096
1099
  type HashedTree =
1097
- | { type: 'leaf'; version?: number; script: Bytes; hash: Bytes; tapInternalKey?: Bytes }
1100
+ | { type: 'leaf'; version?: number; script: Bytes; hash: Bytes }
1098
1101
  | { type: 'branch'; left: HashedTree; right: HashedTree; hash: Bytes };
1099
- function checkTaprootScript(script: Bytes, allowUnknowOutput = false) {
1102
+ function checkTaprootScript(script: Bytes, internalPubKey: Bytes, allowUnknownOutputs = false) {
1100
1103
  const out = OutScript.decode(script);
1101
- if (out.type === 'unknown' && allowUnknowOutput) return;
1104
+ if (out.type === 'unknown' && allowUnknownOutputs) return;
1102
1105
  if (!['tr_ns', 'tr_ms'].includes(out.type))
1103
1106
  throw new Error(`P2TR: invalid leaf script=${out.type}`);
1107
+ const outms = out as OutTRNSType | OutTRMSType;
1108
+ if (!allowUnknownOutputs && outms.pubkeys) {
1109
+ for (const p of outms.pubkeys) {
1110
+ if (P.equalBytes(p, TAPROOT_UNSPENDABLE_KEY))
1111
+ throw new Error('Unspendable taproot key in leaf script');
1112
+ // It's likely a mistake at this point:
1113
+ // 1. p2tr(A, p2tr_ns(2, [A, B])) == p2tr(A, p2tr_pk(B)) (A or B key)
1114
+ // but will take more space and fees.
1115
+ // 2. For multi-sig p2tr(A, p2tr_ns(2, [A, B, C])) it's probably a security issue:
1116
+ // User creates 2 of 3 multisig of keys [A, B, C],
1117
+ // but key A always can spend whole output without signatures from other keys.
1118
+ // p2tr(A, p2tr_ns(2, [B, C, D])) is ok: A or (B and C) or (B and D) or (C and D)
1119
+ if (P.equalBytes(p, internalPubKey)) {
1120
+ throw new Error(
1121
+ 'Using P2TR with leaf script with same key as internal key is not supported'
1122
+ );
1123
+ }
1124
+ }
1125
+ }
1104
1126
  }
1105
- function taprootHashTree(tree: TaprootScriptTree, allowUnknowOutput = false): HashedTree {
1127
+ function taprootHashTree(
1128
+ tree: TaprootScriptTree,
1129
+ internalPubKey: Bytes,
1130
+ allowUnknownOutputs = false
1131
+ ): HashedTree {
1106
1132
  if (!tree) throw new Error('taprootHashTree: empty tree');
1107
1133
  if (Array.isArray(tree) && tree.length === 1) tree = tree[0];
1108
1134
  // Terminal node (leaf)
1109
1135
  if (!Array.isArray(tree)) {
1110
- const { leafVersion: version, script: leafScript, tapInternalKey } = tree;
1136
+ const { leafVersion: version, script: leafScript } = tree;
1111
1137
  // Earliest tree walk where we can validate tapScripts
1112
1138
  if (tree.tapLeafScript || (tree.tapMerkleRoot && !P.equalBytes(tree.tapMerkleRoot, P.EMPTY)))
1113
1139
  throw new Error('P2TR: tapRoot leafScript cannot have tree');
1114
- // Just to be sure that it is spendable
1115
- if (tapInternalKey && P.equalBytes(tapInternalKey, TAPROOT_UNSPENDABLE_KEY))
1116
- throw new Error('P2TR: tapRoot leafScript cannot have unspendble key');
1117
1140
  const script = typeof leafScript === 'string' ? hex.decode(leafScript) : leafScript;
1118
1141
  if (!isBytes(script)) throw new Error(`checkScript: wrong script type=${script}`);
1119
- checkTaprootScript(script, allowUnknowOutput);
1142
+ checkTaprootScript(script, internalPubKey, allowUnknownOutputs);
1120
1143
  return {
1121
1144
  type: 'leaf',
1122
- tapInternalKey,
1123
1145
  version,
1124
1146
  script,
1125
1147
  hash: tapLeafHash(script, version),
@@ -1130,8 +1152,8 @@ function taprootHashTree(tree: TaprootScriptTree, allowUnknowOutput = false): Ha
1130
1152
  if (tree.length !== 2) throw new Error('hashTree: non binary tree!');
1131
1153
  // branch
1132
1154
  // Both nodes should exist
1133
- const left = taprootHashTree(tree[0], allowUnknowOutput);
1134
- const right = taprootHashTree(tree[1], allowUnknowOutput);
1155
+ const left = taprootHashTree(tree[0], internalPubKey, allowUnknownOutputs);
1156
+ const right = taprootHashTree(tree[1], internalPubKey, allowUnknownOutputs);
1135
1157
  // We cannot swap left/right here, since it will change structure of tree
1136
1158
  let [lH, rH] = [left.hash, right.hash];
1137
1159
  if (_cmpBytes(rH, lH) === -1) [lH, rH] = [rH, lH];
@@ -1143,7 +1165,6 @@ type TaprootLeaf = {
1143
1165
  script: Bytes;
1144
1166
  hash: Bytes;
1145
1167
  path: Bytes[];
1146
- tapInternalKey?: Bytes;
1147
1168
  };
1148
1169
 
1149
1170
  type HashedTreeWithPath =
@@ -1197,7 +1218,7 @@ export function p2tr(
1197
1218
  internalPubKey?: Bytes | string,
1198
1219
  tree?: TaprootScriptTree,
1199
1220
  network = NETWORK,
1200
- allowUnknowOutput = false
1221
+ allowUnknownOutputs = false
1201
1222
  ): P2TROut {
1202
1223
  // Unspendable
1203
1224
  if (!internalPubKey && !tree) throw new Error('p2tr: should have pubKey or scriptTree (or both)');
@@ -1206,7 +1227,9 @@ export function p2tr(
1206
1227
  ? hex.decode(internalPubKey)
1207
1228
  : internalPubKey || TAPROOT_UNSPENDABLE_KEY;
1208
1229
  if (!isValidPubkey(pubKey, PubT.schnorr)) throw new Error('p2tr: non-schnorr pubkey');
1209
- let hashedTree = tree ? taprootAddPath(taprootHashTree(tree, allowUnknowOutput)) : undefined;
1230
+ let hashedTree = tree
1231
+ ? taprootAddPath(taprootHashTree(tree, pubKey, allowUnknownOutputs))
1232
+ : undefined;
1210
1233
  const tapMerkleRoot = hashedTree ? hashedTree.hash : undefined;
1211
1234
  const [tweakedPubkey, parity] = taprootTweakPubkey(pubKey, tapMerkleRoot || P.EMPTY);
1212
1235
  let leaves;
@@ -1215,7 +1238,7 @@ export function p2tr(
1215
1238
  ...l,
1216
1239
  controlBlock: TaprootControlBlock.encode({
1217
1240
  version: (l.version || TAP_LEAF_VERSION) + parity,
1218
- internalKey: l.tapInternalKey || pubKey,
1241
+ internalKey: pubKey,
1219
1242
  merklePath: l.path,
1220
1243
  }),
1221
1244
  }));
@@ -1351,7 +1374,7 @@ export function p2tr_ms(m: number, pubkeys: Bytes[], allowSamePubkeys = false) {
1351
1374
  script: OutScript.encode({ type: 'tr_ms', pubkeys, m }),
1352
1375
  };
1353
1376
  }
1354
- // Uknown output type
1377
+ // Unknown output type
1355
1378
  type OutUnknownType = { type: 'unknown'; script: Bytes };
1356
1379
  const OutUnknown: Coder<OptScript, OutUnknownType | undefined> = {
1357
1380
  encode(from: ScriptType): OutUnknownType | undefined {
@@ -1481,7 +1504,7 @@ export function Address(network = NETWORK) {
1481
1504
  if (version === 0 && data.length === 32) return { type: 'wsh', hash: data };
1482
1505
  else if (version === 0 && data.length === 20) return { type: 'wpkh', hash: data };
1483
1506
  else if (version === 1 && data.length === 32) return { type: 'tr', pubkey: data };
1484
- else throw new Error('Unkown witness program');
1507
+ else throw new Error('Unknown witness program');
1485
1508
  }
1486
1509
  const data = base58check.decode(address);
1487
1510
  if (data.length !== 21) throw new Error('Invalid base58 address');
@@ -1500,6 +1523,10 @@ export function Address(network = NETWORK) {
1500
1523
  }
1501
1524
  // /Address
1502
1525
 
1526
+ /**
1527
+ * Internal, exported only for backwards-compat. Use `SigHash` instead.
1528
+ * @deprecated
1529
+ */
1503
1530
  export enum SignatureHash {
1504
1531
  DEFAULT,
1505
1532
  ALL,
@@ -1507,7 +1534,23 @@ export enum SignatureHash {
1507
1534
  SINGLE,
1508
1535
  ANYONECANPAY = 0x80,
1509
1536
  }
1510
- export const SigHashCoder = P.apply(P.U32LE, P.coders.tsEnum(SignatureHash));
1537
+
1538
+ export enum SigHash {
1539
+ DEFAULT = SignatureHash.DEFAULT,
1540
+ ALL = SignatureHash.ALL,
1541
+ NONE = SignatureHash.NONE,
1542
+ SINGLE = SignatureHash.SINGLE,
1543
+ DEFAULT_ANYONECANPAY = SignatureHash.DEFAULT | SignatureHash.ANYONECANPAY,
1544
+ ALL_ANYONECANPAY = SignatureHash.ALL | SignatureHash.ANYONECANPAY,
1545
+ NONE_ANYONECANPAY = SignatureHash.NONE | SignatureHash.ANYONECANPAY,
1546
+ SINGLE_ANYONECANPAY = SignatureHash.SINGLE | SignatureHash.ANYONECANPAY,
1547
+ }
1548
+
1549
+ function validateSigHash(s: SigHash) {
1550
+ if (typeof s !== 'number' || typeof SigHash[s] !== 'string')
1551
+ throw new Error(`Invalid SigHash=${s}`);
1552
+ return s;
1553
+ }
1511
1554
 
1512
1555
  function unpackSighash(hashType: number) {
1513
1556
  const masked = hashType & 0b0011111;
@@ -1603,9 +1646,13 @@ export type TxOpts = {
1603
1646
  PSBTVersion?: number;
1604
1647
  // Flags
1605
1648
  // Allow output scripts to be unknown scripts (probably unspendable)
1649
+ /** @deprecated Use `allowUnknownOutputs` */
1606
1650
  allowUnknowOutput?: boolean;
1651
+ allowUnknownOutputs?: boolean;
1607
1652
  // Try to sign/finalize unknown input. All bets are off, but there is chance that it will work
1653
+ /** @deprecated Use `allowUnknownInputs` */
1608
1654
  allowUnknowInput?: boolean;
1655
+ allowUnknownInputs?: boolean;
1609
1656
  // Check input/output scripts for sanity
1610
1657
  disableScriptCheck?: boolean;
1611
1658
  // There is strange behaviour where tx without outputs encoded with empty output in the end,
@@ -1617,18 +1664,22 @@ export type TxOpts = {
1617
1664
  lowR?: boolean; // Use lowR signatures
1618
1665
  };
1619
1666
 
1620
- // Check if object doens't have custom constructor (like Uint8Array/Array)
1621
- const isPlainObject = (obj: any) =>
1622
- Object.prototype.toString.call(obj) === '[object Object]' && obj.constructor === Object;
1623
-
1667
+ const toStr = {}.toString;
1624
1668
  function validateOpts(opts: TxOpts) {
1625
- if (!isPlainObject(opts)) throw new Error(`Wrong object type for transaction options: ${opts}`);
1669
+ if (opts !== undefined && toStr.call(opts) !== '[object Object]')
1670
+ throw new Error(`Wrong object type for transaction options: ${opts}`);
1671
+
1626
1672
  const _opts = {
1627
1673
  ...opts,
1674
+ // Defaults
1628
1675
  version: def(opts.version, DEFAULT_VERSION),
1629
1676
  lockTime: def(opts.lockTime, 0),
1630
1677
  PSBTVersion: def(opts.PSBTVersion, 0),
1631
- }; // Defaults
1678
+ };
1679
+ if (typeof _opts.allowUnknowInput !== 'undefined')
1680
+ opts.allowUnknownInputs = _opts.allowUnknowInput;
1681
+ if (typeof _opts.allowUnknowOutput !== 'undefined')
1682
+ opts.allowUnknownOutputs = _opts.allowUnknowOutput;
1632
1683
  // 0 and -1 happens in tests
1633
1684
  if (![-1, 0, 1, 2].includes(_opts.version)) throw new Error(`Unknown version: ${_opts.version}`);
1634
1685
  if (typeof _opts.lockTime !== 'number') throw new Error('Transaction lock time should be number');
@@ -1639,8 +1690,8 @@ function validateOpts(opts: TxOpts) {
1639
1690
  throw new Error(`Unknown PSBT version ${_opts.PSBTVersion}`);
1640
1691
  // Flags
1641
1692
  for (const k of [
1642
- 'allowUnknowOutput',
1643
- 'allowUnknowInput',
1693
+ 'allowUnknownOutputs',
1694
+ 'allowUnknownInputs',
1644
1695
  'disableScriptCheck',
1645
1696
  'bip174jsCompat',
1646
1697
  'allowLegacyWitnessUtxo',
@@ -1916,11 +1967,12 @@ export class Transaction {
1916
1967
  // however in case of nonWitnessUtxo it is better to expect string, since constructing this complex object will be difficult for user
1917
1968
  if (typeof nonWitnessUtxo === 'string') nonWitnessUtxo = hex.decode(nonWitnessUtxo);
1918
1969
  if (isBytes(nonWitnessUtxo)) nonWitnessUtxo = RawTx.decode(nonWitnessUtxo);
1919
- if (nonWitnessUtxo === undefined) nonWitnessUtxo = cur?.nonWitnessUtxo;
1970
+ if (!('nonWitnessUtxo' in i) && nonWitnessUtxo === undefined)
1971
+ nonWitnessUtxo = cur?.nonWitnessUtxo;
1920
1972
  if (typeof txid === 'string') txid = hex.decode(txid);
1921
1973
  if (txid === undefined) txid = cur?.txid;
1922
1974
  let res: PSBTKeyMapKeys<typeof PSBTInput> = { ...cur, ...i, nonWitnessUtxo, txid };
1923
- if (res.nonWitnessUtxo === undefined) delete res.nonWitnessUtxo;
1975
+ if (!('nonWitnessUtxo' in i) && res.nonWitnessUtxo === undefined) delete res.nonWitnessUtxo;
1924
1976
  if (res.sequence === undefined) res.sequence = DEFAULT_SEQUENCE;
1925
1977
  if (res.tapMerkleRoot === null) delete res.tapMerkleRoot;
1926
1978
  res = mergeKeyMap(PSBTInput, res, cur, allowedFields);
@@ -1978,11 +2030,11 @@ export class Transaction {
1978
2030
  PSBTOutputCoder.encode(res);
1979
2031
  if (
1980
2032
  res.script &&
1981
- !this.opts.allowUnknowOutput &&
2033
+ !this.opts.allowUnknownOutputs &&
1982
2034
  OutScript.decode(res.script).type === 'unknown'
1983
2035
  ) {
1984
2036
  throw new Error(
1985
- 'Transaction/output: unknown output script type, there is a chance that input is unspendable. Pass allowUnkownScript=true, if you sure'
2037
+ 'Transaction/output: unknown output script type, there is a chance that input is unspendable. Pass allowUnknownScript=true, if you sure'
1986
2038
  );
1987
2039
  }
1988
2040
  if (!this.opts.disableScriptCheck) checkScript(res.script, res.redeemScript, res.witnessScript);
@@ -2146,10 +2198,10 @@ export class Transaction {
2146
2198
  // Used pretty often, should be fast
2147
2199
  private prevOut(input: TransactionInput): P.UnwrapCoder<typeof RawOutput> {
2148
2200
  if (input.nonWitnessUtxo) {
2149
- if (input.index === undefined) throw new Error('Uknown input index');
2201
+ if (input.index === undefined) throw new Error('Unknown input index');
2150
2202
  return input.nonWitnessUtxo.outputs[input.index];
2151
2203
  } else if (input.witnessUtxo) return input.witnessUtxo;
2152
- else throw new Error('Cannot find previous output info.');
2204
+ else throw new Error('Cannot find previous output info');
2153
2205
  }
2154
2206
  private inputType(input: TransactionInput) {
2155
2207
  let txType = 'legacy';
@@ -2210,12 +2262,7 @@ export class Transaction {
2210
2262
  }
2211
2263
 
2212
2264
  // Signer can be privateKey OR instance of bip32 HD stuff
2213
- signIdx(
2214
- privateKey: Signer,
2215
- idx: number,
2216
- allowedSighash?: SignatureHash[],
2217
- _auxRand?: Bytes
2218
- ): boolean {
2265
+ signIdx(privateKey: Signer, idx: number, allowedSighash?: SigHash[], _auxRand?: Bytes): boolean {
2219
2266
  this.checkInputIdx(idx);
2220
2267
  const input = this.inputs[idx];
2221
2268
  const inputType = this.inputType(input);
@@ -2240,7 +2287,8 @@ export class Transaction {
2240
2287
  }
2241
2288
  // Sighash checks
2242
2289
  // Just for compat with bitcoinjs-lib, so users won't face unexpected behaviour.
2243
- if (!allowedSighash) allowedSighash = [inputType.defaultSighash];
2290
+ if (!allowedSighash) allowedSighash = [inputType.defaultSighash as unknown as SigHash];
2291
+ else allowedSighash.forEach(validateSigHash);
2244
2292
  const sighash = inputType.sighash;
2245
2293
  if (!allowedSighash.includes(sighash)) {
2246
2294
  throw new Error(
@@ -2251,7 +2299,7 @@ export class Transaction {
2251
2299
  // however this was because of bug in bitcoin-core, which remains here because of consensus.
2252
2300
  // If this is absolutely neccessary for your case, please open issue.
2253
2301
  // We disable it to avoid complicated workflow where SINGLE will block adding new outputs
2254
- const { sigInputs, sigOutputs } = this.inputSighash(idx);
2302
+ const { sigOutputs } = this.inputSighash(idx);
2255
2303
  if (sigOutputs === SignatureHash.SINGLE && idx >= this.outputs.length) {
2256
2304
  throw new Error(
2257
2305
  `Input with sighash SINGLE, but there is no output with corresponding index=${idx}`
@@ -2280,7 +2328,7 @@ export class Transaction {
2280
2328
  input.tapInternalKey,
2281
2329
  merkleRoot
2282
2330
  );
2283
- const [taprootPubKey, parity] = taprootTweakPubkey(input.tapInternalKey, merkleRoot);
2331
+ const [taprootPubKey, _] = taprootTweakPubkey(input.tapInternalKey, merkleRoot);
2284
2332
  if (P.equalBytes(taprootPubKey, pubKey)) {
2285
2333
  const hash = this.preimageWitnessV1(idx, prevOutScript, sighash, amount);
2286
2334
  const sig = concat(
@@ -2293,18 +2341,13 @@ export class Transaction {
2293
2341
  }
2294
2342
  if (input.tapLeafScript) {
2295
2343
  input.tapScriptSig = input.tapScriptSig || [];
2296
- for (const [cb, _script] of input.tapLeafScript) {
2344
+ for (const [_, _script] of input.tapLeafScript) {
2297
2345
  const script = _script.subarray(0, -1);
2298
2346
  const scriptDecoded = Script.decode(script);
2299
2347
  const ver = _script[_script.length - 1];
2300
2348
  const hash = tapLeafHash(script, ver);
2301
- const { pubKey, privKey } = getTaprootKeys(
2302
- privateKey,
2303
- schnorrPub,
2304
- cb.internalKey,
2305
- P.EMPTY // Because we cannot have nested taproot tree
2306
- );
2307
- const pos = scriptDecoded.findIndex((i) => isBytes(i) && P.equalBytes(i, pubKey));
2349
+ // NOTE: no need to tweak internal key here, since we don't support nested p2tr
2350
+ const pos = scriptDecoded.findIndex((i) => isBytes(i) && P.equalBytes(i, schnorrPub));
2308
2351
  // Skip if there is no public key in tapLeafScript
2309
2352
  if (pos === -1) continue;
2310
2353
  const msg = this.preimageWitnessV1(
@@ -2317,12 +2360,12 @@ export class Transaction {
2317
2360
  ver
2318
2361
  );
2319
2362
  const sig = concat(
2320
- schnorr.sign(msg, privKey, _auxRand),
2363
+ schnorr.sign(msg, privateKey, _auxRand),
2321
2364
  sighash !== SignatureHash.DEFAULT ? new Uint8Array([sighash]) : P.EMPTY
2322
2365
  );
2323
2366
  this.updateInput(
2324
2367
  idx,
2325
- { tapScriptSig: [[{ pubKey: pubKey, leafHash: hash }, sig]] },
2368
+ { tapScriptSig: [[{ pubKey: schnorrPub, leafHash: hash }, sig]] },
2326
2369
  true
2327
2370
  );
2328
2371
  signed = true;
@@ -2426,7 +2469,7 @@ export class Transaction {
2426
2469
  signatures.push(scriptSig[sigIdx][1]);
2427
2470
  }
2428
2471
  if (signatures.length !== outScript.pubkeys.length) continue;
2429
- } else if (outScript.type === 'unknown' && this.opts.allowUnknowInput) {
2472
+ } else if (outScript.type === 'unknown' && this.opts.allowUnknownInputs) {
2430
2473
  // Trying our best to sign what we can
2431
2474
  const scriptDecoded = Script.decode(script);
2432
2475
  signatures = scriptSig
@@ -2483,7 +2526,7 @@ export class Transaction {
2483
2526
  } else if (inputType.last.type === 'wpkh') {
2484
2527
  inputScript = P.EMPTY;
2485
2528
  witness = [input.partialSig[0][1], input.partialSig[0][0]];
2486
- } else if (inputType.last.type === 'unknown' && !this.opts.allowUnknowInput)
2529
+ } else if (inputType.last.type === 'unknown' && !this.opts.allowUnknownInputs)
2487
2530
  throw new Error('Unknown inputs not allowed');
2488
2531
 
2489
2532
  // Create final scripts (generic part)
@@ -2547,7 +2590,7 @@ export class Transaction {
2547
2590
  }
2548
2591
  clone() {
2549
2592
  // deepClone probably faster, but this enforces that encoding is valid
2550
- return Transaction.fromPSBT(this.toPSBT(2), this.opts);
2593
+ return Transaction.fromPSBT(this.toPSBT(this.opts.PSBTVersion), this.opts);
2551
2594
  }
2552
2595
  }
2553
2596
  // User facing API?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scure/btc-signer",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Audited & minimal library for creating, signing & decoding Bitcoin transactions: with Schnorr, Taproot, UTXO & PSBT",
5
5
  "files": [
6
6
  "index.js",
@@ -14,17 +14,17 @@
14
14
  "module": "index.js",
15
15
  "types": "index.d.ts",
16
16
  "dependencies": {
17
- "@noble/curves": "~1.0.0",
18
- "@noble/hashes": "~1.3.0",
19
- "@scure/base": "~1.1.1",
20
- "micro-packed": "~0.3.2"
17
+ "@noble/curves": "~1.3.0",
18
+ "@noble/hashes": "~1.3.3",
19
+ "@scure/base": "~1.1.4",
20
+ "micro-packed": "~0.4.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@scure/bip32": "~1.3.0",
24
- "micro-packed-debugger": "0.3.1",
23
+ "@scure/bip32": "~1.3.3",
24
+ "micro-packed-debugger": "0.4.1",
25
25
  "micro-should": "0.4.0",
26
- "prettier": "2.8.4",
27
- "typescript": "5.0.2"
26
+ "prettier": "3.1.1",
27
+ "typescript": "5.3.2"
28
28
  },
29
29
  "author": "Paul Miller (https://paulmillr.com)",
30
30
  "license": "MIT",
@@ -36,8 +36,10 @@
36
36
  "scripts": {
37
37
  "build": "tsc",
38
38
  "lint": "prettier --check index.ts",
39
+ "format": "prettier --write index.ts",
39
40
  "test": "node test/index.test.js && node test/psbt-test/bip174-psbt-extended.test.js",
40
- "test:extended": "node --experimental-loader ./test/bitcoinjs-test/esm-loader.js ./test/bitcoinjs-test/index.test.js"
41
+ "test:extended": "node --experimental-loader ./test/bitcoinjs-test/esm-loader.js ./test/bitcoinjs-test/index.test.js",
42
+ "test:slow": "node test/index.test.js && node test/slow.test.js"
41
43
  },
42
44
  "keywords": [
43
45
  "bitcoin",
@@ -56,4 +58,4 @@
56
58
  "p2tr"
57
59
  ],
58
60
  "funding": "https://paulmillr.com/funding/"
59
- }
61
+ }