UNPKG

@radixdlt/hardware-ledger

Version:
162 lines 5.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RadixAPDU = void 0; const crypto_1 = require("@radixdlt/crypto"); const _types_1 = require("./_types"); // ##### Follows https://github.com/radixdlt/radixdlt-ledger-app/blob/main/APDUSPEC.md ##### const hdPathComponentsToBuffer = (hdPath) => { if (hdPath.coinType.value() !== crypto_1.RADIX_COIN_TYPE || !hdPath.coinType.isHardened) { throw new Error(`Expected coinType to be ${crypto_1.RADIX_COIN_TYPE}'`); } const bytesPerComponent = 4; const data = Buffer.alloc(bytesPerComponent * hdPath.pathComponents.length); const write = (pathComponent, offset) => { data.writeUInt32BE(pathComponent.index, offset); }; hdPath.pathComponents.forEach((component, index) => { write(component, index * bytesPerComponent); }); return data; }; const hdPathToBuffer = (hdPath) => { const bipPathsData = hdPathComponentsToBuffer(hdPath); const bipPathsLength = hdPath.pathComponents.length; const bipPathsLengthAsSingleByte = Buffer.alloc(1); bipPathsLengthAsSingleByte.writeUInt8(bipPathsLength); return Buffer.concat([bipPathsLengthAsSingleByte, bipPathsData]); }; const makeAPDU = (input) => { var _a, _b, _c; return ({ cla: _types_1.radixCLA, ins: input.ins, p1: (_a = input.p1) !== null && _a !== void 0 ? _a : 0, p2: (_b = input.p2) !== null && _b !== void 0 ? _b : 0, data: input.data, requiredResponseStatusCodeFromDevice: (_c = input.requiredResponseStatusCodeFromDevice) !== null && _c !== void 0 ? _c : [ _types_1.LedgerResponseCodes.SW_OK, ], }); }; const getVersion = () => makeAPDU({ ins: _types_1.LedgerInstruction.GET_VERSION, }); const parameterValueForDisplayAddressOnLedger = (input) => (input.display ? 0x01 : 0x00); const getPublicKey = (input) => { const p1 = parameterValueForDisplayAddressOnLedger(input); let p2 = 0; if (input.verifyAddressOnly !== undefined) { p2 = input.verifyAddressOnly ? 0x01 : 0x00; } const data = hdPathToBuffer(input.path); return makeAPDU({ ins: _types_1.LedgerInstruction.GET_PUBLIC_KEY, p1, p2, data, }); }; const doKeyExchange = (path, publicKeyOfOtherParty, display) => { const p1 = display === 'encrypt' ? 0x01 : display === 'decrypt' ? 0x02 : 0x00; const publicKeyUncompressedData = publicKeyOfOtherParty.asData({ compressed: false, }); const publicKeyLengthBuf = Buffer.alloc(1); publicKeyLengthBuf.writeUInt8(publicKeyUncompressedData.length); const publicKeyData = Buffer.concat([ publicKeyLengthBuf, publicKeyUncompressedData, ]); const pathData = hdPathToBuffer(path); const data = Buffer.concat([pathData, publicKeyData]); return makeAPDU({ ins: _types_1.LedgerInstruction.DO_KEY_EXCHANGE, p1, data, }); }; const doSignHash = (input) => { const pathData = hdPathToBuffer(input.path); const hashLenBuf = Buffer.alloc(1); const hashedMessageByteCount = input.hashToSign.length; hashLenBuf.writeUInt8(hashedMessageByteCount); const hashData = Buffer.concat([hashLenBuf, input.hashToSign]); const data = Buffer.concat([pathData, hashData]); return makeAPDU({ ins: _types_1.LedgerInstruction.DO_SIGN_HASH, data, }); }; var SignTxAPDUType; (function (SignTxAPDUType) { SignTxAPDUType[SignTxAPDUType["SINGLE_RADIX_ENGINE_INSTRUCTION_APDU"] = 73] = "SINGLE_RADIX_ENGINE_INSTRUCTION_APDU"; SignTxAPDUType[SignTxAPDUType["FIRST_METADATA_APDU"] = 77] = "FIRST_METADATA_APDU"; })(SignTxAPDUType || (SignTxAPDUType = {})); const signTxInitialSetupPackage = (input) => { const p1 = SignTxAPDUType.FIRST_METADATA_APDU.valueOf(); const pathData = hdPathToBuffer(input.path); const sizeOfTXAsData = Buffer.alloc(4); sizeOfTXAsData.writeUInt32BE(input.txByteCount); const instructionCountAsData = Buffer.alloc(2); instructionCountAsData.writeUInt16BE(input.numberOfInstructions); const hrpLen = input.nonNativeTokenRriHRP === undefined ? 0 : input.nonNativeTokenRriHRP.length; if (hrpLen > 255) { throw new Error(`Non native token HRP must not longer than 255.`); } const nonNativeTokenHrpLengthAsData = Buffer.alloc(1); nonNativeTokenHrpLengthAsData.writeUInt8(hrpLen); const nonNativeTokenHrpData = input.nonNativeTokenRriHRP === undefined ? Buffer.alloc(0) : Buffer.from(input.nonNativeTokenRriHRP, 'utf8'); const hrpData = Buffer.concat([ nonNativeTokenHrpLengthAsData, nonNativeTokenHrpData, ]); const data = Buffer.concat([ pathData, sizeOfTXAsData, instructionCountAsData, hrpData, ]); return makeAPDU({ ins: _types_1.LedgerInstruction.DO_SIGN_TX, p1, data, }); }; const signTxSingleInstruction = (input) => { const p1 = SignTxAPDUType.SINGLE_RADIX_ENGINE_INSTRUCTION_APDU.valueOf(); let p2 = 0b00000000; if (input.displayInstructionContentsOnLedgerDevice) { const bitMask_displayInstructionContentsOnLedgerDevice = 0b1 << 0; p2 = p2 ^ bitMask_displayInstructionContentsOnLedgerDevice; } if (input.displayTXSummaryOnLedgerDevice) { const bitMask_displayTXSummaryOnLedgerDevice = 0b1 << 1; p2 = p2 ^ bitMask_displayTXSummaryOnLedgerDevice; } return makeAPDU({ ins: _types_1.LedgerInstruction.DO_SIGN_TX, p1, p2, data: input.instructionBytes, }); }; const getAppName = () => makeAPDU({ ins: _types_1.LedgerInstruction.GET_APP_NAME, }); exports.RadixAPDU = { getAppName, getVersion, getPublicKey, doKeyExchange, doSignHash, signTX: { initialSetup: signTxInitialSetupPackage, singleInstruction: signTxSingleInstruction, }, }; //# sourceMappingURL=apdu.js.map