packageDocumentation module import elliptic from 'elliptic' ; import * as bytes from './bytes' ; import * as errors from './errors' ; import { keccak256 } from './keccak256' ; import { randomBytes } from './random' ; import { isPrivateKey , strip0x , isAddress , isBech32Address } from '@harmony-js/utils' ; import { fromBech32 } from './bech32' ; import { encode } from './rlp' ; const secp256k1 = elliptic . ec ( 'secp256k1' ) ; function description return { string } export const generatePrivateKey = ( ) : string => { const entropy = '0x' + randomBytes ( 16 ) ; const innerHex = keccak256 ( bytes . concat ( [ '0x' + randomBytes ( 32 ) , entropy || '0x' + randomBytes ( 32 ) ] ) ) ; const middleHex = bytes . concat ( [ bytes . concat ( [ '0x' + randomBytes ( 32 ) , innerHex ] ) , '0x' + randomBytes ( 32 ) , ] ) ; const outerHex = keccak256 ( middleHex ) ; return outerHex ; } ; function param { string } privateKey return { string } export const getPubkeyFromPrivateKey = ( privateKey ) : string => { return '0x' + getPublic ( privateKey , true ) ; } ; function param { string } privateKey return { string } export const getAddressFromPrivateKey = ( privateKey ) : string => { const publicHash = '0x' + getPublic ( privateKey ) . slice ( 2 ) ; const publicKey = keccak256 ( publicHash ) ; const address = '0x' + publicKey . slice ( - 40 ) ; return address ; } ; export const getPublic = ( privateKey , compress ? ) : string => { if ( ! isPrivateKey ( privateKey ) || ! validatePrivateKey ( privateKey ) ) { throw new Error ( `${ privateKey } is not PrivateKey` ) ; } const ecKey = secp256k1 . keyFromPrivate ( strip0x ( privateKey ) , 'hex' ) ; return ecKey . getPublic ( compress || false , 'hex' ) ; } ; function param { string } publicKey return { string } export const getAddressFromPublicKey = ( publicKey ) : string => { const ecKey = secp256k1 . keyFromPublic ( publicKey . slice ( 2 ) , 'hex' ) ; const publicHash = ecKey . getPublic ( false , 'hex' ) ; const address = '0x' + keccak256 ( '0x' + publicHash . slice ( 2 ) ) . slice ( - 40 ) ; return address ; } ; function param { string } address return { string } export const toChecksumAddress = ( address ) : string => { if ( typeof address === 'string' && isBech32Address ( address ) ) { address = fromBech32 ( address ) ; } if ( typeof address !== 'string' || ! address . match ( /^0x[0-9A-Fa-f]{40}$/ ) ) { errors . throwError ( 'invalid address' , errors . INVALID_ARGUMENT , { arg : 'address' , value : address , } ) ; } address = address . toLowerCase ( ) ; const chars = address . substring ( 2 ) . split ( '' ) ; let hashed = new Uint8Array ( 40 ) ; for ( let i = 0 ; i < 40 ; i ++ ) { hashed [ i ] = chars [ i ] . charCodeAt ( 0 ) ; } hashed = bytes . arrayify ( keccak256 ( hashed ) ) || hashed ; for ( let i = 0 ; i < 40 ; i += 2 ) { if ( hashed [ i >> 1 ] >> 4 >= 8 ) { chars [ i ] = chars [ i ] . toUpperCase ( ) ; } if ( ( hashed [ i >> 1 ] & 0x0f ) >= 8 ) { chars [ i + 1 ] = chars [ i + 1 ] . toUpperCase ( ) ; } } return '0x' + chars . join ( '' ) ; } ; export const sign = ( digest , privateKey ) : bytes . Signature => { if ( ! isPrivateKey ( privateKey ) ) { throw new Error ( `${ privateKey } is not PrivateKey` ) ; } const keyPair = secp256k1 . keyFromPrivate ( strip0x ( privateKey ) , 'hex' ) ; const signature = keyPair . sign ( bytes . arrayify ( digest ) , { canonical : true } ) ; const publicKey = '0x' + keyPair . getPublic ( true , 'hex' ) ; const result = { recoveryParam : signature . recoveryParam , r : bytes . hexZeroPad ( '0x' + signature . r . toString ( 16 ) , 32 ) , s : bytes . hexZeroPad ( '0x' + signature . s . toString ( 16 ) , 32 ) , v : 27 + signature . recoveryParam , } ; if ( verifySignature ( digest , result , publicKey ) ) { return result ; } else { throw new Error ( 'signing process failed' ) ; } } ; export function getContractAddress ( from , nonce ) { if ( ! from ) { throw new Error ( 'missing from address' ) ; } const addr = keccak256 ( encode ( [ from , bytes . stripZeros ( bytes . hexlify ( nonce ) ) ] ) ) ; return '0x' + addr . substring ( 26 ) ; } export function verifySignature ( digest , signature , publicKey ) { return recoverPublicKey ( digest , signature ) === publicKey ; } export function recoverPublicKey ( digest , signature ) { const sig = bytes . splitSignature ( signature ) ; const rs = { r : bytes . arrayify ( sig . r ) , s : bytes . arrayify ( sig . s ) } ; const recovered = secp256k1 . recoverPubKey ( bytes . arrayify ( digest ) , rs , sig . recoveryParam ) ; const key = recovered . encode ( 'hex' , false ) ; const ecKey = secp256k1 . keyFromPublic ( key , 'hex' ) ; const publicKey = '0x' + ecKey . getPublic ( true , 'hex' ) ; return publicKey ; } export function recoverAddress ( digest , signature ) { return getAddressFromPublicKey ( recoverPublicKey ( bytes . arrayify ( digest ) || new Uint8Array ( ) , signature ) ) ; } param { string } address returns { boolean } export const isValidChecksumAddress = ( address ) : boolean => { return isAddress ( address . replace ( '0x' , '' ) ) && toChecksumAddress ( address ) === address ; } ; export const validatePrivateKey = ( privateKey ) : boolean => { const ecKey = secp256k1 . keyFromPrivate ( strip0x ( privateKey ) , 'hex' ) ; const { result } = ecKey . validate ( ) ; return result ; } ;