@bitgo-beta/utxo-lib
Version:
Client-side Bitcoin JavaScript library
184 lines • 26.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSignatureDigest = exports.getTxidDigest = exports.getOutputsDigest = exports.getSequenceDigest = exports.getPrevoutsDigest = exports.getBlake2bHash = void 0;
/**
* Implements hashing methods described in https://zips.z.cash/zip-0244.
* Only supports full transparent transactions without shielded inputs or outputs.
*/
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
const bufferutils_1 = require("bitcoinjs-lib/src/bufferutils");
const blake2b = require('@bitgo-beta/blake2b');
const UtxoTransaction_1 = require("../UtxoTransaction");
/**
* Blake2b hashing algorithm for Zcash
* @param buffer
* @param personalization
* @returns 256-bit BLAKE2b hash
*/
function getBlake2bHash(buffer, personalization) {
const out = Buffer.allocUnsafe(32);
personalization = Buffer.from(personalization);
return blake2b(out.length, null, null, personalization).update(buffer).digest(out);
}
exports.getBlake2bHash = getBlake2bHash;
function getHeaderDigest(tx) {
// https://zips.z.cash/zip-0244#t-1-header-digest
const mask = tx.overwintered ? 1 : 0;
const writer = bufferutils_1.BufferWriter.withCapacity(4 * 5);
writer.writeInt32(tx.version | (mask << 31)); // Set overwinter bit
writer.writeUInt32(tx.versionGroupId);
writer.writeUInt32(tx.consensusBranchId);
writer.writeUInt32(tx.locktime);
writer.writeUInt32(tx.expiryHeight);
return getBlake2bHash(writer.end(), 'ZTxIdHeadersHash');
}
function getPrevoutsDigest(ins, tag = 'ZTxIdPrevoutHash', sigParams) {
if (sigParams) {
if (sigParams.hashType & bitcoinjs_lib_1.Transaction.SIGHASH_ANYONECANPAY) {
return getPrevoutsDigest([]);
}
}
const bufferWriter = new bufferutils_1.BufferWriter(Buffer.allocUnsafe(36 * ins.length));
ins.forEach(function (txIn) {
bufferWriter.writeSlice(txIn.hash);
bufferWriter.writeUInt32(txIn.index);
});
return getBlake2bHash(bufferWriter.end(), tag);
}
exports.getPrevoutsDigest = getPrevoutsDigest;
function getSequenceDigest(ins, tag = 'ZTxIdSequencHash', sigParams) {
// txid: https://zips.z.cash/zip-0244#t-2b-sequence-digest
// sig: https://zips.z.cash/zip-0244#s-2b-sequence-sig-digest
// https://github.com/zcash-hackworks/zcash-test-vectors/blob/dd8fdb/zip_0244.py#L263
if (sigParams) {
const { hashType } = sigParams;
if (hashType & bitcoinjs_lib_1.Transaction.SIGHASH_ANYONECANPAY ||
(hashType & 0x1f) === bitcoinjs_lib_1.Transaction.SIGHASH_SINGLE ||
(hashType & 0x1f) === bitcoinjs_lib_1.Transaction.SIGHASH_NONE) {
return getSequenceDigest([]);
}
}
const bufferWriter = new bufferutils_1.BufferWriter(Buffer.allocUnsafe(4 * ins.length));
ins.forEach(function (txIn) {
bufferWriter.writeUInt32(txIn.sequence);
});
return getBlake2bHash(bufferWriter.end(), tag);
}
exports.getSequenceDigest = getSequenceDigest;
function getOutputsDigest(outs, tag = 'ZTxIdOutputsHash', sigParams) {
// txid: https://zips.z.cash/zip-0244#t-2c-outputs-digest
// sig: https://zips.z.cash/zip-0244#s-2c-outputs-sig-digest
// https://github.com/zcash-hackworks/zcash-test-vectors/blob/dd8fdb/zip_0244.py#L275
if (sigParams) {
let { hashType } = sigParams;
hashType = hashType & 0x1f;
if (hashType === bitcoinjs_lib_1.Transaction.SIGHASH_SINGLE) {
if (sigParams.inIndex === undefined) {
throw new Error();
}
if (outs[sigParams.inIndex] === undefined) {
return getOutputsDigest(outs);
}
return getOutputsDigest([outs[sigParams.inIndex]]);
}
if (hashType === bitcoinjs_lib_1.Transaction.SIGHASH_NONE) {
return getOutputsDigest([]);
}
return getOutputsDigest(outs, tag);
}
// Find out the size of the outputs and write them
const txOutsSize = outs.reduce(function (sum, output) {
return sum + 8 + UtxoTransaction_1.varSliceSize(output.script);
}, 0);
const bufferWriter = new bufferutils_1.BufferWriter(Buffer.allocUnsafe(txOutsSize));
outs.forEach(function (out) {
bufferWriter.writeUInt64(out.value);
bufferWriter.writeVarSlice(out.script);
});
return getBlake2bHash(bufferWriter.end(), tag);
}
exports.getOutputsDigest = getOutputsDigest;
function getTxinDigest(input, sigParams) {
// https://zips.z.cash/zip-0244#s-2d-txin-sig-digest
// https://github.com/zcash-hackworks/zcash-test-vectors/blob/dd8fdb/zip_0244.py#L291
const writer = bufferutils_1.BufferWriter.withCapacity(32 /* prevout hash */ +
4 /* prevout vin */ +
UtxoTransaction_1.varSliceSize(sigParams.prevOutScript) +
8 /* value */ +
4 /* sequence */);
writer.writeSlice(input.hash);
writer.writeUInt32(input.index);
writer.writeVarSlice(sigParams.prevOutScript);
writer.writeUInt64(sigParams.value);
writer.writeUInt32(input.sequence);
return getBlake2bHash(writer.end(), 'Zcash___TxInHash');
}
function getTransparentDigest(tx, sigParams) {
// txid: https://zips.z.cash/zip-0244#t-2-transparent-digest
// sig: https://zips.z.cash/zip-0244#s-2a-prevouts-sig-digest
if (sigParams) {
if (sigParams.inIndex === undefined) {
return getTransparentDigest(tx);
}
}
let buffer;
if (tx.ins.length || tx.outs.length) {
const writer = bufferutils_1.BufferWriter.withCapacity(32 * (sigParams ? 4 : 3));
writer.writeSlice(getPrevoutsDigest(tx.ins, undefined, sigParams));
writer.writeSlice(getSequenceDigest(tx.ins, undefined, sigParams));
writer.writeSlice(getOutputsDigest(tx.outs, undefined, sigParams));
if (sigParams) {
if (sigParams.inIndex === undefined) {
throw new Error();
}
writer.writeSlice(getTxinDigest(tx.ins[sigParams.inIndex], sigParams));
}
buffer = writer.end();
}
else {
buffer = Buffer.of();
}
return getBlake2bHash(buffer, 'ZTxIdTranspaHash');
}
function getSaplingDigest(tx) {
// https://zips.z.cash/zip-0244#t-3-sapling-digest
return getBlake2bHash(Buffer.of(), 'ZTxIdSaplingHash');
}
function getOrchardDigest(tx) {
// https://zips.z.cash/zip-0244#t-4-orchard-digest
return getBlake2bHash(Buffer.of(), 'ZTxIdOrchardHash');
}
/**
* @param tx
* @param signatureParams - calculates txid when undefined
*/
function getDigest(tx, signatureParams) {
// txid: https://zips.z.cash/zip-0244#id4
// sig: https://zips.z.cash/zip-0244#id13
const writer = bufferutils_1.BufferWriter.withCapacity(32 * 4);
writer.writeSlice(getHeaderDigest(tx));
writer.writeSlice(getTransparentDigest(tx, signatureParams));
writer.writeSlice(getSaplingDigest(tx));
writer.writeSlice(getOrchardDigest(tx));
const tag = 'ZcashTxHash_';
const personalization = bufferutils_1.BufferWriter.withCapacity(tag.length + 4 /* UInt32 */);
personalization.writeSlice(Buffer.from(tag));
personalization.writeUInt32(tx.consensusBranchId);
return getBlake2bHash(writer.end(), personalization.end());
}
function getTxidDigest(tx) {
// https://zips.z.cash/zip-0244#id4
return getDigest(tx);
}
exports.getTxidDigest = getTxidDigest;
function getSignatureDigest(tx, inIndex, prevOutScript, value, hashType) {
// https://zips.z.cash/zip-0244#id13
return getDigest(tx, {
inIndex,
prevOutScript,
value,
hashType,
});
}
exports.getSignatureDigest = getSignatureDigest;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFzaFppcDAyNDQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYml0Z28vemNhc2gvaGFzaFppcDAyNDQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUE7OztHQUdHO0FBQ0gsaURBQStEO0FBQy9ELCtEQUE2RDtBQUU3RCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMscUJBQXFCLENBQUMsQ0FBQztBQUcvQyx3REFBa0Q7QUFTbEQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixjQUFjLENBQUMsTUFBYyxFQUFFLGVBQWdDO0lBQzdFLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbkMsZUFBZSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDL0MsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLGVBQWUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDckYsQ0FBQztBQUpELHdDQUlDO0FBRUQsU0FBUyxlQUFlLENBQWtDLEVBQTZCO0lBQ3JGLGlEQUFpRDtJQUNqRCxNQUFNLElBQUksR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyQyxNQUFNLE1BQU0sR0FBRywwQkFBWSxDQUFDLFlBQVksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDaEQsTUFBTSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsT0FBTyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxxQkFBcUI7SUFDbkUsTUFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDdEMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxF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LENBQUM7SUFDdkMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxvQkFBb0IsQ0FBQyxFQUFFLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztJQUM3RCxNQUFNLENBQUMsVUFBVSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDeEMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRXhDLE1BQU0sR0FBRyxHQUFHLGNBQWMsQ0FBQztJQUMzQixNQUFNLGVBQWUsR0FBRywwQkFBWSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMvRSxlQUFlLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUM3QyxlQUFlLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQ2xELE9BQU8sY0FBYyxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsRUFBRSxlQUFlLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQsU0FBZ0IsYUFBYSxDQUFrQyxFQUE2QjtJQUMxRixtQ0FBbUM7SUFDbkMsT0FBTyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDdkIsQ0FBQztBQUhELHNDQUdDO0FBRUQsU0FBZ0Isa0JBQWtCLENBQ2hDLEVBQTZCLEVBQzdCLE9BQTJCLEVBQzNCLGFBQXFCLEVBQ3JCLEtBQWMsRUFDZCxRQUFnQjtJQUVoQixvQ0FBb0M7SUFDcEMsT0FBTyxTQUFTLENBQUMsRUFBRSxFQUFFO1FBQ25CLE9BQU87UUFDUCxhQUFhO1FBQ2IsS0FBSztRQUNMLFFBQVE7S0FDVCxDQUFDLENBQUM7QUFDTCxDQUFDO0FBZEQsZ0RBY0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEltcGxlbWVudHMgaGFzaGluZyBtZXRob2RzIGRlc2NyaWJlZCBpbiBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0LlxuICogT25seSBzdXBwb3J0cyBmdWxsIHRyYW5zcGFyZW50IHRyYW5zYWN0aW9ucyB3aXRob3V0IHNoaWVsZGVkIGlucHV0cyBvciBvdXRwdXRzLlxuICovXG5pbXBvcnQgeyBUcmFuc2FjdGlvbiwgVHhJbnB1dCwgVHhPdXRwdXQgfSBmcm9tICdiaXRjb2luanMtbGliJztcbmltcG9ydCB7IEJ1ZmZlcldyaXRlciB9IGZyb20gJ2JpdGNvaW5qcy1saWIvc3JjL2J1ZmZlcnV0aWxzJztcblxuY29uc3QgYmxha2UyYiA9IHJlcXVpcmUoJ0BiaXRnby1iZXRhL2JsYWtlMmInKTtcblxuaW1wb3J0IHsgWmNhc2hUcmFuc2FjdGlvbiB9IGZyb20gJy4vWmNhc2hUcmFuc2FjdGlvbic7XG5pbXBvcnQgeyB2YXJTbGljZVNpemUgfSBmcm9tICcuLi9VdHhvVHJhbnNhY3Rpb24nO1xuXG50eXBlIFNpZ25hdHVyZVBhcmFtczxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50ID0gbnVtYmVyPiA9IHtcbiAgaW5JbmRleD86IG51bWJlcjtcbiAgcHJldk91dFNjcmlwdDogQnVmZmVyO1xuICB2YWx1ZTogVE51bWJlcjtcbiAgaGFzaFR5cGU6IG51bWJlcjtcbn07XG5cbi8qKlxuICogQmxha2UyYiBoYXNoaW5nIGFsZ29yaXRobSBmb3IgWmNhc2hcbiAqIEBwYXJhbSBidWZmZXJcbiAqIEBwYXJhbSBwZXJzb25hbGl6YXRpb25cbiAqIEByZXR1cm5zIDI1Ni1iaXQgQkxBS0UyYiBoYXNoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRCbGFrZTJiSGFzaChidWZmZXI6IEJ1ZmZlciwgcGVyc29uYWxpemF0aW9uOiBzdHJpbmcgfCBCdWZmZXIpOiBCdWZmZXIge1xuICBjb25zdCBvdXQgPSBCdWZmZXIuYWxsb2NVbnNhZmUoMzIpO1xuICBwZXJzb25hbGl6YXRpb24gPSBCdWZmZXIuZnJvbShwZXJzb25hbGl6YXRpb24pO1xuICByZXR1cm4gYmxha2UyYihvdXQubGVuZ3RoLCBudWxsLCBudWxsLCBwZXJzb25hbGl6YXRpb24pLnVwZGF0ZShidWZmZXIpLmRpZ2VzdChvdXQpO1xufVxuXG5mdW5jdGlvbiBnZXRIZWFkZXJEaWdlc3Q8VE51bWJlciBleHRlbmRzIG51bWJlciB8IGJpZ2ludD4odHg6IFpjYXNoVHJhbnNhY3Rpb248VE51bWJlcj4pOiBCdWZmZXIge1xuICAvLyBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0I3QtMS1oZWFkZXItZGlnZXN0XG4gIGNvbnN0IG1hc2sgPSB0eC5vdmVyd2ludGVyZWQgPyAxIDogMDtcbiAgY29uc3Qgd3JpdGVyID0gQnVmZmVyV3JpdGVyLndpdGhDYXBhY2l0eSg0ICogNSk7XG4gIHdyaXRlci53cml0ZUludDMyKHR4LnZlcnNpb24gfCAobWFzayA8PCAzMSkpOyAvLyBTZXQgb3ZlcndpbnRlciBiaXRcbiAgd3JpdGVyLndyaXRlVUludDMyKHR4LnZlcnNpb25Hcm91cElkKTtcbiAgd3JpdGVyLndyaXRlVUludDMyKHR4LmNvbnNlbnN1c0JyYW5jaElkKTtcbiAgd3JpdGVyLndyaXRlVUludDMyKHR4LmxvY2t0aW1lKTtcbiAgd3JpdGVyLndyaXRlVUludDMyKHR4LmV4cGlyeUhlaWdodCk7XG4gIHJldHVybiBnZXRCbGFrZTJiSGFzaCh3cml0ZXIuZW5kKCksICdaVHhJZEhlYWRlcnNIYXNoJyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRQcmV2b3V0c0RpZ2VzdDxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50PihcbiAgaW5zOiBUeElucHV0W10sXG4gIHRhZyA9ICdaVHhJZFByZXZvdXRIYXNoJyxcbiAgc2lnUGFyYW1zPzogU2lnbmF0dXJlUGFyYW1zPFROdW1iZXI+XG4pOiBCdWZmZXIge1xuICBpZiAoc2lnUGFyYW1zKSB7XG4gICAgaWYgKHNpZ1BhcmFtcy5oYXNoVHlwZSAmIFRyYW5zYWN0aW9uLlNJR0hBU0hfQU5ZT05FQ0FOUEFZKSB7XG4gICAgICByZXR1cm4gZ2V0UHJldm91dHNEaWdlc3QoW10pO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGJ1ZmZlcldyaXRlciA9IG5ldyBCdWZmZXJXcml0ZXIoQnVmZmVyLmFsbG9jVW5zYWZlKDM2ICogaW5zLmxlbmd0aCkpO1xuICBpbnMuZm9yRWFjaChmdW5jdGlvbiAodHhJbikge1xuICAgIGJ1ZmZlcldyaXRlci53cml0ZVNsaWNlKHR4SW4uaGFzaCk7XG4gICAgYnVmZmVyV3JpdGVyLndyaXRlVUludDMyKHR4SW4uaW5kZXgpO1xuICB9KTtcbiAgcmV0dXJuIGdldEJsYWtlMmJIYXNoKGJ1ZmZlcldyaXRlci5lbmQoKSwgdGFnKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcXVlbmNlRGlnZXN0PFROdW1iZXIgZXh0ZW5kcyBudW1iZXIgfCBiaWdpbnQ+KFxuICBpbnM6IFR4SW5wdXRbXSxcbiAgdGFnID0gJ1pUeElkU2VxdWVuY0hhc2gnLFxuICBzaWdQYXJhbXM/OiBTaWduYXR1cmVQYXJhbXM8VE51bWJlcj5cbik6IEJ1ZmZlciB7XG4gIC8vIHR4aWQ6IGh0dHBzOi8vemlwcy56LmNhc2gvemlwLTAyNDQjdC0yYi1zZXF1ZW5jZS1kaWdlc3RcbiAgLy8gc2lnOiBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0I3MtMmItc2VxdWVuY2Utc2lnLWRpZ2VzdFxuICAvLyBodHRwczovL2dpdGh1Yi5jb20vemNhc2gtaGFja3dvcmtzL3pjYXNoLXRlc3QtdmVjdG9ycy9ibG9iL2RkOGZkYi96aXBfMDI0NC5weSNMMjYzXG4gIGlmIChzaWdQYXJhbXMpIHtcbiAgICBjb25zdCB7IGhhc2hUeXBlIH0gPSBzaWdQYXJhbXM7XG4gICAgaWYgKFxuICAgICAgaGFzaFR5cGUgJiBUcmFuc2FjdGlvbi5TSUdIQVNIX0FOWU9ORUNBTlBBWSB8fFxuICAgICAgKGhhc2hUeXBlICYgMHgxZikgPT09IFRyYW5zYWN0aW9uLlNJR0hBU0hfU0lOR0xFIHx8XG4gICAgICAoaGFzaFR5cGUgJiAweDFmKSA9PT0gVHJhbnNhY3Rpb24uU0lHSEFTSF9OT05FXG4gICAgKSB7XG4gICAgICByZXR1cm4gZ2V0U2VxdWVuY2VEaWdlc3QoW10pO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGJ1ZmZlcldyaXRlciA9IG5ldyBCdWZmZXJXcml0ZXIoQnVmZmVyLmFsbG9jVW5zYWZlKDQgKiBpbnMubGVuZ3RoKSk7XG5cbiAgaW5zLmZvckVhY2goZnVuY3Rpb24gKHR4SW4pIHtcbiAgICBidWZmZXJXcml0ZXIud3JpdGVVSW50MzIodHhJbi5zZXF1ZW5jZSk7XG4gIH0pO1xuXG4gIHJldHVybiBnZXRCbGFrZTJiSGFzaChidWZmZXJXcml0ZXIuZW5kKCksIHRhZyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRPdXRwdXRzRGlnZXN0PFROdW1iZXIgZXh0ZW5kcyBudW1iZXIgfCBiaWdpbnQ+KFxuICBvdXRzOiBUeE91dHB1dDxUTnVtYmVyPltdLFxuICB0YWcgPSAnWlR4SWRPdXRwdXRzSGFzaCcsXG4gIHNpZ1BhcmFtcz86IFNpZ25hdHVyZVBhcmFtczxUTnVtYmVyPlxuKTogQnVmZmVyIHtcbiAgLy8gdHhpZDogaHR0cHM6Ly96aXBzLnouY2FzaC96aXAtMDI0NCN0LTJjLW91dHB1dHMtZGlnZXN0XG4gIC8vIHNpZzogaHR0cHM6Ly96aXBzLnouY2FzaC96aXAtMDI0NCNzLTJjLW91dHB1dHMtc2lnLWRpZ2VzdFxuICAvLyBodHRwczovL2dpdGh1Yi5jb20vemNhc2gtaGFja3dvcmtzL3pjYXNoLXRlc3QtdmVjdG9ycy9ibG9iL2RkOGZkYi96aXBfMDI0NC5weSNMMjc1XG4gIGlmIChzaWdQYXJhbXMpIHtcbiAgICBsZXQgeyBoYXNoVHlwZSB9ID0gc2lnUGFyYW1zO1xuICAgIGhhc2hUeXBlID0gaGFzaFR5cGUgJiAweDFmO1xuXG4gICAgaWYgKGhhc2hUeXBlID09PSBUcmFuc2FjdGlvbi5TSUdIQVNIX1NJTkdMRSkge1xuICAgICAgaWYgKHNpZ1BhcmFtcy5pbkluZGV4ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XG4gICAgICB9XG4gICAgICBpZiAob3V0c1tzaWdQYXJhbXMuaW5JbmRleF0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gZ2V0T3V0cHV0c0RpZ2VzdChvdXRzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBnZXRPdXRwdXRzRGlnZXN0KFtvdXRzW3NpZ1BhcmFtcy5pbkluZGV4XV0pO1xuICAgIH1cblxuICAgIGlmIChoYXNoVHlwZSA9PT0gVHJhbnNhY3Rpb24uU0lHSEFTSF9OT05FKSB7XG4gICAgICByZXR1cm4gZ2V0T3V0cHV0c0RpZ2VzdChbXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdldE91dHB1dHNEaWdlc3Qob3V0cywgdGFnKTtcbiAgfVxuXG4gIC8vIEZpbmQgb3V0IHRoZSBzaXplIG9mIHRoZSBvdXRwdXRzIGFuZCB3cml0ZSB0aGVtXG4gIGNvbnN0IHR4T3V0c1NpemUgPSBvdXRzLnJlZHVjZShmdW5jdGlvbiAoc3VtLCBvdXRwdXQpIHtcbiAgICByZXR1cm4gc3VtICsgOCArIHZhclNsaWNlU2l6ZShvdXRwdXQuc2NyaXB0KTtcbiAgfSwgMCk7XG5cbiAgY29uc3QgYnVmZmVyV3JpdGVyID0gbmV3IEJ1ZmZlcldyaXRlcihCdWZmZXIuYWxsb2NVbnNhZmUodHhPdXRzU2l6ZSkpO1xuXG4gIG91dHMuZm9yRWFjaChmdW5jdGlvbiAob3V0KSB7XG4gICAgYnVmZmVyV3JpdGVyLndyaXRlVUludDY0KG91dC52YWx1ZSk7XG4gICAgYnVmZmVyV3JpdGVyLndyaXRlVmFyU2xpY2Uob3V0LnNjcmlwdCk7XG4gIH0pO1xuXG4gIHJldHVybiBnZXRCbGFrZTJiSGFzaChidWZmZXJXcml0ZXIuZW5kKCksIHRhZyk7XG59XG5cbmZ1bmN0aW9uIGdldFR4aW5EaWdlc3Q8VE51bWJlciBleHRlbmRzIG51bWJlciB8IGJpZ2ludD4oaW5wdXQ6IFR4SW5wdXQsIHNpZ1BhcmFtczogU2lnbmF0dXJlUGFyYW1zPFROdW1iZXI+KSB7XG4gIC8vIGh0dHBzOi8vemlwcy56LmNhc2gvemlwLTAyNDQjcy0yZC10eGluLXNpZy1kaWdlc3RcbiAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3pjYXNoLWhhY2t3b3Jrcy96Y2FzaC10ZXN0LXZlY3RvcnMvYmxvYi9kZDhmZGIvemlwXzAyNDQucHkjTDI5MVxuICBjb25zdCB3cml0ZXIgPSBCdWZmZXJXcml0ZXIud2l0aENhcGFjaXR5KFxuICAgIDMyIC8qIHByZXZvdXQgaGFzaCAqLyArXG4gICAgICA0IC8qIHByZXZvdXQgdmluICovICtcbiAgICAgIHZhclNsaWNlU2l6ZShzaWdQYXJhbXMucHJldk91dFNjcmlwdCkgK1xuICAgICAgOCAvKiB2YWx1ZSAqLyArXG4gICAgICA0IC8qIHNlcXVlbmNlICovXG4gICk7XG4gIHdyaXRlci53cml0ZVNsaWNlKGlucHV0Lmhhc2gpO1xuICB3cml0ZXIud3JpdGVVSW50MzIoaW5wdXQuaW5kZXgpO1xuICB3cml0ZXIud3JpdGVWYXJTbGljZShzaWdQYXJhbXMucHJldk91dFNjcmlwdCk7XG4gIHdyaXRlci53cml0ZVVJbnQ2NChzaWdQYXJhbXMudmFsdWUpO1xuICB3cml0ZXIud3JpdGVVSW50MzIoaW5wdXQuc2VxdWVuY2UpO1xuICByZXR1cm4gZ2V0Qmxha2UyYkhhc2god3JpdGVyLmVuZCgpLCAnWmNhc2hfX19UeEluSGFzaCcpO1xufVxuXG5mdW5jdGlvbiBnZXRUcmFuc3BhcmVudERpZ2VzdDxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50PihcbiAgdHg6IHsgaW5zOiBUeElucHV0W107IG91dHM6IFR4T3V0cHV0PFROdW1iZXI+W10gfSxcbiAgc2lnUGFyYW1zPzogU2lnbmF0dXJlUGFyYW1zPFROdW1iZXI+XG4pOiBCdWZmZXIge1xuICAvLyB0eGlkOiBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0I3QtMi10cmFuc3BhcmVudC1kaWdlc3RcbiAgLy8gc2lnOiBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0I3MtMmEtcHJldm91dHMtc2lnLWRpZ2VzdFxuICBpZiAoc2lnUGFyYW1zKSB7XG4gICAgaWYgKHNpZ1BhcmFtcy5pbkluZGV4ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBnZXRUcmFuc3BhcmVudERpZ2VzdCh0eCk7XG4gICAgfVxuICB9XG5cbiAgbGV0IGJ1ZmZlcjtcbiAgaWYgKHR4Lmlucy5sZW5ndGggfHwgdHgub3V0cy5sZW5ndGgpIHtcbiAgICBjb25zdCB3cml0ZXIgPSBCdWZmZXJXcml0ZXIud2l0aENhcGFjaXR5KDMyICogKHNpZ1BhcmFtcyA/IDQgOiAzKSk7XG4gICAgd3JpdGVyLndyaXRlU2xpY2UoZ2V0UHJldm91dHNEaWdlc3QodHguaW5zLCB1bmRlZmluZWQsIHNpZ1BhcmFtcykpO1xuICAgIHdyaXRlci53cml0ZVNsaWNlKGdldFNlcXVlbmNlRGlnZXN0KHR4LmlucywgdW5kZWZpbmVkLCBzaWdQYXJhbXMpKTtcbiAgICB3cml0ZXIud3JpdGVTbGljZShnZXRPdXRwdXRzRGlnZXN0KHR4Lm91dHMsIHVuZGVmaW5lZCwgc2lnUGFyYW1zKSk7XG4gICAgaWYgKHNpZ1BhcmFtcykge1xuICAgICAgaWYgKHNpZ1BhcmFtcy5pbkluZGV4ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XG4gICAgICB9XG4gICAgICB3cml0ZXIud3JpdGVTbGljZShnZXRUeGluRGlnZXN0KHR4Lmluc1tzaWdQYXJhbXMuaW5JbmRleF0sIHNpZ1BhcmFtcykpO1xuICAgIH1cbiAgICBidWZmZXIgPSB3cml0ZXIuZW5kKCk7XG4gIH0gZWxzZSB7XG4gICAgYnVmZmVyID0gQnVmZmVyLm9mKCk7XG4gIH1cbiAgcmV0dXJuIGdldEJsYWtlMmJIYXNoKGJ1ZmZlciwgJ1pUeElkVHJhbnNwYUhhc2gnKTtcbn1cblxuZnVuY3Rpb24gZ2V0U2FwbGluZ0RpZ2VzdDxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50Pih0eDogWmNhc2hUcmFuc2FjdGlvbjxUTnVtYmVyPik6IEJ1ZmZlciB7XG4gIC8vIGh0dHBzOi8vemlwcy56LmNhc2gvemlwLTAyNDQjdC0zLXNhcGxpbmctZGlnZXN0XG4gIHJldHVybiBnZXRCbGFrZTJiSGFzaChCdWZmZXIub2YoKSwgJ1pUeElkU2FwbGluZ0hhc2gnKTtcbn1cblxuZnVuY3Rpb24gZ2V0T3JjaGFyZERpZ2VzdDxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50Pih0eDogWmNhc2hUcmFuc2FjdGlvbjxUTnVtYmVyPik6IEJ1ZmZlciB7XG4gIC8vIGh0dHBzOi8vemlwcy56LmNhc2gvemlwLTAyNDQjdC00LW9yY2hhcmQtZGlnZXN0XG4gIHJldHVybiBnZXRCbGFrZTJiSGFzaChCdWZmZXIub2YoKSwgJ1pUeElkT3JjaGFyZEhhc2gnKTtcbn1cblxuLyoqXG4gKiBAcGFyYW0gdHhcbiAqIEBwYXJhbSBzaWduYXR1cmVQYXJhbXMgLSBjYWxjdWxhdGVzIHR4aWQgd2hlbiB1bmRlZmluZWRcbiAqL1xuZnVuY3Rpb24gZ2V0RGlnZXN0PFROdW1iZXIgZXh0ZW5kcyBudW1iZXIgfCBiaWdpbnQ+KFxuICB0eDogWmNhc2hUcmFuc2FjdGlvbjxUTnVtYmVyPixcbiAgc2lnbmF0dXJlUGFyYW1zPzogU2lnbmF0dXJlUGFyYW1zPFROdW1iZXI+XG4pOiBCdWZmZXIge1xuICAvLyB0eGlkOiBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0I2lkNFxuICAvLyBzaWc6IGh0dHBzOi8vemlwcy56LmNhc2gvemlwLTAyNDQjaWQxM1xuICBjb25zdCB3cml0ZXIgPSBCdWZmZXJXcml0ZXIud2l0aENhcGFjaXR5KDMyICogNCk7XG4gIHdyaXRlci53cml0ZVNsaWNlKGdldEhlYWRlckRpZ2VzdCh0eCkpO1xuICB3cml0ZXIud3JpdGVTbGljZShnZXRUcmFuc3BhcmVudERpZ2VzdCh0eCwgc2lnbmF0dXJlUGFyYW1zKSk7XG4gIHdyaXRlci53cml0ZVNsaWNlKGdldFNhcGxpbmdEaWdlc3QodHgpKTtcbiAgd3JpdGVyLndyaXRlU2xpY2UoZ2V0T3JjaGFyZERpZ2VzdCh0eCkpO1xuXG4gIGNvbnN0IHRhZyA9ICdaY2FzaFR4SGFzaF8nO1xuICBjb25zdCBwZXJzb25hbGl6YXRpb24gPSBCdWZmZXJXcml0ZXIud2l0aENhcGFjaXR5KHRhZy5sZW5ndGggKyA0IC8qIFVJbnQzMiAqLyk7XG4gIHBlcnNvbmFsaXphdGlvbi53cml0ZVNsaWNlKEJ1ZmZlci5mcm9tKHRhZykpO1xuICBwZXJzb25hbGl6YXRpb24ud3JpdGVVSW50MzIodHguY29uc2Vuc3VzQnJhbmNoSWQpO1xuICByZXR1cm4gZ2V0Qmxha2UyYkhhc2god3JpdGVyLmVuZCgpLCBwZXJzb25hbGl6YXRpb24uZW5kKCkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VHhpZERpZ2VzdDxUTnVtYmVyIGV4dGVuZHMgbnVtYmVyIHwgYmlnaW50Pih0eDogWmNhc2hUcmFuc2FjdGlvbjxUTnVtYmVyPik6IEJ1ZmZlciB7XG4gIC8vIGh0dHBzOi8vemlwcy56LmNhc2gvemlwLTAyNDQjaWQ0XG4gIHJldHVybiBnZXREaWdlc3QodHgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2lnbmF0dXJlRGlnZXN0PFROdW1iZXIgZXh0ZW5kcyBudW1iZXIgfCBiaWdpbnQ+KFxuICB0eDogWmNhc2hUcmFuc2FjdGlvbjxUTnVtYmVyPixcbiAgaW5JbmRleDogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBwcmV2T3V0U2NyaXB0OiBCdWZmZXIsXG4gIHZhbHVlOiBUTnVtYmVyLFxuICBoYXNoVHlwZTogbnVtYmVyXG4pOiBCdWZmZXIge1xuICAvLyBodHRwczovL3ppcHMuei5jYXNoL3ppcC0wMjQ0I2lkMTNcbiAgcmV0dXJuIGdldERpZ2VzdCh0eCwge1xuICAgIGluSW5kZXgsXG4gICAgcHJldk91dFNjcmlwdCxcbiAgICB2YWx1ZSxcbiAgICBoYXNoVHlwZSxcbiAgfSk7XG59XG4iXX0=