import * as bip39 from 'bip39' ; import pbkdf2 from 'pbkdf2' ; import isEmpty from 'lodash/isEmpty' ; import { tx , wallet , general } from '../apdu' ; import Transport from '../transport' ; import { MSG } from '../config/status/msg' ; import { CODE } from '../config/status/code' ; import { PathType } from '../config/param' ; import { SDKError } from '../error/errorHandle' ; function hardenPath ( index ) { return ( Math . floor ( index ) + 0x80000000 ) . toString ( 16 ) ; } export const getFullPath = ( { pathType = PathType . BIP32 , pathString , } ) : string => { const paths = pathString . split ( '/' ) . map ( ( index ) => { if ( ! index . match ( /^\d+(|')$/ ) ) { throw new SDKError ( 'getFullPath' , `invalid pathString : ${ pathString }` ) ; } if ( index . endsWith ( "'" ) ) { return hardenPath ( parseInt ( index . slice ( 0 , - 1 ) , 10 ) ) ; } return parseInt ( index , 10 ) . toString ( 16 ) . padStart ( 8 , '0' ) ; } ) ; return pathType . toString ( ) . concat ( ... paths ) ; } ; export const getPath = async ( coinType , keyIndex , depth = 5 , pathType = PathType . BIP32 ) : Promise < string > => { let fullPath = pathType . toString ( ) ; if ( depth >= 1 ) { fullPath += '8000002C' ; } if ( depth >= 2 ) { fullPath += coinType ; } if ( depth >= 3 ) { fullPath += '80000000' ; } if ( pathType === PathType . SLIP0010 || pathType === PathType . BIP32ED25519 ) { return fullPath ; } if ( depth >= 4 ) { fullPath += '00000000' ; } if ( depth >= 5 ) { fullPath += ( keyIndex . toString ( 16 ) ) . padStart ( 8 , '0' ) ; } return fullPath ; } ; export const getReturnMsg = ( code ) : string => { const message = MSG [ `_${ code }` ] ? MSG [ `_${ code }` ] : 'unknown command error' ; return message ; } ; const getCheckSum = ( data ) => { let XORTemp = 0 ; for ( let i = 0 ; i < data . length ; i ++ ) { XORTemp ^= parseInt ( data [ i ] , 16 ) ; } let temp = XORTemp . toString ( 16 ) ; if ( temp . length % 2 !== 0 ) { temp = `0${ temp }` ; } return temp ; } ; export const assemblyCommandAndData = ( cla , ins , p1 , p2 , oriData ) => { const pid = '00' ; const cmdLen = '09' ; const packetLength = 18 ; let dataLength = 0 ; let packets = oriData ?? '' ; let dataBuf = Buffer . from ( packets , 'hex' ) ; const oriDataLength = dataBuf . length ; if ( ! isEmpty ( dataBuf ) ) { const data = packets . match ( /.{2}/g ) ; const checksum = getCheckSum ( data ) ; packets += checksum ; dataBuf = Buffer . concat ( [ dataBuf , Buffer . from ( checksum , 'hex' ) ] ) ; } const XORLength = dataBuf . length ; if ( dataBuf . length > 0 ) { const length = dataBuf . length / packetLength ; const remains = dataBuf . length % packetLength ; dataLength += length ; if ( remains !== 0 ) { dataLength += 1 ; } } const oriDataBuf = Buffer . allocUnsafe ( 4 ) ; oriDataBuf . fill ( 0 ) ; oriDataBuf . writeInt16BE ( oriDataLength , 0 ) ; const hexOriDataLength = oriDataBuf . slice ( 0 , 2 ) . toString ( 'hex' ) . padStart ( 4 , '0' ) ; const XORData = Buffer . allocUnsafe ( 4 ) ; XORData . fill ( 0 ) ; XORData . writeInt16BE ( XORLength , 0 ) ; const hexXORLength = XORData . slice ( 0 , 2 ) . toString ( 'hex' ) . padStart ( 4 , '0' ) ; const hexDataLength = Buffer . from ( [ dataLength ] ) . toString ( 'hex' ) ; const command = pid + cmdLen + cla + ins + p1 + p2 + hexOriDataLength + hexXORLength + hexDataLength ; return { command , data : packets } ; } ; export const checkSupportScripts = async ( transport ) => { const { statusCode } = await tx . getSignedHex ( transport ) ; if ( statusCode === CODE . _9000 ) { return true ; } else if ( statusCode === CODE . _6D00 ) { return false ; } else { throw new SDKError ( checkSupportScripts . name , 'checkSupportScripts error' ) ; } } ; export const createSeedByApp = async ( wordNumber , randomBytes ) : Promise < string > => { const strength = wordNumber * 11 - wordNumber / 3 ; return bip39 . generateMnemonic ( strength , randomBytes ) ; } ; export const createWalletByMnemonic = async ( transport , appId , appPrivateKey , mnemonic , SEPublicKey ) : Promise < void > => { const seeds = [ ] ; const version = await general . getSEVersion ( transport ) ; seeds [ 0 ] = await bip39 . mnemonicToSeed ( mnemonic ) ; if ( version >= 317 ) { const entropy = bip39 . mnemonicToEntropy ( mnemonic ) ; const key = pbkdf2 . pbkdf2Sync ( '' , Buffer . from ( entropy , 'hex' ) , 4096 , 96 , 'sha512' ) ; key [ 0 ] &= 0b11111000 ; key [ 31 ] &= 0b00011111 ; key [ 31 ] |= 0b01000000 ; seeds [ 1 ] = key ; } const seedHex = Buffer . concat ( seeds ) . toString ( 'hex' ) ; return wallet . setSeed ( transport , appId , appPrivateKey , seedHex , SEPublicKey ) ; } ; param { number } d returns { Promise < void > } export const delay = ( d ) : Promise < void > => new Promise ( ( r ) => setTimeout ( r , d ) ) ;