UNPKG

@bitgo/utxo-lib

Version:

Client-side Bitcoin JavaScript library

357 lines 55.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Musig2NonceStore = void 0; exports.encodePsbtMusig2Participants = encodePsbtMusig2Participants; exports.encodePsbtMusig2PubNonce = encodePsbtMusig2PubNonce; exports.encodePsbtMusig2PartialSig = encodePsbtMusig2PartialSig; exports.decodePsbtMusig2Participants = decodePsbtMusig2Participants; exports.decodePsbtMusig2Nonce = decodePsbtMusig2Nonce; exports.decodePsbtMusig2PartialSig = decodePsbtMusig2PartialSig; exports.createTapInternalKey = createTapInternalKey; exports.createTapOutputKey = createTapOutputKey; exports.createAggregateNonce = createAggregateNonce; exports.createTapTweak = createTapTweak; exports.musig2PartialSign = musig2PartialSign; exports.musig2PartialSigVerify = musig2PartialSigVerify; exports.musig2AggregateSigs = musig2AggregateSigs; exports.createMusig2SigningSession = createMusig2SigningSession; exports.parsePsbtMusig2Participants = parsePsbtMusig2Participants; exports.parsePsbtMusig2Nonces = parsePsbtMusig2Nonces; exports.parsePsbtMusig2PartialSigs = parsePsbtMusig2PartialSigs; exports.assertPsbtMusig2Participants = assertPsbtMusig2Participants; exports.assertPsbtMusig2Nonces = assertPsbtMusig2Nonces; exports.getSigHashTypeFromSigs = getSigHashTypeFromSigs; exports.createMusig2DeterministicNonce = createMusig2DeterministicNonce; exports.musig2DeterministicSign = musig2DeterministicSign; const outputScripts_1 = require("./outputScripts"); const secp256k1_1 = require("@bitgo/secp256k1"); const taproot_1 = require("../taproot"); const index_1 = require("../index"); const PsbtUtil_1 = require("./PsbtUtil"); /** * Because musig uses reference-equal buffers to cache nonces, we wrap it here to allow using * nonces that are byte-equal but not reference-equal. */ class Musig2NonceStore { constructor() { this.nonces = []; } /** * Get original Buffer instance for nonce (which may be a copy). * @return byte-equal buffer that is reference-equal to what was stored earlier in createMusig2Nonce */ getRef(nonce) { for (const b of this.nonces) { if (Buffer.from(b).equals(nonce)) { return b; } } throw new Error(`unknown nonce`); } /** * Creates musig2 nonce and stores buffer reference. * tapInternalkey, tapMerkleRoot, tapBip32Derivation for rootWalletKey are required per p2trMusig2 key path input. * Also participant keys are required from psbt proprietary key values. * Ref: https://gist.github.com/sanket1729/4b525c6049f4d9e034d27368c49f28a6 * @param privateKey - signer private key * @param publicKey - signer xy public key * @param xOnlyPublicKey - tweaked aggregated key (tapOutputKey) * @param sessionId Additional entropy. If provided it must either be a counter unique to this secret key, * (converted to an array of 32 bytes), or 32 uniformly random bytes. */ createMusig2Nonce(privateKey, publicKey, xOnlyPublicKey, txHash, sessionId) { if (txHash.length != 32) { throw new Error(`Invalid txHash size ${txHash}`); } const buf = secp256k1_1.musig.nonceGen({ secretKey: privateKey, publicKey, xOnlyPublicKey, msg: txHash, sessionId }); this.nonces.push(buf); return buf; } } exports.Musig2NonceStore = Musig2NonceStore; /** * Psbt proprietary key val util function for participants pub keys. SubType is 0x01 * Ref: https://gist.github.com/sanket1729/4b525c6049f4d9e034d27368c49f28a6 * @return x-only tapOutputKey||tapInternalKey as sub keydata, plain sigining participant keys as valuedata */ function encodePsbtMusig2Participants(participants) { const keydata = [participants.tapOutputKey, participants.tapInternalKey].map((pubkey) => (0, outputScripts_1.checkXOnlyPublicKey)(pubkey)); const value = participants.participantPubKeys.map((pubkey) => (0, outputScripts_1.checkPlainPublicKey)(pubkey)); const key = { identifier: PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER, subtype: PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PARTICIPANT_PUB_KEYS, keydata: Buffer.concat(keydata), }; return { key, value: Buffer.concat(value) }; } /** * Psbt proprietary key val util function for pub nonce. SubType is 0x02 * Ref: https://gist.github.com/sanket1729/4b525c6049f4d9e034d27368c49f28a6 * @return plain-participantPubKey||x-only-tapOutputKey as sub keydata, 66 bytes of 2 pub nonces as valuedata */ function encodePsbtMusig2PubNonce(nonce) { if (nonce.pubNonce.length !== 66) { throw new Error(`Invalid pubNonces length ${nonce.pubNonce.length}`); } const keydata = Buffer.concat([ (0, outputScripts_1.checkPlainPublicKey)(nonce.participantPubKey), (0, outputScripts_1.checkXOnlyPublicKey)(nonce.tapOutputKey), ]); const key = { identifier: PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER, subtype: PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PUB_NONCE, keydata, }; return { key, value: nonce.pubNonce }; } function encodePsbtMusig2PartialSig(partialSig) { if (partialSig.partialSig.length !== 32 && partialSig.partialSig.length !== 33) { throw new Error(`Invalid partialSig length ${partialSig.partialSig.length}`); } const keydata = Buffer.concat([ (0, outputScripts_1.checkPlainPublicKey)(partialSig.participantPubKey), (0, outputScripts_1.checkXOnlyPublicKey)(partialSig.tapOutputKey), ]); const key = { identifier: PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER, subtype: PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PARTIAL_SIG, keydata, }; return { key, value: partialSig.partialSig }; } /** * Decodes proprietary key value data for participant pub keys * @param kv */ function decodePsbtMusig2Participants(kv) { if (kv.key.identifier !== PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER || kv.key.subtype !== PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PARTICIPANT_PUB_KEYS) { throw new Error(`Invalid identifier ${kv.key.identifier} or subtype ${kv.key.subtype} for participants pub keys`); } const key = kv.key.keydata; if (key.length !== 64) { throw new Error(`Invalid keydata size ${key.length} for participant pub keys`); } const value = kv.value; if (value.length !== 66) { throw new Error(`Invalid valuedata size ${value.length} for participant pub keys`); } const participantPubKeys = [value.subarray(0, 33), value.subarray(33)]; if (participantPubKeys[0].equals(participantPubKeys[1])) { throw new Error(`Duplicate participant pub keys found`); } return { tapOutputKey: key.subarray(0, 32), tapInternalKey: key.subarray(32), participantPubKeys }; } /** * Decodes proprietary key value data for musig2 nonce * @param kv */ function decodePsbtMusig2Nonce(kv) { if (kv.key.identifier !== PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER || kv.key.subtype !== PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PUB_NONCE) { throw new Error(`Invalid identifier ${kv.key.identifier} or subtype ${kv.key.subtype} for nonce`); } const key = kv.key.keydata; if (key.length !== 65) { throw new Error(`Invalid keydata size ${key.length} for nonce`); } const value = kv.value; if (value.length !== 66) { throw new Error(`Invalid valuedata size ${value.length} for nonce`); } return { participantPubKey: key.subarray(0, 33), tapOutputKey: key.subarray(33), pubNonce: value }; } /** * Decodes proprietary key value data for musig2 partial sig * @param kv */ function decodePsbtMusig2PartialSig(kv) { if (kv.key.identifier !== PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER || kv.key.subtype !== PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PARTIAL_SIG) { throw new Error(`Invalid identifier ${kv.key.identifier} or subtype ${kv.key.subtype} for partial sig`); } const key = kv.key.keydata; if (key.length !== 65) { throw new Error(`Invalid keydata size ${key.length} for partial sig`); } const value = kv.value; if (value.length !== 32 && value.length !== 33) { throw new Error(`Invalid valuedata size ${value.length} for partial sig`); } return { participantPubKey: key.subarray(0, 33), tapOutputKey: key.subarray(33), partialSig: value }; } function createTapInternalKey(plainPubKeys) { return Buffer.from(secp256k1_1.musig.getXOnlyPubkey(secp256k1_1.musig.keyAgg(plainPubKeys))); } function createTapOutputKey(internalPubKey, tapTreeRoot) { return Buffer.from((0, taproot_1.tapTweakPubkey)(secp256k1_1.ecc, (0, outputScripts_1.toXOnlyPublicKey)(internalPubKey), (0, outputScripts_1.checkTapMerkleRoot)(tapTreeRoot)).xOnlyPubkey); } function createAggregateNonce(pubNonces) { return Buffer.from(secp256k1_1.musig.nonceAgg(pubNonces)); } function createTapTweak(tapInternalKey, tapMerkleRoot) { return Buffer.from((0, taproot_1.calculateTapTweak)((0, outputScripts_1.checkXOnlyPublicKey)(tapInternalKey), (0, outputScripts_1.checkTapMerkleRoot)(tapMerkleRoot))); } function startMusig2SigningSession(aggNonce, hash, publicKeys, tweak) { return secp256k1_1.musig.startSigningSession(aggNonce, hash, publicKeys, { tweak, xOnly: true }); } function musig2PartialSign(privateKey, publicNonce, sessionKey, nonceStore) { (0, outputScripts_1.checkTxHash)(Buffer.from(sessionKey.msg)); return Buffer.from(secp256k1_1.musig.partialSign({ secretKey: privateKey, publicNonce: nonceStore.getRef(publicNonce), sessionKey, })); } function musig2PartialSigVerify(sig, publicKey, publicNonce, sessionKey) { (0, outputScripts_1.checkTxHash)(Buffer.from(sessionKey.msg)); return secp256k1_1.musig.partialVerify({ sig, publicKey, publicNonce, sessionKey }); } function musig2AggregateSigs(sigs, sessionKey) { return Buffer.from(secp256k1_1.musig.signAgg(sigs, sessionKey)); } /** @return session key that can be used to reference the session later */ function createMusig2SigningSession(sessionArgs) { (0, outputScripts_1.checkTxHash)(sessionArgs.txHash); const aggNonce = createAggregateNonce(sessionArgs.pubNonces); const tweak = createTapTweak(sessionArgs.internalPubKey, sessionArgs.tapTreeRoot); return startMusig2SigningSession(aggNonce, sessionArgs.txHash, sessionArgs.pubKeys, tweak); } /** * @returns psbt proprietary key for musig2 participant key value data * If no key value exists, undefined is returned. */ function parsePsbtMusig2Participants(input) { const participantsKeyVals = (0, PsbtUtil_1.getPsbtInputProprietaryKeyVals)(input, { identifier: PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER, subtype: PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PARTICIPANT_PUB_KEYS, }); if (!participantsKeyVals.length) { return undefined; } if (participantsKeyVals.length > 1) { throw new Error(`Found ${participantsKeyVals.length} matching participant key value instead of 1`); } return decodePsbtMusig2Participants(participantsKeyVals[0]); } /** * @returns psbt proprietary key for musig2 public nonce key value data * If no key value exists, undefined is returned. */ function parsePsbtMusig2Nonces(input) { const nonceKeyVals = (0, PsbtUtil_1.getPsbtInputProprietaryKeyVals)(input, { identifier: PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER, subtype: PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PUB_NONCE, }); if (!nonceKeyVals.length) { return undefined; } if (nonceKeyVals.length > 2) { throw new Error(`Found ${nonceKeyVals.length} matching nonce key value instead of 1 or 2`); } return nonceKeyVals.map((kv) => decodePsbtMusig2Nonce(kv)); } /** * @returns psbt proprietary key for musig2 partial sig key value data * If no key value exists, undefined is returned. */ function parsePsbtMusig2PartialSigs(input) { const sigKeyVals = (0, PsbtUtil_1.getPsbtInputProprietaryKeyVals)(input, { identifier: PsbtUtil_1.PSBT_PROPRIETARY_IDENTIFIER, subtype: PsbtUtil_1.ProprietaryKeySubtype.MUSIG2_PARTIAL_SIG, }); if (!sigKeyVals.length) { return undefined; } if (sigKeyVals.length > 2) { throw new Error(`Found ${sigKeyVals.length} matching partial signature key value instead of 1 or 2`); } return sigKeyVals.map((kv) => decodePsbtMusig2PartialSig(kv)); } /** * Assert musig2 participant key value data with tapInternalKey and tapMerkleRoot. * <tapOutputKey><tapInputKey> => <participantKey1><participantKey2> * Using tapMerkleRoot and 2 participant keys, the tapInputKey is validated and using tapMerkleRoot and tapInputKey, * the tapOutputKey is validated. */ function assertPsbtMusig2Participants(participantKeyValData, tapInternalKey, tapMerkleRoot) { (0, outputScripts_1.checkXOnlyPublicKey)(tapInternalKey); (0, outputScripts_1.checkTapMerkleRoot)(tapMerkleRoot); const participantPubKeys = participantKeyValData.participantPubKeys; const internalKey = createTapInternalKey(participantPubKeys); if (!internalKey.equals(participantKeyValData.tapInternalKey)) { throw new Error('Invalid participants keydata tapInternalKey'); } const outputKey = createTapOutputKey(internalKey, tapMerkleRoot); if (!outputKey.equals(participantKeyValData.tapOutputKey)) { throw new Error('Invalid participants keydata tapOutputKey'); } if (!internalKey.equals(tapInternalKey)) { throw new Error('tapInternalKey and aggregated participant pub keys does not match'); } } /** * Assert musig2 public nonce key value data with participant key value data * (refer assertPsbtMusig2ParticipantsKeyValData). * <participantKey1><tapOutputKey> => <pubNonce1> * <participantKey2><tapOutputKey> => <pubNonce2> * Checks against participant keys and tapOutputKey */ function assertPsbtMusig2Nonces(noncesKeyValData, participantKeyValData) { (0, outputScripts_1.checkXOnlyPublicKey)(participantKeyValData.tapOutputKey); participantKeyValData.participantPubKeys.forEach((kv) => (0, outputScripts_1.checkPlainPublicKey)(kv)); if (participantKeyValData.participantPubKeys[0].equals(participantKeyValData.participantPubKeys[1])) { throw new Error(`Duplicate participant pub keys found`); } if (noncesKeyValData.length > 2) { throw new Error(`Invalid nonce key value count ${noncesKeyValData.length}`); } noncesKeyValData.forEach((nonceKv) => { const index = participantKeyValData.participantPubKeys.findIndex((pubKey) => nonceKv.participantPubKey.equals(pubKey)); if (index < 0) { throw new Error('Invalid nonce keydata participant pub key'); } if (!nonceKv.tapOutputKey.equals(participantKeyValData.tapOutputKey)) { throw new Error('Invalid nonce keydata tapOutputKey'); } }); } /** * @returns Input object but sig hash type data is taken out from partialSig field. * If sig hash type is not common for all sigs, error out, otherwise returns the modified object and single hash type. */ function getSigHashTypeFromSigs(partialSigs) { if (!partialSigs.length) { throw new Error('partialSigs array can not be empty'); } const pSigsWithHashType = partialSigs.map((kv) => { const { partialSig, participantPubKey, tapOutputKey } = kv; return partialSig.length === 33 ? { pSig: { partialSig: partialSig.slice(0, 32), participantPubKey, tapOutputKey }, sigHashType: partialSig[32] } : { pSig: { partialSig, participantPubKey, tapOutputKey }, sigHashType: index_1.Transaction.SIGHASH_DEFAULT }; }); const sigHashType = pSigsWithHashType[0].sigHashType; if (!pSigsWithHashType.every((pSig) => pSig.sigHashType === sigHashType)) { throw new Error('signatures must use same sig hash type'); } return { partialSigs: pSigsWithHashType.map(({ pSig }) => pSig), sigHashType }; } function createMusig2DeterministicNonce(params) { return Buffer.from(secp256k1_1.musig.deterministicNonceGen({ secretKey: params.privateKey, aggOtherNonce: secp256k1_1.musig.nonceAgg([params.otherNonce]), publicKeys: params.publicKeys, tweaks: [{ tweak: createTapTweak(params.internalPubKey, params.tapTreeRoot), xOnly: true }], msg: params.hash, }).publicNonce); } function musig2DeterministicSign(params) { const { sig, sessionKey, publicNonce } = secp256k1_1.musig.deterministicSign({ secretKey: params.privateKey, aggOtherNonce: secp256k1_1.musig.nonceAgg([params.otherNonce]), publicKeys: params.publicKeys, tweaks: [{ tweak: createTapTweak(params.internalPubKey, params.tapTreeRoot), xOnly: true }], msg: params.hash, }); return { sig: Buffer.from(sig), sessionKey, publicNonce: Buffer.from(publicNonce) }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTXVzaWcyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JpdGdvL011c2lnMi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUF5R0Esb0VBU0M7QUFPRCw0REFjQztBQUVELGdFQWNDO0FBTUQsb0VBdUJDO0FBTUQsc0RBZ0JDO0FBTUQsZ0VBbUJDO0FBRUQsb0RBRUM7QUFFRCxnREFJQztBQUVELG9EQUVDO0FBRUQsd0NBRUM7QUFXRCw4Q0FjQztBQUVELHdEQVFDO0FBRUQsa0RBRUM7QUFHRCxnRUFXQztBQU1ELGtFQWVDO0FBTUQsc0RBZUM7QUFNRCxnRUFlQztBQVFELG9FQXVCQztBQVNELHdEQTBCQztBQU1ELHdEQW9CQztBQUVELHdFQVVDO0FBRUQsMERBYUM7QUE5ZEQsbURBTXlCO0FBQ3pCLGdEQUE4QztBQUU5Qyx3Q0FBK0Q7QUFDL0Qsb0NBQXVDO0FBRXZDLHlDQUFnSDtBQXVDaEg7OztHQUdHO0FBQ0gsTUFBYSxnQkFBZ0I7SUFBN0I7UUFDVSxXQUFNLEdBQWlCLEVBQUUsQ0FBQztJQXdDcEMsQ0FBQztJQXRDQzs7O09BR0c7SUFDSCxNQUFNLENBQUMsS0FBaUI7UUFDdEIsS0FBSyxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDNUIsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUNqQyxPQUFPLENBQUMsQ0FBQztZQUNYLENBQUM7UUFDSCxDQUFDO1FBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNILGlCQUFpQixDQUNmLFVBQXNCLEVBQ3RCLFNBQXFCLEVBQ3JCLGNBQTBCLEVBQzFCLE1BQWtCLEVBQ2xCLFNBQWtCO1FBRWxCLElBQUksTUFBTSxDQUFDLE1BQU0sSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUN4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QUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO0FBQ3RGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBTZXNzaW9uS2V5IH0gZnJvbSAnQGJyYW5kb25ibGFjay9tdXNpZyc7XG5cbmltcG9ydCB7XG4gIGNoZWNrUGxhaW5QdWJsaWNLZXksXG4gIGNoZWNrVGFwTWVya2xlUm9vdCxcbiAgY2hlY2tUeEhhc2gsXG4gIGNoZWNrWE9ubHlQdWJsaWNLZXksXG4gIHRvWE9ubHlQdWJsaWNLZXksXG59IGZyb20gJy4vb3V0cHV0U2NyaXB0cyc7XG5pbXBvcnQgeyBlY2MsIG11c2lnIH0gZnJvbSAnQGJpdGdvL3NlY3AyNTZrMSc7XG5pbXBvcnQgeyBUdXBsZSB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgY2FsY3VsYXRlVGFwVHdlYWssIHRhcFR3ZWFrUHVia2V5IH0gZnJvbSAnLi4vdGFwcm9vdCc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvbiB9IGZyb20gJy4uL2luZGV4JztcbmltcG9ydCB7IFBzYnRJbnB1dCB9IGZyb20gJ2JpcDE3NC9zcmMvbGliL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgZ2V0UHNidElucHV0UHJvcHJpZXRhcnlLZXlWYWxzLCBQcm9wcmlldGFyeUtleVN1YnR5cGUsIFBTQlRfUFJPUFJJRVRBUllfSURFTlRJRklFUiB9IGZyb20gJy4vUHNidFV0aWwnO1xuaW1wb3J0IHsgUHJvcHJpZXRhcnlLZXlWYWx1ZSB9IGZyb20gJy4vUHJvcHJpZXRhcnlLZXlWYWxVdGlscyc7XG5cbi8qKlxuICogIFBhcnRpY2lwYW50IGtleSB2YWx1ZSBvYmplY3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHNidE11c2lnMlBhcnRpY2lwYW50cyB7XG4gIHRhcE91dHB1dEtleTogQnVmZmVyO1xuICB0YXBJbnRlcm5hbEtleTogQnVmZmVyO1xuICBwYXJ0aWNpcGFudFB1YktleXM6IFR1cGxlPEJ1ZmZlcj47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHNidE11c2lnMkRldGVybWluaXN0aWNQYXJhbXMge1xuICBwcml2YXRlS2V5OiBCdWZmZXI7XG4gIG90aGVyTm9uY2U6IEJ1ZmZlcjtcbiAgcHVibGljS2V5czogVHVwbGU8QnVmZmVyPjtcbiAgaW50ZXJuYWxQdWJLZXk6IEJ1ZmZlcjtcbiAgdGFwVHJlZVJvb3Q6IEJ1ZmZlcjtcbiAgaGFzaDogQnVmZmVyO1xufVxuXG4vKipcbiAqICBOb25jZSBrZXkgdmFsdWUgb2JqZWN0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBzYnRNdXNpZzJQdWJOb25jZSB7XG4gIHBhcnRpY2lwYW50UHViS2V5OiBCdWZmZXI7XG4gIHRhcE91dHB1dEtleTogQnVmZmVyO1xuICBwdWJOb25jZTogQnVmZmVyO1xufVxuXG4vKipcbiAqICBQYXJ0aWFsIHNpZ25hdHVyZSBrZXkgdmFsdWUgb2JqZWN0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBzYnRNdXNpZzJQYXJ0aWFsU2lnIHtcbiAgcGFydGljaXBhbnRQdWJLZXk6IEJ1ZmZlcjtcbiAgdGFwT3V0cHV0S2V5OiBCdWZmZXI7XG4gIHBhcnRpYWxTaWc6IEJ1ZmZlcjtcbn1cblxuLyoqXG4gKiBCZWNhdXNlIG11c2lnIHVzZXMgcmVmZXJlbmNlLWVxdWFsIGJ1ZmZlcnMgdG8gY2FjaGUgbm9uY2VzLCB3ZSB3cmFwIGl0IGhlcmUgdG8gYWxsb3cgdXNpbmdcbiAqIG5vbmNlcyB0aGF0IGFyZSBieXRlLWVxdWFsIGJ1dCBub3QgcmVmZXJlbmNlLWVxdWFsLlxuICovXG5leHBvcnQgY2xhc3MgTXVzaWcyTm9uY2VTdG9yZSB7XG4gIHByaXZhdGUgbm9uY2VzOiBVaW50OEFycmF5W10gPSBbXTtcblxuICAvKipcbiAgICogR2V0IG9yaWdpbmFsIEJ1ZmZlciBpbnN0YW5jZSBmb3Igbm9uY2UgKHdoaWNoIG1heSBiZSBhIGNvcHkpLlxuICAgKiBAcmV0dXJuIGJ5dGUtZXF1YWwgYnVmZmVyIHRoYXQgaXMgcmVmZXJlbmNlLWVxdWFsIHRvIHdoYXQgd2FzIHN0b3JlZCBlYXJsaWVyIGluIGNyZWF0ZU11c2lnMk5vbmNlXG4gICAqL1xuICBnZXRSZWYobm9uY2U6IFVpbnQ4QXJyYXkpOiBVaW50OEFycmF5IHtcbiAgICBmb3IgKGNvbnN0IGIgb2YgdGhpcy5ub25jZXMpIHtcbiAgICAgIGlmIChCdWZmZXIuZnJvbShiKS5lcXVhbHMobm9uY2UpKSB7XG4gICAgICAgIHJldHVybiBiO1xuICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYHVua25vd24gbm9uY2VgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIG11c2lnMiBub25jZSBhbmQgc3RvcmVzIGJ1ZmZlciByZWZlcmVuY2UuXG4gICAqIHRhcEludGVybmFsa2V5LCB0YXBNZXJrbGVSb290LCB0YXBCaXAzMkRlcml2YXRpb24gZm9yIHJvb3RXYWxsZXRLZXkgYXJlIHJlcXVpcmVkIHBlciBwMnRyTXVzaWcyIGtleSBwYXRoIGlucHV0LlxuICAgKiBBbHNvIHBhcnRpY2lwYW50IGtleXMgYXJlIHJlcXVpcmVkIGZyb20gcHNidCBwcm9wcmlldGFyeSBrZXkgdmFsdWVzLlxuICAgKiBSZWY6IGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3NhbmtldDE3MjkvNGI1MjVjNjA0OWY0ZDllMDM0ZDI3MzY4YzQ5ZjI4YTZcbiAgICogQHBhcmFtIHByaXZhdGVLZXkgLSBzaWduZXIgcHJpdmF0ZSBrZXlcbiAgICogQHBhcmFtIHB1YmxpY0tleSAtIHNpZ25lciB4eSBwdWJsaWMga2V5XG4gICAqIEBwYXJhbSB4T25seVB1YmxpY0tleSAtIHR3ZWFrZWQgYWdncmVnYXRlZCBrZXkgKHRhcE91dHB1dEtleSlcbiAgICogQHBhcmFtIHNlc3Npb25JZCBBZGRpdGlvbmFsIGVudHJvcHkuIElmIHByb3ZpZGVkIGl0IG11c3QgZWl0aGVyIGJlIGEgY291bnRlciB1bmlxdWUgdG8gdGhpcyBzZWNyZXQga2V5LFxuICAgKiAoY29udmVydGVkIHRvIGFuIGFycmF5IG9mIDMyIGJ5dGVzKSwgb3IgMzIgdW5pZm9ybWx5IHJhbmRvbSBieXRlcy5cbiAgICovXG4gIGNyZWF0ZU11c2lnMk5vbmNlKFxuICAgIHByaXZhdGVLZXk6IFVpbnQ4QXJyYXksXG4gICAgcHVibGljS2V5OiBVaW50OEFycmF5LFxuICAgIHhPbmx5UHVibGljS2V5OiBVaW50OEFycmF5LFxuICAgIHR4SGFzaDogVWludDhBcnJheSxcbiAgICBzZXNzaW9uSWQ/OiBCdWZmZXJcbiAgKTogVWludDhBcnJheSB7XG4gICAgaWYgKHR4SGFzaC5sZW5ndGggIT0gMzIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB0eEhhc2ggc2l6ZSAke3R4SGFzaH1gKTtcbiAgICB9XG4gICAgY29uc3QgYnVmID0gbXVzaWcubm9uY2VHZW4oeyBzZWNyZXRLZXk6IHByaXZhdGVLZXksIHB1YmxpY0tleSwgeE9ubHlQdWJsaWNLZXksIG1zZzogdHhIYXNoLCBzZXNzaW9uSWQgfSk7XG4gICAgdGhpcy5ub25jZXMucHVzaChidWYpO1xuICAgIHJldHVybiBidWY7XG4gIH1cbn1cblxuLyoqXG4gKiBQc2J0IHByb3ByaWV0YXJ5IGtleSB2YWwgdXRpbCBmdW5jdGlvbiBmb3IgcGFydGljaXBhbnRzIHB1YiBrZXlzLiBTdWJUeXBlIGlzIDB4MDFcbiAqIFJlZjogaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vc2Fua2V0MTcyOS80YjUyNWM2MDQ5ZjRkOWUwMzRkMjczNjhjNDlmMjhhNlxuICogQHJldHVybiB4LW9ubHkgdGFwT3V0cHV0S2V5fHx0YXBJbnRlcm5hbEtleSBhcyBzdWIga2V5ZGF0YSwgcGxhaW4gc2lnaW5pbmcgcGFydGljaXBhbnQga2V5cyBhcyB2YWx1ZWRhdGFcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVuY29kZVBzYnRNdXNpZzJQYXJ0aWNpcGFudHMocGFydGljaXBhbnRzOiBQc2J0TXVzaWcyUGFydGljaXBhbnRzKTogUHJvcHJpZXRhcnlLZXlWYWx1ZSB7XG4gIGNvbnN0IGtleWRhdGEgPSBbcGFydGljaXBhbnRzLnRhcE91dHB1dEtleSwgcGFydGljaXBhbnRzLnRhcEludGVybmFsS2V5XS5tYXAoKHB1YmtleSkgPT4gY2hlY2tYT25seVB1YmxpY0tleShwdWJrZXkpKTtcbiAgY29uc3QgdmFsdWUgPSBwYXJ0aWNpcGFudHMucGFydGljaXBhbnRQdWJLZXlzLm1hcCgocHVia2V5KSA9PiBjaGVja1BsYWluUHVibGljS2V5KHB1YmtleSkpO1xuICBjb25zdCBrZXkgPSB7XG4gICAgaWRlbnRpZmllcjogUFNCVF9QUk9QUklFVEFSWV9JREVOVElGSUVSLFxuICAgIHN1YnR5cGU6IFByb3ByaWV0YXJ5S2V5U3VidHlwZS5NVVNJRzJfUEFSVElDSVBBTlRfUFVCX0tFWVMsXG4gICAga2V5ZGF0YTogQnVmZmVyLmNvbmNhdChrZXlkYXRhKSxcbiAgfTtcbiAgcmV0dXJuIHsga2V5LCB2YWx1ZTogQnVmZmVyLmNvbmNhdCh2YWx1ZSkgfTtcbn1cblxuLyoqXG4gKiBQc2J0IHByb3ByaWV0YXJ5IGtleSB2YWwgdXRpbCBmdW5jdGlvbiBmb3IgcHViIG5vbmNlLiBTdWJUeXBlIGlzIDB4MDJcbiAqIFJlZjogaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vc2Fua2V0MTcyOS80YjUyNWM2MDQ5ZjRkOWUwMzRkMjczNjhjNDlmMjhhNlxuICogQHJldHVybiBwbGFpbi1wYXJ0aWNpcGFudFB1YktleXx8eC1vbmx5LXRhcE91dHB1dEtleSBhcyBzdWIga2V5ZGF0YSwgNjYgYnl0ZXMgb2YgMiBwdWIgbm9uY2VzIGFzIHZhbHVlZGF0YVxuICovXG5leHBvcnQgZnVuY3Rpb24gZW5jb2RlUHNidE11c2lnMlB1Yk5vbmNlKG5vbmNlOiBQc2J0TXVzaWcyUHViTm9uY2UpOiBQcm9wcmlldGFyeUtleVZhbHVlIHtcbiAgaWYgKG5vbmNlLnB1Yk5vbmNlLmxlbmd0aCAhPT0gNjYpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcHViTm9uY2VzIGxlbmd0aCAke25vbmNlLnB1Yk5vbmNlLmxlbmd0aH1gKTtcbiAgfVxuICBjb25zdCBrZXlkYXRhID0gQnVmZmVyLmNvbmNhdChbXG4gICAgY2hlY2tQbGFpblB1YmxpY0tleShub25jZS5wYXJ0aWNpcGFudFB1YktleSksXG4gICAgY2hlY2tYT25seVB1YmxpY0tleShub25jZS50YXBPdXRwdXRLZXkpLFxuICBdKTtcbiAgY29uc3Qga2V5ID0ge1xuICAgIGlkZW50aWZpZXI6IFBTQlRfUFJPUFJJRVRBUllfSURFTlRJRklFUixcbiAgICBzdWJ0eXBlOiBQcm9wcmlldGFyeUtleVN1YnR5cGUuTVVTSUcyX1BVQl9OT05DRSxcbiAgICBrZXlkYXRhLFxuICB9O1xuICByZXR1cm4geyBrZXksIHZhbHVlOiBub25jZS5wdWJOb25jZSB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZW5jb2RlUHNidE11c2lnMlBhcnRpYWxTaWcocGFydGlhbFNpZzogUHNidE11c2lnMlBhcnRpYWxTaWcpOiBQcm9wcmlldGFyeUtleVZhbHVlIHtcbiAgaWYgKHBhcnRpYWxTaWcucGFydGlhbFNpZy5sZW5ndGggIT09IDMyICYmIHBhcnRpYWxTaWcucGFydGlhbFNpZy5sZW5ndGggIT09IDMzKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhcnRpYWxTaWcgbGVuZ3RoICR7cGFydGlhbFNpZy5wYXJ0aWFsU2lnLmxlbmd0aH1gKTtcbiAgfVxuICBjb25zdCBrZXlkYXRhID0gQnVmZmVyLmNvbmNhdChbXG4gICAgY2hlY2tQbGFpblB1YmxpY0tleShwYXJ0aWFsU2lnLnBhcnRpY2lwYW50UHViS2V5KSxcbiAgICBjaGVja1hPbmx5UHVibGljS2V5KHBhcnRpYWxTaWcudGFwT3V0cHV0S2V5KSxcbiAgXSk7XG4gIGNvbnN0IGtleSA9IHtcbiAgICBpZGVudGlmaWVyOiBQU0JUX1BST1BSSUVUQVJZX0lERU5USUZJRVIsXG4gICAgc3VidHlwZTogUHJvcHJpZXRhcnlLZXlTdWJ0eXBlLk1VU0lHMl9QQVJUSUFMX1NJRyxcbiAgICBrZXlkYXRhLFxuICB9O1xuICByZXR1cm4geyBrZXksIHZhbHVlOiBwYXJ0aWFsU2lnLnBhcnRpYWxTaWcgfTtcbn1cblxuLyoqXG4gKiBEZWNvZGVzIHByb3ByaWV0YXJ5IGtleSB2YWx1ZSBkYXRhIGZvciBwYXJ0aWNpcGFudCBwdWIga2V5c1xuICogQHBhcmFtIGt2XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVQc2J0TXVzaWcyUGFydGljaXBhbnRzKGt2OiBQcm9wcmlldGFyeUtleVZhbHVlKTogUHNidE11c2lnMlBhcnRpY2lwYW50cyB7XG4gIGlmIChcbiAgICBrdi5rZXkuaWRlbnRpZmllciAhPT0gUFNCVF9QUk9QUklFVEFSWV9JREVOVElGSUVSIHx8XG4gICAga3Yua2V5LnN1YnR5cGUgIT09IFByb3ByaWV0YXJ5S2V5U3VidHlwZS5NVVNJRzJfUEFSVElDSVBBTlRfUFVCX0tFWVNcbiAgKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGlkZW50aWZpZXIgJHtrdi5rZXkuaWRlbnRpZmllcn0gb3Igc3VidHlwZSAke2t2LmtleS5zdWJ0eXBlfSBmb3IgcGFydGljaXBhbnRzIHB1YiBrZXlzYCk7XG4gIH1cblxuICBjb25zdCBrZXkgPSBrdi5rZXkua2V5ZGF0YTtcbiAgaWYgKGtleS5sZW5ndGggIT09IDY0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGtleWRhdGEgc2l6ZSAke2tleS5sZW5ndGh9IGZvciBwYXJ0aWNpcGFudCBwdWIga2V5c2ApO1xuICB9XG5cbiAgY29uc3QgdmFsdWUgPSBrdi52YWx1ZTtcbiAgaWYgKHZhbHVlLmxlbmd0aCAhPT0gNjYpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdmFsdWVkYXRhIHNpemUgJHt2YWx1ZS5sZW5ndGh9IGZvciBwYXJ0aWNpcGFudCBwdWIga2V5c2ApO1xuICB9XG4gIGNvbnN0IHBhcnRpY2lwYW50UHViS2V5czogVHVwbGU8QnVmZmVyPiA9IFt2YWx1ZS5zdWJhcnJheSgwLCAzMyksIHZhbHVlLnN1YmFycmF5KDMzKV07XG4gIGlmIChwYXJ0aWNpcGFudFB1YktleXNbMF0uZXF1YWxzKHBhcnRpY2lwYW50UHViS2V5c1sxXSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYER1cGxpY2F0ZSBwYXJ0aWNpcGFudCBwdWIga2V5cyBmb3VuZGApO1xuICB9XG5cbiAgcmV0dXJuIHsgdGFwT3V0cHV0S2V5OiBrZXkuc3ViYXJyYXkoMCwgMzIpLCB0YXBJbnRlcm5hbEtleToga2V5LnN1YmFycmF5KDMyKSwgcGFydGljaXBhbnRQdWJLZXlzIH07XG59XG5cbi8qKlxuICogRGVjb2RlcyBwcm9wcmlldGFyeSBrZXkgdmFsdWUgZGF0YSBmb3IgbXVzaWcyIG5vbmNlXG4gKiBAcGFyYW0ga3ZcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZVBzYnRNdXNpZzJOb25jZShrdjogUHJvcHJpZXRhcnlLZXlWYWx1ZSk6IFBzYnRNdXNpZzJQdWJOb25jZSB7XG4gIGlmIChrdi5rZXkuaWRlbnRpZmllciAhPT0gUFNCVF9QUk9QUklFVEFSWV9JREVOVElGSUVSIHx8IGt2LmtleS5zdWJ0eXBlICE9PSBQcm9wcmlldGFyeUtleVN1YnR5cGUuTVVTSUcyX1BVQl9OT05DRSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBpZGVudGlmaWVyICR7a3Yua2V5LmlkZW50aWZpZXJ9IG9yIHN1YnR5cGUgJHtrdi5rZXkuc3VidHlwZX0gZm9yIG5vbmNlYCk7XG4gIH1cblxuICBjb25zdCBrZXkgPSBrdi5rZXkua2V5ZGF0YTtcbiAgaWYgKGtleS5sZW5ndGggIT09IDY1KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGtleWRhdGEgc2l6ZSAke2tleS5sZW5ndGh9IGZvciBub25jZWApO1xuICB9XG5cbiAgY29uc3QgdmFsdWUgPSBrdi52YWx1ZTtcbiAgaWYgKHZhbHVlLmxlbmd0aCAhPT0gNjYpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgdmFsdWVkYXRhIHNpemUgJHt2YWx1ZS5sZW5ndGh9IGZvciBub25jZWApO1xuICB9XG5cbiAgcmV0dXJuIHsgcGFydGljaXBhbnRQdWJLZXk6IGtleS5zdWJhcnJheSgwLCAzMyksIHRhcE91dHB1dEtleToga2V5LnN1YmFycmF5KDMzKSwgcHViTm9uY2U6IHZhbHVlIH07XG59XG5cbi8qKlxuICogRGVjb2RlcyBwcm9wcmlldGFyeSBrZXkgdmFsdWUgZGF0YSBmb3IgbXVzaWcyIHBhcnRpYWwgc2lnXG4gKiBAcGFyYW0ga3ZcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZVBzYnRNdXNpZzJQYXJ0aWFsU2lnKGt2OiBQcm9wcmlldGFyeUtleVZhbHVlKTogUHNidE11c2lnMlBhcnRpYWxTaWcge1xuICBpZiAoXG4gICAga3Yua2V5LmlkZW50aWZpZXIgIT09IFBTQlRfUFJPUFJJRVRBUllfSURFTlRJRklFUiB8fFxuICAgIGt2LmtleS5zdWJ0eXBlICE9PSBQcm9wcmlldGFyeUtleVN1YnR5cGUuTVVTSUcyX1BBUlRJQUxfU0lHXG4gICkge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBpZGVudGlmaWVyICR7a3Yua2V5LmlkZW50aWZpZXJ9IG9yIHN1YnR5cGUgJHtrdi5rZXkuc3VidHlwZX0gZm9yIHBhcnRpYWwgc2lnYCk7XG4gIH1cblxuICBjb25zdCBrZXkgPSBrdi5rZXkua2V5ZGF0YTtcbiAgaWYgKGtleS5sZW5ndGggIT09IDY1KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGtleWRhdGEgc2l6ZSAke2tleS5sZW5ndGh9IGZvciBwYXJ0aWFsIHNpZ2ApO1xuICB9XG5cbiAgY29uc3QgdmFsdWUgPSBrdi52YWx1ZTtcbiAgaWYgKHZhbHVlLmxlbmd0aCAhPT0gMzIgJiYgdmFsdWUubGVuZ3RoICE9PSAzMykge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2YWx1ZWRhdGEgc2l6ZSAke3ZhbHVlLmxlbmd0aH0gZm9yIHBhcnRpYWwgc2lnYCk7XG4gIH1cblxuICByZXR1cm4geyBwYXJ0aWNpcGFudFB1YktleToga2V5LnN1YmFycmF5KDAsIDMzKSwgdGFwT3V0cHV0S2V5OiBrZXkuc3ViYXJyYXkoMzMpLCBwYXJ0aWFsU2lnOiB2YWx1ZSB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlVGFwSW50ZXJuYWxLZXkocGxhaW5QdWJLZXlzOiBCdWZmZXJbXSk6IEJ1ZmZlciB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShtdXNpZy5nZXRYT25seVB1YmtleShtdXNpZy5rZXlBZ2cocGxhaW5QdWJLZXlzKSkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlVGFwT3V0cHV0S2V5KGludGVybmFsUHViS2V5OiBCdWZmZXIsIHRhcFRyZWVSb290OiBCdWZmZXIpOiBCdWZmZXIge1xuICByZXR1cm4gQnVmZmVyLmZyb20oXG4gICAgdGFwVHdlYWtQdWJrZXkoZWNjLCB0b1hPbmx5UHVibGljS2V5KGludGVybmFsUHViS2V5KSwgY2hlY2tUYXBNZXJrbGVSb290KHRhcFRyZWVSb290KSkueE9ubHlQdWJrZXlcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUFnZ3JlZ2F0ZU5vbmNlKHB1Yk5vbmNlczogVHVwbGU8QnVmZmVyPik6IEJ1ZmZlciB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShtdXNpZy5ub25jZUFnZyhwdWJOb25jZXMpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVRhcFR3ZWFrKHRhcEludGVybmFsS2V5OiBCdWZmZXIsIHRhcE1lcmtsZVJvb3Q6IEJ1ZmZlcik6IEJ1ZmZlciB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShjYWxjdWxhdGVUYXBUd2VhayhjaGVja1hPbmx5UHVibGljS2V5KHRhcEludGVybmFsS2V5KSwgY2hlY2tUYXBNZXJrbGVSb290KHRhcE1lcmtsZVJvb3QpKSk7XG59XG5cbmZ1bmN0aW9uIHN0YXJ0TXVzaWcyU2lnbmluZ1Nlc3Npb24oXG4gIGFnZ05vbmNlOiBCdWZmZXIsXG4gIGhhc2g6IEJ1ZmZlcixcbiAgcHVibGljS2V5czogVHVwbGU8QnVmZmVyPixcbiAgdHdlYWs6IEJ1ZmZlclxuKTogU2Vzc2lvbktleSB7XG4gIHJldHVybiBtdXNpZy5zdGFydFNpZ25pbmdTZXNzaW9uKGFnZ05vbmNlLCBoYXNoLCBwdWJsaWNLZXlzLCB7IHR3ZWFrLCB4T25seTogdHJ1ZSB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG11c2lnMlBhcnRpYWxTaWduKFxuICBwcml2YXRlS2V5OiBCdWZmZXIsXG4gIHB1YmxpY05vbmNlOiBVaW50OEFycmF5LFxuICBzZXNzaW9uS2V5OiBTZXNzaW9uS2V5LFxuICBub25jZVN0b3JlOiBNdXNpZzJOb25jZVN0b3JlXG4pOiBCdWZmZXIge1xuICBjaGVja1R4SGFzaChCdWZmZXIuZnJvbShzZXNzaW9uS2V5Lm1zZykpO1xuICByZXR1cm4gQnVmZmVyLmZyb20oXG4gICAgbXVzaWcucGFydGlhbFNpZ24oe1xuICAgICAgc2VjcmV0S2V5OiBwcml2YXRlS2V5LFxuICAgICAgcHVibGljTm9uY2U6IG5vbmNlU3RvcmUuZ2V0UmVmKHB1YmxpY05vbmNlKSxcbiAgICAgIHNlc3Npb25LZXksXG4gICAgfSlcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG11c2lnMlBhcnRpYWxTaWdWZXJpZnkoXG4gIHNpZzogQnVmZmVyLFxuICBwdWJsaWNLZXk6IEJ1ZmZlcixcbiAgcHVibGljTm9uY2U6IEJ1ZmZlcixcbiAgc2Vzc2lvbktleTogU2Vzc2lvbktleVxuKTogYm9vbGVhbiB7XG4gIGNoZWNrVHhIYXNoKEJ1ZmZlci5mcm9tKHNlc3Npb25LZXkubXNnKSk7XG4gIHJldHVybiBtdXNpZy5wYXJ0aWFsVmVyaWZ5KHsgc2lnLCBwdWJsaWNLZXksIHB1YmxpY05vbmNlLCBzZXNzaW9uS2V5IH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbXVzaWcyQWdncmVnYXRlU2lncyhzaWdzOiBCdWZmZXJbXSwgc2Vzc2lvbktleTogU2Vzc2lvbktleSk6IEJ1ZmZlciB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShtdXNpZy5zaWduQWdnKHNpZ3MsIHNlc3Npb25LZXkpKTtcbn1cblxuLyoqIEByZXR1cm4gc2Vzc2lvbiBrZXkgdGhhdCBjYW4gYmUgdXNlZCB0byByZWZlcmVuY2UgdGhlIHNlc3Npb24gbGF0ZXIgKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNdXNpZzJTaWduaW5nU2Vzc2lvbihzZXNzaW9uQXJnczoge1xuICBwdWJOb25jZXM6IFR1cGxlPEJ1ZmZlcj47XG4gIHR4SGFzaDogQnVmZmVyO1xuICBwdWJLZXlzOiBUdXBsZTxCdWZmZXI+O1xuICBpbnRlcm5hbFB1YktleTogQnVmZmVyO1xuICB0YXBUcmVlUm9vdDogQnVmZmVyO1xufSk6IFNlc3Npb25LZXkge1xuICBjaGVja1R4SGFzaChzZXNzaW9uQXJncy50eEhhc2gpO1xuICBjb25zdCBhZ2dOb25jZSA9IGNyZWF0ZUFnZ3JlZ2F0ZU5vbmNlKHNlc3Npb25BcmdzLnB1Yk5vbmNlcyk7XG4gIGNvbnN0IHR3ZWFrID0gY3JlYXRlVGFwVHdlYWsoc2Vzc2lvbkFyZ3MuaW50ZXJuYWxQdWJLZXksIHNlc3Npb25BcmdzLnRhcFRyZWVSb290KTtcbiAgcmV0dXJuIHN0YXJ0TXVzaWcyU2lnbmluZ1Nlc3Npb24oYWdnTm9uY2UsIHNlc3Npb25BcmdzLnR4SGFzaCwgc2Vzc2lvbkFyZ3MucHViS2V5cywgdHdlYWspO1xufVxuXG4vKipcbiAqIEByZXR1cm5zIHBzYnQgcHJvcHJpZXRhcnkga2V5IGZvciBtdXNpZzIgcGFydGljaXBhbnQga2V5IHZhbHVlIGRhdGFcbiAqIElmIG5vIGtleSB2YWx1ZSBleGlzdHMsIHVuZGVmaW5lZCBpcyByZXR1cm5lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUHNidE11c2lnMlBhcnRpY2lwYW50cyhpbnB1dDogUHNidElucHV0KTogUHNidE11c2lnMlBhcnRpY2lwYW50cyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhcnRpY2lwYW50c0tleVZhbHMgPSBnZXRQc2J0SW5wdXRQcm9wcmlldGFyeUtleVZhbHMoaW5wdXQsIHtcbiAgICBpZGVudGlmaWVyOiBQU0JUX1BST1BSSUVUQVJZX0lERU5USUZJRVIsXG4gICAgc3VidHlwZTogUHJvcHJpZXRhcnlLZXlTdWJ0eXBlLk1VU0lHMl9QQVJUSUNJUEFOVF9QVUJfS0VZUyxcbiAgfSk7XG5cbiAgaWYgKCFwYXJ0aWNpcGFudHNLZXlWYWxzLmxlbmd0aCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBpZiAocGFydGljaXBhbnRzS2V5VmFscy5sZW5ndGggPiAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBGb3VuZCAke3BhcnRpY2lwYW50c0tleVZhbHMubGVuZ3RofSBtYXRjaGluZyBwYXJ0aWNpcGFudCBrZXkgdmFsdWUgaW5zdGVhZCBvZiAxYCk7XG4gIH1cblxuICByZXR1cm4gZGVjb2RlUHNidE11c2lnMlBhcnRpY2lwYW50cyhwYXJ0aWNpcGFudHNLZXlWYWxzWzBdKTtcbn1cblxuLyoqXG4gKiBAcmV0dXJucyBwc2J0IHByb3ByaWV0YXJ5IGtleSBmb3IgbXVzaWcyIHB1YmxpYyBub25jZSBrZXkgdmFsdWUgZGF0YVxuICogSWYgbm8ga2V5IHZhbHVlIGV4aXN0cywgdW5kZWZpbmVkIGlzIHJldHVybmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VQc2J0TXVzaWcyTm9uY2VzKGlucHV0OiBQc2J0SW5wdXQpOiBQc2J0TXVzaWcyUHViTm9uY2VbXSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG5vbmNlS2V5VmFscyA9IGdldFBzYnRJbnB1dFByb3ByaWV0YXJ5S2V5VmFscyhpbnB1dCwge1xuICAgIGlkZW50aWZpZXI6IFBTQlRfUFJPUFJJRVRBUllfSURFTlRJRklFUixcbiAgICBzdWJ0eXBlOiBQcm9wcmlldGFyeUtleVN1YnR5cGUuTVVTSUcyX1BVQl9OT05DRSxcbiAgfSk7XG5cbiAgaWYgKCFub25jZUtleVZhbHMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmIChub25jZUtleVZhbHMubGVuZ3RoID4gMikge1xuICAgIHRocm93IG5ldyBFcnJvcihgRm91bmQgJHtub25jZUtleVZhbHMubGVuZ3RofSBtYXRjaGluZyBub25jZSBrZXkgdmFsdWUgaW5zdGVhZCBvZiAxIG9yIDJgKTtcbiAgfVxuXG4gIHJldHVybiBub25jZUtleVZhbHMubWFwKChrdikgPT4gZGVjb2RlUHNidE11c2lnMk5vbmNlKGt2KSk7XG59XG5cbi8qKlxuICogQHJldHVybnMgcHNidCBwcm9wcmlldGFyeSBrZXkgZm9yIG11c2lnMiBwYXJ0aWFsIHNpZyBrZXkgdmFsdWUgZGF0YVxuICogSWYgbm8ga2V5IHZhbHVlIGV4aXN0cywgdW5kZWZpbmVkIGlzIHJldHVybmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VQc2J0TXVzaWcyUGFydGlhbFNpZ3MoaW5wdXQ6IFBzYnRJbnB1dCk6IFBzYnRNdXNpZzJQYXJ0aWFsU2lnW10gfCB1bmRlZmluZWQge1xuICBjb25zdCBzaWdLZXlWYWxzID0gZ2V0UHNidElucHV0UHJvcHJpZXRhcnlLZXlWYWxzKGlucHV0LCB7XG4gICAgaWRlbnRpZmllcjogUFNCVF9QUk9QUklFVEFSWV9JREVOVElGSUVSLFxuICAgIHN1YnR5cGU6IFByb3ByaWV0YXJ5S2V5U3VidHlwZS5NVVNJRzJfUEFSVElBTF9TSUcsXG4gIH0pO1xuXG4gIGlmICghc2lnS2V5VmFscy5sZW5ndGgpIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgaWYgKHNpZ0tleVZhbHMubGVuZ3RoID4gMikge1xuICAgIHRocm93IG5ldyBFcnJvcihgRm91bmQgJHtzaWdLZXlWYWxzLmxlbmd0aH0gbWF0Y2hpbmcgcGFydGlhbCBzaWduYXR1cmUga2V5IHZhbHVlIGluc3RlYWQgb2YgMSBvciAyYCk7XG4gIH1cblxuICByZXR1cm4gc2lnS2V5VmFscy5tYXAoKGt2KSA9PiBkZWNvZGVQc2J0TXVzaWcyUGFydGlhbFNpZyhrdikpO1xufVxuXG4vKipcbiAqIEFzc2VydCBtdXNpZzIgcGFydGljaXBhbnQga2V5IHZhbHVlIGRhdGEgd2l0aCB0YXBJbnRlcm5hbEtleSBhbmQgdGFwTWVya2xlUm9vdC5cbiAqIDx0YXBPdXRwdXRLZXk+PHRhcElucHV0S2V5PiA9PiA8cGFydGljaXBhbnRLZXkxPjxwYXJ0aWNpcGFudEtleTI+XG4gKiBVc2luZyB0YXBNZXJrbGVSb290IGFuZCAyIHBhcnRpY2lwYW50IGtleXMsIHRoZSB0YXBJbnB1dEtleSBpcyB2YWxpZGF0ZWQgYW5kIHVzaW5nIHRhcE1lcmtsZVJvb3QgYW5kIHRhcElucHV0S2V5LFxuICogdGhlIHRhcE91dHB1dEtleSBpcyB2YWxpZGF0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc3NlcnRQc2J0TXVzaWcyUGFydGljaXBhbnRzKFxuICBwYXJ0aWNpcGFudEtleVZhbERhdGE6IFBzYnRNdXNpZzJQYXJ0aWNpcGFudHMsXG4gIHRhcEludGVybmFsS2V5OiBCdWZmZXIsXG4gIHRhcE1lcmtsZVJvb3Q6IEJ1ZmZlclxuKTogdm9pZCB7XG4gIGNoZWNrWE9ubHlQdWJsaWNLZXkodGFwSW50ZXJuYWxLZXkpO1xuICBjaGVja1RhcE1lcmtsZVJvb3QodGFwTWVya2xlUm9vdCk7XG5