import { bech32 } from 'bech32' import crypto from 'crypto' import hexEncoding from 'crypto-js/enc-hex' import ripemd160 from 'crypto-js/ripemd160' import sha256 from 'crypto-js/sha256' /** * Convert string to bytes. * * @param {string} string * @returns {number[]} The bytes from the given string. */ export const getBytes = (string: string): number[] => { const arrayBytes: number[] = [] const buffer = Buffer.from(string, 'utf16le') for (let i = 0; i < buffer.length; i++) { arrayBytes.push(buffer[i]) } return arrayBytes } /** * Convert Buffer to hex string. * * @param {Buffer} arr * @returns {string} The hex string from the given buffer. */ export const ab2hexstring = (arr: Buffer) => { let result = '' for (let i = 0; i < arr.length; i++) { let str = arr[i].toString(16) str = str.length === 0 ? '00' : str.length === 1 ? '0' + str : str result += str } return result } /** * Calculate `ripemd160(sha256(hex))` from the hex string * * @param {string} hex The hex encoded string. * @returns {string} The hex string from the given buffer. * * @throws {"sha256ripemd160 expects a string"} Thrown if non-string is provided. * @throws {"invalid hex string length"} Thrown if the given hex string is an invalid one. */ export const sha256ripemd160 = (hex: string): string => { if (typeof hex !== 'string') throw new Error('sha256ripemd160 expects a string') if (hex.length % 2 !== 0) throw new Error(`invalid hex string length: ${hex}`) const hexEncoded = hexEncoding.parse(hex) const ProgramSha256 = sha256(hexEncoded) return ripemd160(ProgramSha256).toString() } /** * Encode address from the string or Buffer. * * @param {string|Buffer} value The string or Buffer to be encoded. * @param {string} prefix The prefix of the address. (optional) * @param {BufferEncoding} type The buffer encoding type. It will be used when string is provided. (optional) * @returns {string} The address generated from the given string or buffer. */ export const encodeAddress = (value: string | Buffer, prefix = 'dojima', type: BufferEncoding = 'hex'): string => { let words if (Buffer.isBuffer(value)) { words = bech32.toWords(Buffer.from(value)) } else { words = bech32.toWords(Buffer.from(value, type)) } return bech32.encode(prefix, words) } /** * Create address from the public key. * * @param {Buffer} publicKey The public key in Buffer format. * @returns {string} The address generated from the given public key(buffer format). */ export const createAddress = (publicKey: Buffer): string => { const hexed = ab2hexstring(publicKey) const hash = sha256ripemd160(hexed) const address = encodeAddress(hash, 'dojima') return address } /** * Calculate pbkdf2 (Password-Based Key Derivation Function 2). * * @param {string|Buffer|Array|DataView} passphrase. * @param {string|Buffer|Array|DataView} salt * @param {number} iterations * @param {number} keylen * @param {string} digest * @returns {Buffer} The pbkdf2 value from the given options. */ export const pbkdf2Async = async ( passphrase: string | Buffer | NodeJS.TypedArray | DataView, salt: string | Buffer | NodeJS.TypedArray | DataView, iterations: number, keylen: number, digest: string, ): Promise => { return new Promise((resolve, reject) => { crypto.pbkdf2(passphrase, salt, iterations, keylen, digest, (err, drived) => { if (err) { reject(err) } else { resolve(drived) } }) }) }