UNPKG

@secux/utility

Version:

SecuX Hardware Wallet internal tools for SDK

18 lines (15 loc) 4.99 kB
"use strict"; /*! Copyright 2022 SecuX Technology Inc Copyright Chen Wei-En Copyright Wu Tsung-Yu Licensed under the Apache License, Version 2.0 (the License); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */Object.defineProperty(exports,"__esModule",{value:!0}),exports.deriveKey=exports.decodeXPUB=exports.convertXpubMagic=exports.toExtenededPublicKey=void 0;const BIP32Path_1=require("./BIP32Path"),bs58_1=require("./bs58"),hash_js_1=require("hash.js"),elliptic_1=require("elliptic"),ow_1=require("ow"),utility_1=require("./utility"),groestl=require("groestl-hash-js"),logger=null===utility_1.Logger||void 0===utility_1.Logger?void 0:utility_1.Logger.child({id:"utility"}),secp256k1=new elliptic_1.ec("secp256k1"),BN=secp256k1.curve.n.constructor;exports.toExtenededPublicKey=function(path,parentFingerPrint,chainCode,publicKey){var _a;(0,ow_1.default)(path,utility_1.owTool.bip32String),(0,ow_1.default)(parentFingerPrint,(0,utility_1.ow_checkBufferLength)(4)),(0,ow_1.default)(chainCode,(0,utility_1.ow_checkBufferLength)(32)),(0,ow_1.default)(publicKey,(0,utility_1.ow_checkBufferLength)(33));const buffer=Buffer.allocUnsafe(78),bip44=(0,BIP32Path_1.splitPath)(path);switch(bip44.purpose.value){case 44:case 86:buffer.writeUInt32BE(76067358,0);break;case 49:buffer.writeUInt32BE(77429938,0);break;case 84:buffer.writeUInt32BE(78792518,0);break;default:throw Error("unsupported purpose of path")}const depth=bip44.pathNum;let element;switch(buffer.writeUInt8(depth,4),(depth>0?parentFingerPrint:Buffer.alloc(4)).copy(buffer,5),depth){case 1:element=bip44.purpose;break;case 2:element=bip44.coinType;break;case 3:element=bip44.accountId;break;case 4:element=bip44.change;break;case 5:element=bip44.addressIndex;break;default:throw Error("Invalid Path, only support 1 to 5 depth path")}const index=element.isHardened?element.value+BIP32Path_1.HARDENED_OFFSET:null==element?void 0:element.value;return buffer.writeUInt32BE(index,9),chainCode.copy(buffer,13),publicKey.copy(buffer,45),17===(null===(_a=bip44.coinType)||void 0===_a?void 0:_a.value)?bs58_GRS.encode(buffer):bs58_BTC.encode(buffer)},exports.convertXpubMagic=function(xpub,magic){let result="";try{const payload=bs58_BTC.decode(xpub);payload.writeUInt32BE(magic,0),result=bs58_BTC.encode(payload)}catch(error){null==logger||logger.warn(`The xpub is not Bitcoin compatible, try use Groestlcoin version:\n${xpub}`);const payload=bs58_GRS.decode(xpub);payload.writeUInt32BE(magic,0),result=bs58_GRS.encode(payload)}return result},exports.decodeXPUB=function(xpub){let payload,purpose;(0,ow_1.default)(xpub,utility_1.owTool.xpubString);try{payload=bs58_BTC.decode(xpub)}catch(error){null==logger||logger.warn(`The xpub is not Bitcoin compatible, try use Groestlcoin version:\n${xpub}`),payload=bs58_GRS.decode(xpub)}switch(payload.readUInt32BE(0)){case 76067358:purpose=44,null==logger||logger.warn("Please note that TapRoot type xpub using the same prefix, it cannot be considered here.");break;case 77429938:purpose=49;break;case 78792518:purpose=84;break;default:throw Error(`unsupport prefix, got 0x${payload.slice(0,4)}`)}const depth=payload.readUInt8(4),fingerprint=payload.slice(5,9),chaincode=payload.slice(13,45);return{purpose,depth,publickey:payload.slice(45),chaincode,fingerprint}},exports.deriveKey=function(publickey,chaincode,indexArray){(0,ow_1.default)(publickey,(0,utility_1.ow_checkBufferLength)(33)),(0,ow_1.default)(chaincode,(0,utility_1.ow_checkBufferLength)(32)),(0,ow_1.default)(indexArray,ow_1.default.array.ofType(ow_1.default.number.uint32));let xpub={publickey,chaincode};for(const index of indexArray)xpub=derive(xpub.publickey,xpub.chaincode,index);return xpub};const bs58_BTC=new bs58_1.bs58Check((function(data){const sha=(0,hash_js_1.sha256)().update(data).digest();return Buffer.from((0,hash_js_1.sha256)().update(sha).digest())})),bs58_GRS=new bs58_1.bs58Check((function(data){return Buffer.from(groestl.groestl_2(data,1,1))}));function derive(publickey,chaincode,index){const data=Buffer.allocUnsafe(37);publickey.copy(data,0),data.writeUInt32BE(index,33);const hmacSha512=(0,hash_js_1.hmac)(hash_js_1.sha512,chaincode).update(data).digest(),I=Buffer.from(hmacSha512),IL=I.slice(0,32),IR=I.slice(32);let Ki;try{const pair=secp256k1.keyFromPublic(publickey),tweak=new BN(IL);if(tweak.cmp(secp256k1.curve.n)>=0)throw Error("tweak error");const point=pair.getPublic().add(secp256k1.curve.g.mul(tweak));if(point.isInfinity())throw Error("point error");Ki=Buffer.from(point.encode("array",!0))}catch(err){return derive(publickey,chaincode,index+1)}return{publickey:Ki,chaincode:IR}}