Skip to content

Commit

Permalink
fix serialization of witness version in scriptPubKey (bitcoinjs#49)
Browse files Browse the repository at this point in the history
* fix serialization of witness version in scriptPubKey

* export blindingDataLike from psbt.ts

* build

* remove warnings + enrich test

* use wip blech32 branch

* use FUTURE_SEGWIT_CONSTANT

* blech32 from npm (1.1.2)
  • Loading branch information
louisinger committed Apr 15, 2022
1 parent 64ddd92 commit 1c71f68
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"bip32": "^2.0.4",
"bip66": "^1.1.0",
"bitcoin-ops": "^1.4.0",
"blech32": "^1.1.1",
"blech32": "^1.1.2",
"bs58check": "^2.0.0",
"create-hash": "^1.2.0",
"ecpair": "^2.0.1",
Expand Down
14 changes: 6 additions & 8 deletions src/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@ const FUTURE_SEGWIT_MIN_SIZE = 2;
const FUTURE_SEGWIT_MAX_VERSION = 16;
const FUTURE_SEGWIT_MIN_VERSION = 1;
const FUTURE_SEGWIT_VERSION_DIFF = 0x50;
const FUTURE_SEGWIT_VERSION_WARNING =
'WARNING: Sending to a future segwit version address can lead to loss of funds. ' +
'End users MUST be warned carefully in the GUI and asked if they wish to proceed ' +
'with caution. Wallets should verify the segwit version from the output of fromBech32, ' +
'then decide when it is safe to use which version of segwit.';
function _toFutureSegwitAddress(output, network) {
const data = output.slice(2);
if (
Expand All @@ -78,7 +73,6 @@ function _toFutureSegwitAddress(output, network) {
throw new TypeError('Invalid version for segwit address');
if (output[1] !== data.length)
throw new TypeError('Invalid script for segwit address');
console.warn(FUTURE_SEGWIT_VERSION_WARNING);
return toBech32(data, version, network.bech32);
}
// negative value for confidential types
Expand Down Expand Up @@ -138,7 +132,12 @@ function fromBlech32(address) {
const pubkey = Buffer.from(result.blindingPublicKey, 'hex');
const prg = Buffer.from(result.witness, 'hex');
const data = Buffer.concat([
Buffer.from([result.witnessVersion, prg.length]),
Buffer.from([
result.witnessVersion
? result.witnessVersion + FUTURE_SEGWIT_VERSION_DIFF
: result.witnessVersion,
prg.length,
]),
prg,
]);
return {
Expand Down Expand Up @@ -239,7 +238,6 @@ function toOutputScript(address, network) {
decodedBech32.data.length >= FUTURE_SEGWIT_MIN_SIZE &&
decodedBech32.data.length <= FUTURE_SEGWIT_MAX_SIZE
) {
console.warn(FUTURE_SEGWIT_VERSION_WARNING);
return bscript.compile([
decodedBech32.version + FUTURE_SEGWIT_VERSION_DIFF,
decodedBech32.data,
Expand Down
2 changes: 1 addition & 1 deletion src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as bip341 from './bip341';
export * from './asset';
export { address, crypto, networks, payments, script, confidential, issuance, bip341, };
export { TaggedHashPrefix } from './crypto';
export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, witnessStackToScriptWitness, } from './psbt';
export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, witnessStackToScriptWitness, BlindingDataLike, } from './psbt';
export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
export { Network as NetworkExtended } from './networks';
Expand Down
38 changes: 38 additions & 0 deletions test/integration/taproot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from '../../ts_src/bip341';
import { compile, OPS } from '../../ts_src/script';
import { witnessStackToScriptWitness } from '../../ts_src/psbt';
import * as assert from 'assert';

const bip341 = BIP341Factory(ecc);

Expand All @@ -37,6 +38,43 @@ describe('liquidjs-lib (transaction with taproot)', () => {
'KwoJAjrautr5EUPVxvnisVgixipMiYGKxykiV8U6e6JtAP9ZURV5',
);

it('should be able to compute confidential address from taproot output script', () => {
const bobScript = compile([bob.publicKey.slice(1), OPS.OP_CHECKSIG]);

// in this exemple, alice is the internal key (can spend via keypath spend)
// however, the script tree allows bob to spend the coin with a simple p2pkh
const leaves: TaprootLeaf[] = [
{
scriptHex: bobScript.toString('hex'),
},
{
scriptHex:
'20b617298552a72ade070667e86ca63b8f5789a9fe8731ef91202a91c9f3459007ac',
},
];

const hashTree = toHashTree(leaves);
const output = bip341.taprootOutputScript(alice.publicKey, hashTree);

const unconfidentialAddress = address.fromOutputScript(
output,
networks.regtest,
);
const confidentialAddress = address.toConfidential(
unconfidentialAddress,
bob.publicKey,
);
const fromConf = address.fromConfidential(confidentialAddress);
assert.strictEqual(unconfidentialAddress, fromConf.unconfidentialAddress);

assert.ok(fromConf.blindingKey.equals(bob.publicKey));
const scriptFromConfidential = address.toOutputScript(
confidentialAddress,
networks.regtest,
);
assert.ok(scriptFromConfidential.equals(output));
});

it('can create (and broadcast via 3PBP) a taproot keyspend Transaction', async () => {
const changeAddress = payments.p2pkh({
pubkey: alice.publicKey,
Expand Down
16 changes: 6 additions & 10 deletions ts_src/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ const FUTURE_SEGWIT_MIN_SIZE: number = 2;
const FUTURE_SEGWIT_MAX_VERSION: number = 16;
const FUTURE_SEGWIT_MIN_VERSION: number = 1;
const FUTURE_SEGWIT_VERSION_DIFF: number = 0x50;
const FUTURE_SEGWIT_VERSION_WARNING: string =
'WARNING: Sending to a future segwit version address can lead to loss of funds. ' +
'End users MUST be warned carefully in the GUI and asked if they wish to proceed ' +
'with caution. Wallets should verify the segwit version from the output of fromBech32, ' +
'then decide when it is safe to use which version of segwit.';

function _toFutureSegwitAddress(output: Buffer, network: Network): string {
const data = output.slice(2);
Expand All @@ -61,8 +56,6 @@ function _toFutureSegwitAddress(output: Buffer, network: Network): string {
if (output[1] !== data.length)
throw new TypeError('Invalid script for segwit address');

console.warn(FUTURE_SEGWIT_VERSION_WARNING);

return toBech32(data, version, network.bech32);
}

Expand Down Expand Up @@ -131,7 +124,12 @@ export function fromBlech32(address: string): Blech32Result {
const pubkey = Buffer.from(result.blindingPublicKey, 'hex');
const prg = Buffer.from(result.witness, 'hex');
const data = Buffer.concat([
Buffer.from([result.witnessVersion, prg.length]),
Buffer.from([
result.witnessVersion
? result.witnessVersion + FUTURE_SEGWIT_VERSION_DIFF
: result.witnessVersion,
prg.length,
]),
prg,
]);
return {
Expand Down Expand Up @@ -254,8 +252,6 @@ export function toOutputScript(address: string, network?: Network): Buffer {
decodedBech32.data.length >= FUTURE_SEGWIT_MIN_SIZE &&
decodedBech32.data.length <= FUTURE_SEGWIT_MAX_SIZE
) {
console.warn(FUTURE_SEGWIT_VERSION_WARNING);

return bscript.compile([
decodedBech32.version + FUTURE_SEGWIT_VERSION_DIFF,
decodedBech32.data,
Expand Down
1 change: 1 addition & 0 deletions ts_src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export {
HDSigner,
HDSignerAsync,
witnessStackToScriptWitness,
BlindingDataLike,
} from './psbt';
export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -464,10 +464,10 @@ bitcoin-ops@^1.3.0, bitcoin-ops@^1.4.0:
resolved "https://registry.yarnpkg.com/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz#e45de620398e22fd4ca6023de43974ff42240278"
integrity sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==

blech32@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/blech32/-/blech32-1.1.1.tgz#b3260d953710c25a2bdac08bfe919d0db1cb3203"
integrity sha512-5EvwgaKzsUMU9En0aAum5Gq48Gp40ODxUZTAPK5gg5BNxjkjDve3Qh/yLEg33wYEaNXL3IFRsnQoky5+bA9tLQ==
blech32@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/blech32/-/blech32-1.1.2.tgz#545459680555e229603241be3b9bf0979f6fbb3a"
integrity sha512-C5qxzoF9KyX88X8Zz18cZ6BOeL0n5/Eg/cDot1frntkArRMwg1djNim5wA6QFWwu0lJ1LN8iiRMN4Lp2kZzdfA==
dependencies:
long "^4.0.0"

Expand Down

0 comments on commit 1c71f68

Please sign in to comment.