Skip to content

Commit

Permalink
Add BIP371 fields
Browse files Browse the repository at this point in the history
  • Loading branch information
reardencode committed Apr 1, 2022
1 parent bcd895d commit 7ae8a57
Show file tree
Hide file tree
Showing 38 changed files with 1,426 additions and 18 deletions.
38 changes: 38 additions & 0 deletions src/lib/converter/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import * as nonWitnessUtxo from './input/nonWitnessUtxo';
import * as partialSig from './input/partialSig';
import * as porCommitment from './input/porCommitment';
import * as sighashType from './input/sighashType';
import * as tapKeySig from './input/tapKeySig';
import * as tapLeafScript from './input/tapLeafScript';
import * as tapMerkleRoot from './input/tapMerkleRoot';
import * as tapScriptSig from './input/tapScriptSig';
import * as witnessUtxo from './input/witnessUtxo';
import * as tapTree from './output/tapTree';
declare const globals: {
unsignedTx: typeof unsignedTx;
globalXpub: typeof globalXpub;
Expand Down Expand Up @@ -43,6 +48,24 @@ declare const inputs: {
canAdd: (currentData: any, newData: any) => boolean;
};
checkPubkey: (keyVal: import("../interfaces").KeyValue) => Buffer | undefined;
tapKeySig: typeof tapKeySig;
tapScriptSig: typeof tapScriptSig;
tapLeafScript: typeof tapLeafScript;
tapBip32Derivation: {
decode: (keyVal: import("../interfaces").KeyValue) => import("../interfaces").TapBip32Derivation;
encode: (data: import("../interfaces").TapBip32Derivation) => import("../interfaces").KeyValue;
check: (data: any) => data is import("../interfaces").TapBip32Derivation;
expected: string;
canAddToArray: (array: import("../interfaces").TapBip32Derivation[], item: import("../interfaces").TapBip32Derivation, dupeSet: Set<string>) => boolean;
};
tapInternalKey: {
decode: (keyVal: import("../interfaces").KeyValue) => Buffer;
encode: (data: Buffer) => import("../interfaces").KeyValue;
check: (data: any) => data is Buffer;
expected: string;
canAdd: (currentData: any, newData: any) => boolean;
};
tapMerkleRoot: typeof tapMerkleRoot;
};
declare const outputs: {
bip32Derivation: {
Expand All @@ -67,5 +90,20 @@ declare const outputs: {
canAdd: (currentData: any, newData: any) => boolean;
};
checkPubkey: (keyVal: import("../interfaces").KeyValue) => Buffer | undefined;
tapBip32Derivation: {
decode: (keyVal: import("../interfaces").KeyValue) => import("../interfaces").TapBip32Derivation;
encode: (data: import("../interfaces").TapBip32Derivation) => import("../interfaces").KeyValue;
check: (data: any) => data is import("../interfaces").TapBip32Derivation;
expected: string;
canAddToArray: (array: import("../interfaces").TapBip32Derivation[], item: import("../interfaces").TapBip32Derivation, dupeSet: Set<string>) => boolean;
};
tapTree: typeof tapTree;
tapInternalKey: {
decode: (keyVal: import("../interfaces").KeyValue) => Buffer;
encode: (data: Buffer) => import("../interfaces").KeyValue;
check: (data: any) => data is Buffer;
expected: string;
canAdd: (currentData: any, newData: any) => boolean;
};
};
export { globals, inputs, outputs };
24 changes: 24 additions & 0 deletions src/lib/converter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ const nonWitnessUtxo = require('./input/nonWitnessUtxo');
const partialSig = require('./input/partialSig');
const porCommitment = require('./input/porCommitment');
const sighashType = require('./input/sighashType');
const tapKeySig = require('./input/tapKeySig');
const tapLeafScript = require('./input/tapLeafScript');
const tapMerkleRoot = require('./input/tapMerkleRoot');
const tapScriptSig = require('./input/tapScriptSig');
const witnessUtxo = require('./input/witnessUtxo');
const tapTree = require('./output/tapTree');
const bip32Derivation = require('./shared/bip32Derivation');
const checkPubkey = require('./shared/checkPubkey');
const redeemScript = require('./shared/redeemScript');
const tapBip32Derivation = require('./shared/tapBip32Derivation');
const tapInternalKey = require('./shared/tapInternalKey');
const witnessScript = require('./shared/witnessScript');
const globals = {
unsignedTx,
Expand Down Expand Up @@ -42,6 +49,16 @@ const inputs = {
typeFields_1.InputTypes.PARTIAL_SIG,
typeFields_1.InputTypes.BIP32_DERIVATION,
]),
tapKeySig,
tapScriptSig,
tapLeafScript,
tapBip32Derivation: tapBip32Derivation.makeConverter(
typeFields_1.InputTypes.TAP_BIP32_DERIVATION,
),
tapInternalKey: tapInternalKey.makeConverter(
typeFields_1.InputTypes.TAP_INTERNAL_KEY,
),
tapMerkleRoot,
};
exports.inputs = inputs;
const outputs = {
Expand All @@ -57,5 +74,12 @@ const outputs = {
checkPubkey: checkPubkey.makeChecker([
typeFields_1.OutputTypes.BIP32_DERIVATION,
]),
tapBip32Derivation: tapBip32Derivation.makeConverter(
typeFields_1.OutputTypes.TAP_BIP32_DERIVATION,
),
tapTree,
tapInternalKey: tapInternalKey.makeConverter(
typeFields_1.OutputTypes.TAP_INTERNAL_KEY,
),
};
exports.outputs = outputs;
6 changes: 6 additions & 0 deletions src/lib/converter/input/tapKeySig.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { KeyValue, TapKeySig } from '../../interfaces';
export declare function decode(keyVal: KeyValue): TapKeySig;
export declare function encode(value: TapKeySig): KeyValue;
export declare const expected = "Buffer";
export declare function check(data: any): data is TapKeySig;
export declare function canAdd(currentData: any, newData: any): boolean;
32 changes: 32 additions & 0 deletions src/lib/converter/input/tapKeySig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const typeFields_1 = require('../../typeFields');
function decode(keyVal) {
if (keyVal.key[0] !== typeFields_1.InputTypes.TAP_KEY_SIG) {
throw new Error(
'Decode Error: could not decode tapKeySig with key 0x' +
keyVal.key.toString('hex'),
);
}
if (!check(keyVal.value)) {
throw new Error(
'Decode Error: tapKeySig not a valid 64-65-byte BIP340 signature',
);
}
return keyVal.value;
}
exports.decode = decode;
function encode(value) {
const key = Buffer.from([typeFields_1.InputTypes.TAP_KEY_SIG]);
return { key, value };
}
exports.encode = encode;
exports.expected = 'Buffer';
function check(data) {
return Buffer.isBuffer(data) && (data.length === 64 || data.length === 65);
}
exports.check = check;
function canAdd(currentData, newData) {
return !!currentData && !!newData && currentData.tapKeySig === undefined;
}
exports.canAdd = canAdd;
6 changes: 6 additions & 0 deletions src/lib/converter/input/tapLeafScript.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { KeyValue, TapLeafScript } from '../../interfaces';
export declare function decode(keyVal: KeyValue): TapLeafScript;
export declare function encode(tScript: TapLeafScript): KeyValue;
export declare const expected = "{ controlBlock: Buffer; leafVersion: number, script: Buffer; }";
export declare function check(data: any): data is TapLeafScript;
export declare function canAddToArray(array: TapLeafScript[], item: TapLeafScript, dupeSet: Set<string>): boolean;
62 changes: 62 additions & 0 deletions src/lib/converter/input/tapLeafScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const typeFields_1 = require('../../typeFields');
const varuint = require('../varint');
function decode(keyVal) {
if (keyVal.key[0] !== typeFields_1.InputTypes.TAP_LEAF_SCRIPT) {
throw new Error(
'Decode Error: could not decode tapLeafScript with key 0x' +
keyVal.key.toString('hex'),
);
}
if ((keyVal.key.length - 2) % 32 !== 0) {
throw new Error(
'Decode Error: tapLeafScript has invalid control block in key 0x' +
keyVal.key.toString('hex'),
);
}
const leafVersion = keyVal.value[keyVal.value.length - 1];
if ((keyVal.key[1] & 0xfe) !== leafVersion) {
throw new Error(
'Decode Error: tapLeafScript bad leaf version in key 0x' +
keyVal.key.toString('hex'),
);
}
const script = keyVal.value.slice(0, -1);
const controlBlock = keyVal.key.slice(1);
return { controlBlock, script, leafVersion };
}
exports.decode = decode;
function encode(tScript) {
const head = Buffer.from([typeFields_1.InputTypes.TAP_LEAF_SCRIPT]);
const _offset = varuint.encodingLength(tScript.script.length);
const value = Buffer.allocUnsafe(_offset + tScript.script.length + 1);
varuint.encode(tScript.script.length, value);
value[_offset + tScript.script.length] = tScript.leafVersion;
tScript.script.copy(value, _offset);
return {
key: Buffer.concat([head, tScript.controlBlock]),
value,
};
}
exports.encode = encode;
exports.expected =
'{ controlBlock: Buffer; leafVersion: number, script: Buffer; }';
function check(data) {
return (
Buffer.isBuffer(data.controlBlock) &&
(data.controlBlock.length - 2) % 32 === 0 &&
(data.leafVersion & 0xfe) === data.leafVersion &&
Buffer.isBuffer(data.script)
);
}
exports.check = check;
function canAddToArray(array, item, dupeSet) {
const dupeString = item.controlBlock.toString('hex');
if (dupeSet.has(dupeString)) return false;
dupeSet.add(dupeString);
return (
array.filter(v => v.controlBlock.equals(item.controlBlock)).length === 0
);
}
exports.canAddToArray = canAddToArray;
6 changes: 6 additions & 0 deletions src/lib/converter/input/tapMerkleRoot.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { KeyValue, TapMerkleRoot } from '../../interfaces';
export declare function decode(keyVal: KeyValue): TapMerkleRoot;
export declare function encode(value: TapMerkleRoot): KeyValue;
export declare const expected = "Buffer";
export declare function check(data: any): data is TapMerkleRoot;
export declare function canAdd(currentData: any, newData: any): boolean;
30 changes: 30 additions & 0 deletions src/lib/converter/input/tapMerkleRoot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const typeFields_1 = require('../../typeFields');
function decode(keyVal) {
if (keyVal.key[0] !== typeFields_1.InputTypes.TAP_MERKLE_ROOT) {
throw new Error(
'Decode Error: could not decode tapMerkleRoot with key 0x' +
keyVal.key.toString('hex'),
);
}
if (!check(keyVal.value)) {
throw new Error('Decode Error: tapMerkleRoot not a 32-byte hash');
}
return keyVal.value;
}
exports.decode = decode;
function encode(value) {
const key = Buffer.from([typeFields_1.InputTypes.TAP_MERKLE_ROOT]);
return { key, value };
}
exports.encode = encode;
exports.expected = 'Buffer';
function check(data) {
return Buffer.isBuffer(data) && data.length === 32;
}
exports.check = check;
function canAdd(currentData, newData) {
return !!currentData && !!newData && currentData.tapMerkleRoot === undefined;
}
exports.canAdd = canAdd;
6 changes: 6 additions & 0 deletions src/lib/converter/input/tapScriptSig.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { KeyValue, TapScriptSig } from '../../interfaces';
export declare function decode(keyVal: KeyValue): TapScriptSig;
export declare function encode(tSig: TapScriptSig): KeyValue;
export declare const expected = "{ pubkey: Buffer; signature: Buffer; }";
export declare function check(data: any): data is TapScriptSig;
export declare function canAddToArray(array: TapScriptSig[], item: TapScriptSig, dupeSet: Set<string>): boolean;
58 changes: 58 additions & 0 deletions src/lib/converter/input/tapScriptSig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const typeFields_1 = require('../../typeFields');
function decode(keyVal) {
if (keyVal.key[0] !== typeFields_1.InputTypes.TAP_SCRIPT_SIG) {
throw new Error(
'Decode Error: could not decode tapScriptSig with key 0x' +
keyVal.key.toString('hex'),
);
}
if (keyVal.key.length !== 65) {
throw new Error(
'Decode Error: tapScriptSig has invalid key 0x' +
keyVal.key.toString('hex'),
);
}
if (keyVal.value.length !== 64 && keyVal.value.length !== 65) {
throw new Error(
'Decode Error: tapScriptSig has invalid signature in key 0x' +
keyVal.key.toString('hex'),
);
}
const pubkey = keyVal.key.slice(1, 33);
const leafHash = keyVal.key.slice(33);
return {
pubkey,
leafHash,
signature: keyVal.value,
};
}
exports.decode = decode;
function encode(tSig) {
const head = Buffer.from([typeFields_1.InputTypes.TAP_SCRIPT_SIG]);
return {
key: Buffer.concat([head, tSig.pubkey, tSig.leafHash]),
value: tSig.signature,
};
}
exports.encode = encode;
exports.expected = '{ pubkey: Buffer; signature: Buffer; }';
function check(data) {
return (
Buffer.isBuffer(data.pubkey) &&
Buffer.isBuffer(data.leafHash) &&
Buffer.isBuffer(data.signature) &&
data.pubkey.length === 32 &&
data.leafHash.length === 32 &&
(data.signature.length === 64 || data.signature.length === 65)
);
}
exports.check = check;
function canAddToArray(array, item, dupeSet) {
const dupeString = item.pubkey.toString('hex');
if (dupeSet.has(dupeString)) return false;
dupeSet.add(dupeString);
return array.filter(v => v.pubkey.equals(item.pubkey)).length === 0;
}
exports.canAddToArray = canAddToArray;
6 changes: 6 additions & 0 deletions src/lib/converter/output/tapTree.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { KeyValue, TapTree } from '../../interfaces';
export declare function decode(keyVal: KeyValue): TapTree;
export declare function encode(tree: TapTree): KeyValue;
export declare const expected = "[{ depth: number; leafVersion: number, script: Buffer; }]";
export declare function check(data: any): data is TapTree;
export declare function canAdd(currentData: any, newData: any): boolean;
65 changes: 65 additions & 0 deletions src/lib/converter/output/tapTree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const typeFields_1 = require('../../typeFields');
const varuint = require('../varint');
function decode(keyVal) {
if (keyVal.key[0] !== typeFields_1.OutputTypes.TAP_TREE) {
throw new Error(
'Decode Error: could not decode tapTree with key 0x' +
keyVal.key.toString('hex'),
);
}
let _offset = 0;
const data = [];
while (_offset < keyVal.value.length) {
const depth = keyVal.value[_offset++];
const leafVersion = keyVal.value[_offset++];
const scriptLen = varuint.decode(keyVal.value, _offset);
_offset += varuint.encodingLength(scriptLen);
data.push({
depth,
leafVersion,
script: keyVal.value.slice(_offset, _offset + scriptLen),
});
_offset += scriptLen;
}
return data;
}
exports.decode = decode;
function encode(tree) {
const key = Buffer.from([typeFields_1.OutputTypes.TAP_TREE]);
const bufs = new Array(tree.length * 2);
for (const tapLeaf of tree) {
const headBuf = Buffer.allocUnsafe(
2 + varuint.encodingLength(tapLeaf.script.length),
);
headBuf[0] = tapLeaf.depth;
headBuf[1] = tapLeaf.leafVersion;
varuint.encode(tapLeaf.script.length, headBuf, 2);
bufs.push(headBuf);
bufs.push(tapLeaf.script);
}
return {
key,
value: Buffer.concat(bufs),
};
}
exports.encode = encode;
exports.expected = '[{ depth: number; leafVersion: number, script: Buffer; }]';
function check(data) {
return (
Array.isArray(data) &&
data.every(
tapLeaf =>
tapLeaf.depth >= 0 &&
tapLeaf.depth <= 128 &&
(tapLeaf.leafVersion & 0xfe) === tapLeaf.leafVersion &&
Buffer.isBuffer(tapLeaf.script),
)
);
}
exports.check = check;
function canAdd(currentData, newData) {
return !!currentData && !!newData && currentData.tapTree === undefined;
}
exports.canAdd = canAdd;
Loading

0 comments on commit 7ae8a57

Please sign in to comment.