Skip to content

Commit a05587f

Browse files
authored
Merge pull request #1849 from bitcoinjs/bump/6.1.0
Release v6.1.0
2 parents 9ae2089 + f221e1f commit a05587f

File tree

5 files changed

+7
-272
lines changed

5 files changed

+7
-272
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 6.1.0
2+
__added__
3+
- taproot support for payments (p2tr) and PSBT. See taproot.spec.ts integration test for examples. (#1742)
4+
15
# 6.0.2
26
__fixed__
37
- p2sh payment now uses empty Buffer for redeem.output when redeemScript is OP_FALSE (#1802)

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bitcoinjs-lib",
3-
"version": "6.1.0-rc.0",
3+
"version": "6.1.0",
44
"description": "Client-side Bitcoin JavaScript library",
55
"main": "./src/index.js",
66
"types": "./src/index.d.ts",

test/integration/taproot.md

Lines changed: 0 additions & 157 deletions
This file was deleted.

test/integration/taproot.spec.ts

Lines changed: 0 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -17,41 +17,6 @@ const bip32 = BIP32Factory(ecc);
1717
const ECPair = ECPairFactory(ecc);
1818

1919
describe('bitcoinjs-lib (transaction with taproot)', () => {
20-
it('can create (and broadcast via 3PBP) a taproot keyspend Transaction', async () => {
21-
const myKey = bip32.fromSeed(rng(64), regtest);
22-
23-
const output = createKeySpendOutput(myKey.publicKey);
24-
const address = bitcoin.address.fromOutputScript(output, regtest);
25-
// amount from faucet
26-
const amount = 42e4;
27-
// amount to send
28-
const sendAmount = amount - 1e4;
29-
// get faucet
30-
const unspent = await regtestUtils.faucetComplex(output, amount);
31-
32-
const tx = createSigned(
33-
myKey,
34-
unspent.txId,
35-
unspent.vout,
36-
sendAmount,
37-
[output],
38-
[amount],
39-
);
40-
41-
const hex = tx.toHex();
42-
// console.log('Valid tx sent from:');
43-
// console.log(address);
44-
// console.log('tx hex:');
45-
// console.log(hex);
46-
await regtestUtils.broadcast(hex);
47-
await regtestUtils.verify({
48-
txId: tx.getId(),
49-
address,
50-
vout: 0,
51-
value: sendAmount,
52-
});
53-
});
54-
5520
it('can create (and broadcast via 3PBP) a taproot key-path spend Transaction', async () => {
5621
const internalKey = bip32.fromSeed(rng(64), regtest);
5722
const p2pkhKey = bip32.fromSeed(rng(64), regtest);
@@ -593,83 +558,6 @@ function buildLeafIndexFinalizer(
593558
};
594559
}
595560

596-
// Order of the curve (N) - 1
597-
const N_LESS_1 = Buffer.from(
598-
'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
599-
'hex',
600-
);
601-
// 1 represented as 32 bytes BE
602-
const ONE = Buffer.from(
603-
'0000000000000000000000000000000000000000000000000000000000000001',
604-
'hex',
605-
);
606-
607-
// Function for creating a tweaked p2tr key-spend only address
608-
// (This is recommended by BIP341)
609-
function createKeySpendOutput(publicKey: Buffer): Buffer {
610-
// x-only pubkey (remove 1 byte y parity)
611-
const myXOnlyPubkey = toXOnly(publicKey);
612-
const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
613-
const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
614-
if (tweakResult === null) throw new Error('Invalid Tweak');
615-
const { xOnlyPubkey: tweaked } = tweakResult;
616-
// scriptPubkey
617-
return Buffer.concat([
618-
// witness v1, PUSH_DATA 32 bytes
619-
Buffer.from([0x51, 0x20]),
620-
// x-only tweaked pubkey
621-
tweaked,
622-
]);
623-
}
624-
625-
// Function for signing for a tweaked p2tr key-spend only address
626-
// (Required for the above address)
627-
interface KeyPair {
628-
publicKey: Buffer;
629-
privateKey?: Buffer;
630-
}
631-
function signTweaked(messageHash: Buffer, key: KeyPair): Uint8Array {
632-
const privateKey =
633-
key.publicKey[0] === 2
634-
? key.privateKey
635-
: ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey!)!, ONE)!;
636-
const tweakHash = bitcoin.crypto.taggedHash(
637-
'TapTweak',
638-
toXOnly(key.publicKey),
639-
);
640-
const newPrivateKey = ecc.privateAdd(privateKey!, tweakHash);
641-
if (newPrivateKey === null) throw new Error('Invalid Tweak');
642-
return ecc.signSchnorr(messageHash, newPrivateKey, Buffer.alloc(32));
643-
}
644-
645-
// Function for creating signed tx
646-
function createSigned(
647-
key: KeyPair,
648-
txid: string,
649-
vout: number,
650-
amountToSend: number,
651-
scriptPubkeys: Buffer[],
652-
values: number[],
653-
): bitcoin.Transaction {
654-
const tx = new bitcoin.Transaction();
655-
tx.version = 2;
656-
// Add input
657-
tx.addInput(Buffer.from(txid, 'hex').reverse(), vout);
658-
// Add output
659-
tx.addOutput(scriptPubkeys[0], amountToSend);
660-
const sighash = tx.hashForWitnessV1(
661-
0, // which input
662-
scriptPubkeys, // All previous outputs of all inputs
663-
values, // All previous values of all inputs
664-
bitcoin.Transaction.SIGHASH_DEFAULT, // sighash flag, DEFAULT is schnorr-only (DEFAULT == ALL)
665-
);
666-
const signature = Buffer.from(signTweaked(sighash, key));
667-
// witness stack for keypath spend is just the signature.
668-
// If sighash is not SIGHASH_DEFAULT (ALL) then you must add 1 byte with sighash value
669-
tx.ins[0].witness = [signature];
670-
return tx;
671-
}
672-
673561
// This logic will be extracted to ecpair
674562
function tweakSigner(signer: bitcoin.Signer, opts: any = {}): bitcoin.Signer {
675563
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

0 commit comments

Comments
 (0)