diff --git a/blue_modules/BlueElectrum.ts b/blue_modules/BlueElectrum.ts index adf69b38f69..25df3fb77f5 100644 --- a/blue_modules/BlueElectrum.ts +++ b/blue_modules/BlueElectrum.ts @@ -12,7 +12,7 @@ import { GROUP_IO_BLUEWALLET } from './currency'; import { ElectrumServerItem } from '../screen/settings/ElectrumSettings'; import { triggerWarningHapticFeedback } from './hapticFeedback'; import { AlertButton } from 'react-native'; -import { uint8ArrayToHex } from './uint8array-extras/index'; +import { uint8ArrayToHex, stringToUint8Array, hexToUint8Array } from './uint8array-extras/index'; const ElectrumClient = require('electrum-client'); const net = require('net'); @@ -108,16 +108,16 @@ let latestBlock: { height: number; time: number } | { height: undefined; time: u const txhashHeightCache: Record = {}; let _realm: Realm | undefined; -function bitcoinjs_crypto_sha256(buffer: Uint8Array): Buffer { - return Buffer.from(_sha256(buffer)); +function bitcoinjs_crypto_sha256(buffer: Uint8Array): Uint8Array { + return _sha256(buffer); } async function _getRealm() { if (_realm) return _realm; const cacheFolderPath = RNFS.CachesDirectoryPath; // Path to cache folder - const password = uint8ArrayToHex(bitcoinjs_crypto_sha256(Buffer.from('fyegjitkyf[eqjnc.lf'))); - const buf = Buffer.from(password + password, 'hex'); + const password = uint8ArrayToHex(bitcoinjs_crypto_sha256(stringToUint8Array('fyegjitkyf[eqjnc.lf'))); + const buf = hexToUint8Array(password + password); const encryptionKey = Int8Array.from(buf); const path = `${cacheFolderPath}/electrumcache.realm`; // Use cache folder path @@ -492,8 +492,8 @@ export const getBalanceByAddress = async function (address: string): Promise<{ c if (!mainClient) throw new Error('Electrum client is not connected'); const script = bitcoin.address.toOutputScript(address); const hash = bitcoinjs_crypto_sha256(script); - const reversedHash = Buffer.from(hash).reverse(); - const balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex')); + const reversedHash = new Uint8Array(hash).reverse(); + const balance = await mainClient.blockchainScripthash_getBalance(uint8ArrayToHex(reversedHash)); balance.addr = address; return balance; } catch (error) { @@ -520,8 +520,8 @@ export const getTransactionsByAddress = async function (address: string): Promis if (!mainClient) throw new Error('Electrum client is not connected'); const script = bitcoin.address.toOutputScript(address); const hash = bitcoinjs_crypto_sha256(script); - const reversedHash = Buffer.from(hash).reverse(); - const history = await mainClient.blockchainScripthash_getHistory(reversedHash.toString('hex')); + const reversedHash = new Uint8Array(hash).reverse(); + const history = await mainClient.blockchainScripthash_getHistory(uint8ArrayToHex(reversedHash)); for (const h of history || []) { if (h.tx_hash) txhashHeightCache[h.tx_hash] = h.height; // cache tx height } @@ -533,8 +533,8 @@ export const getMempoolTransactionsByAddress = async function (address: string): if (!mainClient) throw new Error('Electrum client is not connected'); const script = bitcoin.address.toOutputScript(address); const hash = bitcoinjs_crypto_sha256(script); - const reversedHash = Buffer.from(hash).reverse(); - return mainClient.blockchainScripthash_getMempool(reversedHash.toString('hex')); + const reversedHash = new Uint8Array(hash).reverse(); + return mainClient.blockchainScripthash_getMempool(uint8ArrayToHex(reversedHash)); }; export const ping = async function () { @@ -585,7 +585,7 @@ export function txhexToElectrumTransaction(txhex: string): ElectrumTransactionWi if (inn.witness[1]) txinwitness.push(uint8ArrayToHex(inn.witness[1])); ret.vin.push({ - txid: Buffer.from(inn.hash).reverse().toString('hex'), + txid: uint8ArrayToHex(new Uint8Array(inn.hash).reverse()), vout: inn.index, scriptSig: { hex: uint8ArrayToHex(inn.script), asm: '' }, txinwitness, @@ -719,7 +719,7 @@ export const multiGetBalanceByAddress = async (addresses: string[], batchsize: n for (const addr of chunk) { const script = bitcoin.address.toOutputScript(addr); const hash = bitcoinjs_crypto_sha256(script); - const reversedHash = Buffer.from(hash).reverse().toString('hex'); + const reversedHash = uint8ArrayToHex(new Uint8Array(hash).reverse()); scripthashes.push(reversedHash); scripthash2addr[reversedHash] = addr; } @@ -763,7 +763,7 @@ export const multiGetUtxoByAddress = async function (addresses: string[], batchs for (const addr of chunk) { const script = bitcoin.address.toOutputScript(addr); const hash = bitcoinjs_crypto_sha256(script); - const reversedHash = Buffer.from(hash).reverse().toString('hex'); + const reversedHash = uint8ArrayToHex(new Uint8Array(hash).reverse()); scripthashes.push(reversedHash); scripthash2addr[reversedHash] = addr; } @@ -813,7 +813,7 @@ export const multiGetHistoryByAddress = async function ( for (const addr of chunk) { const script = bitcoin.address.toOutputScript(addr); const hash = bitcoinjs_crypto_sha256(script); - const reversedHash = Buffer.from(hash).reverse().toString('hex'); + const reversedHash = uint8ArrayToHex(new Uint8Array(hash).reverse()); scripthashes.push(reversedHash); scripthash2addr[reversedHash] = addr; } diff --git a/blue_modules/base43.ts b/blue_modules/base43.ts index 1fe78ba08af..b450cb52ccc 100644 --- a/blue_modules/base43.ts +++ b/blue_modules/base43.ts @@ -1,4 +1,5 @@ import base from 'base-x'; +import { uint8ArrayToHex } from './uint8array-extras/index'; const Base43 = { encode: function () { @@ -8,7 +9,7 @@ const Base43 = { decode: function (input: string): string { const x = base('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:'); const uint8 = x.decode(input); - return Buffer.from(uint8).toString('hex'); + return uint8ArrayToHex(uint8); }, }; diff --git a/blue_modules/checksumWords.ts b/blue_modules/checksumWords.ts index 0452a7166dd..494c8cd883f 100644 --- a/blue_modules/checksumWords.ts +++ b/blue_modules/checksumWords.ts @@ -55,7 +55,7 @@ export function generateChecksumWords(stringSeedPhrase: string) { } } - const hash = Buffer.from(sha256(Buffer.from(entropy))); + const hash = sha256(new Uint8Array(entropy)); const hashBits = new Array(hash.length * 8); for (let iq = 0; iq < hash.length; ++iq) for (let jq = 0; jq < 8; ++jq) hashBits[iq * 8 + jq] = (hash[iq] & (1 << (7 - jq))) !== 0; // eslint-disable-line no-bitwise diff --git a/blue_modules/fs.ts b/blue_modules/fs.ts index e921fe10be2..5a291b8e657 100644 --- a/blue_modules/fs.ts +++ b/blue_modules/fs.ts @@ -2,12 +2,14 @@ import { Platform } from 'react-native'; import { pick, types, keepLocalCopy, errorCodes } from '@react-native-documents/picker'; import RNFS from 'react-native-fs'; import { launchImageLibrary, ImagePickerResponse } from 'react-native-image-picker'; +import RNQRGenerator from 'rn-qr-generator'; import Share from 'react-native-share'; + import presentAlert from '../components/Alert'; import loc from '../loc'; import { isDesktop } from './environment'; import { readFile } from './react-native-bw-file-access'; -import RNQRGenerator from 'rn-qr-generator'; +import { base64ToUint8Array, uint8ArrayToString } from './uint8array-extras/index'; const _sanitizeFileName = (fileName: string) => { // Remove any path delimiters and non-alphanumeric characters except for -, _, and . @@ -91,7 +93,7 @@ export const openSignedTransaction = async function (): Promise const _readPsbtFileIntoBase64 = async function (uri: string): Promise { const base64 = await RNFS.readFile(uri, 'base64'); - const stringData = Buffer.from(base64, 'base64').toString(); // decode from base64 + const stringData = uint8ArrayToString(base64ToUint8Array(base64)); // decode from base64 if (stringData.startsWith('psbt')) { // file was binary, but outer code expects base64 psbt, so we return base64 we got from rn-fs; // most likely produced by Electrum-desktop diff --git a/blue_modules/uint8array-extras/index.js b/blue_modules/uint8array-extras/index.js index bb4e0f92cd6..8d3e44ff7be 100644 --- a/blue_modules/uint8array-extras/index.js +++ b/blue_modules/uint8array-extras/index.js @@ -4,8 +4,8 @@ * source: https://github.com/sindresorhus/uint8array-extras */ const objectToString = Object.prototype.toString; -const uint8ArrayStringified = "[object Uint8Array]"; -const arrayBufferStringified = "[object ArrayBuffer]"; +const uint8ArrayStringified = '[object Uint8Array]'; +const arrayBufferStringified = '[object ArrayBuffer]'; function isType(value, typeConstructor, typeStringified) { if (!value) { @@ -114,21 +114,8 @@ export function compareUint8Arrays(a, b) { return Math.sign(a.length - b.length); } -// const cachedDecoders = { -// utf8: new globalThis.TextDecoder("utf8"), -// }; - -// -// !!!!!!! commented out because we dont have `TextDecoder` as dep anymore !!!!!!!! -// -// export function uint8ArrayToString(array, encoding = "utf8") { -// assertUint8ArrayOrArrayBuffer(array); -// cachedDecoders[encoding] ??= new globalThis.TextDecoder(encoding); -// return cachedDecoders[encoding].decode(array); -// } - function assertString(value) { - if (typeof value !== "string") { + if (typeof value !== 'string') { throw new TypeError(`Expected \`string\`, got \`${typeof value}\``); } } @@ -141,11 +128,11 @@ export function stringToUint8Array(string) { } function base64ToBase64Url(base64) { - return base64.replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, ""); + return base64.replaceAll('+', '-').replaceAll('/', '_').replace(/[=]+$/, ''); } function base64UrlToBase64(base64url) { - return base64url.replaceAll("-", "+").replaceAll("_", "/"); + return base64url.replaceAll('-', '+').replaceAll('_', '/'); } // Reference: https://phuoc.ng/collection/this-vs-that/concat-vs-push/ @@ -160,7 +147,7 @@ export function uint8ArrayToBase64(array, { urlSafe = false } = {}) { // Required as `btoa` and `atob` don't properly support Unicode: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem base64 = globalThis.btoa(String.fromCodePoint.apply(this, array)); } else { - base64 = ""; + base64 = ''; for (const value of array) { base64 += String.fromCodePoint(value); } @@ -173,7 +160,7 @@ export function uint8ArrayToBase64(array, { urlSafe = false } = {}) { export function base64ToUint8Array(base64String) { assertString(base64String); - return Uint8Array.from(globalThis.atob(base64UrlToBase64(base64String)), (x) => x.codePointAt(0)); + return Uint8Array.from(globalThis.atob(base64UrlToBase64(base64String)), x => x.codePointAt(0)); } export function stringToBase64(string, { urlSafe = false } = {}) { @@ -186,13 +173,13 @@ export function stringToBase64(string, { urlSafe = false } = {}) { // return uint8ArrayToString(base64ToUint8Array(base64String)); // } -const byteToHexLookupTable = Array.from({ length: 256 }, (_, index) => index.toString(16).padStart(2, "0")); +const byteToHexLookupTable = Array.from({ length: 256 }, (_, index) => index.toString(16).padStart(2, '0')); export function uint8ArrayToHex(array) { assertUint8Array(array); // Concatenating a string is faster than using an array. - let hexString = ""; + let hexString = ''; // eslint-disable-next-line unicorn/no-for-loop -- Max performance is critical. for (let index = 0; index < array.length; index++) { @@ -231,7 +218,7 @@ export function hexToUint8Array(hexString) { assertString(hexString); if (hexString.length % 2 !== 0) { - throw new Error("Invalid Hex string length."); + throw new Error('Invalid Hex string length.'); } const resultLength = hexString.length / 2; @@ -327,3 +314,84 @@ export function indexOf(array, value) { export function includes(array, value) { return indexOf(array, value) !== -1; } + +// we can use this implementation when we will have TextDecoder in RN +// const cachedDecoders = { +// utf8: new globalThis.TextDecoder("utf8"), +// }; +// export function uint8ArrayToString(array, encoding = "utf8") { +// assertUint8ArrayOrArrayBuffer(array); +// cachedDecoders[encoding] ??= new globalThis.TextDecoder(encoding); +// return cachedDecoders[encoding].decode(array); +// } +// meanwhile: + +/** + * Convert a Uint8Array (or ArrayBuffer) of UTF-8 bytes into a JS string. + * Only "utf8" is supported. For any other encoding you’ll need a polyfill. + * + * @param {Uint8Array|ArrayBuffer} input + * @param {string} [encoding="utf8"] + * @returns {string} + */ +export function uint8ArrayToString(input, encoding = 'utf8') { + assertUint8ArrayOrArrayBuffer(input); + + // Reject anything other than UTF-8 + if (!/utf-?8/i.test(encoding)) { + throw new Error('Encoding "' + encoding + '" isn’t supported without a TextDecoder polyfill'); + } + + // Normalise to Uint8Array + const bytes = input instanceof Uint8Array ? input : new Uint8Array(input); + return decodeUtf8(bytes); +} + +/** + * Minimal UTF-8 decoder + * @param {Uint8Array} bytes + * @returns {string} + */ +function decodeUtf8(bytes) { + let i = 0; + const l = bytes.length; + const codeUnits = []; + let result = ''; + + while (i < l) { + const byte1 = bytes[i++]; + + // 1-byte (ASCII) + if (byte1 < 0x80) { + codeUnits.push(byte1); + } + // 2-byte + else if (byte1 < 0xe0) { + const byte2 = bytes[i++] & 0x3f; + codeUnits.push(((byte1 & 0x1f) << 6) | byte2); + } + // 3-byte + else if (byte1 < 0xf0) { + const byte2 = bytes[i++] & 0x3f; + const byte3 = bytes[i++] & 0x3f; + codeUnits.push(((byte1 & 0x0f) << 12) | (byte2 << 6) | byte3); + } + // 4-byte (→ surrogate pair) + else { + const byte2 = bytes[i++] & 0x3f; + const byte3 = bytes[i++] & 0x3f; + const byte4 = bytes[i++] & 0x3f; + let cp = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4; + cp -= 0x10000; + codeUnits.push(0xd800 + (cp >> 10), 0xdc00 + (cp & 0x3ff)); + } + + // Flush periodically to avoid huge apply() calls + if (codeUnits.length > 0x8000) { + result += String.fromCharCode.apply(null, codeUnits); + codeUnits.length = 0; + } + } + + return result + String.fromCharCode.apply(null, codeUnits); +} diff --git a/class/blue-app.ts b/class/blue-app.ts index f110bc576f8..f29d4e982bb 100644 --- a/class/blue-app.ts +++ b/class/blue-app.ts @@ -25,6 +25,7 @@ import { SLIP39LegacyP2PKHWallet, SLIP39SegwitBech32Wallet, SLIP39SegwitP2SHWall import { ExtendedTransaction, Transaction, TWallet } from './wallets/types'; import { WatchOnlyWallet } from './wallets/watch-only-wallet'; import { getLNDHub } from '../helpers/lndHub'; +import { hexToUint8Array } from '../blue_modules/uint8array-extras'; let usedBucketNum: boolean | number = false; let savingInProgress = 0; // its both a flag and a counter of attempts to write to disk @@ -263,7 +264,7 @@ export class BlueApp { async getRealmForTransactions() { const cacheFolderPath = RNFS.CachesDirectoryPath; // Path to cache folder const password = this.hashIt(this.cachedPassword || 'fyegjitkyf[eqjnc.lf'); - const buf = Buffer.from(this.hashIt(password) + this.hashIt(password), 'hex'); + const buf = hexToUint8Array(this.hashIt(password) + this.hashIt(password)); const encryptionKey = Int8Array.from(buf); const fileName = this.hashIt(this.hashIt(password)) + '-wallettransactions.realm'; const path = `${cacheFolderPath}/${fileName}`; // Use cache folder path @@ -308,7 +309,7 @@ export class BlueApp { await Keychain.setGenericPassword(service, password, { service }); } - const buf = Buffer.from(password, 'hex'); + const buf = hexToUint8Array(password); const encryptionKey = Int8Array.from(buf); const path = `${cacheFolderPath}/keyvalue.realm`; // Use cache folder path diff --git a/class/contact-list.ts b/class/contact-list.ts index f06acf38692..eddfe9b6a57 100644 --- a/class/contact-list.ts +++ b/class/contact-list.ts @@ -3,6 +3,7 @@ import BIP47Factory from '@spsina/bip47'; import { SilentPayment } from 'silent-payments'; import ecc from '../blue_modules/noble_ecc'; +import { concatUint8Arrays } from '../blue_modules/uint8array-extras'; import * as bitcoin from 'bitcoinjs-lib'; export class ContactList { @@ -31,7 +32,7 @@ export class ContactList { const decoded = bitcoin.address.fromBech32(address); if (decoded.version === 0) return true; if (decoded.version === 1 && decoded.data.length !== 32) return false; - if (decoded.version === 1 && !ecc.isPoint(Buffer.concat([Buffer.from([2]), decoded.data]))) return false; + if (decoded.version === 1 && !ecc.isPoint(Buffer.from(concatUint8Arrays([new Uint8Array([2]), decoded.data])))) return false; if (decoded.version > 1) return false; // ^^^ some day, when versions above 1 will be actually utilized, we would need to unhardcode this return true; diff --git a/class/wallets/abstract-hd-electrum-wallet.ts b/class/wallets/abstract-hd-electrum-wallet.ts index 5943b2c53c6..970a00f5f4b 100644 --- a/class/wallets/abstract-hd-electrum-wallet.ts +++ b/class/wallets/abstract-hd-electrum-wallet.ts @@ -13,6 +13,7 @@ import { ECPairFactory, ECPairInterface } from 'ecpair'; import * as BlueElectrum from '../../blue_modules/BlueElectrum'; import { ElectrumHistory } from '../../blue_modules/BlueElectrum'; import ecc from '../../blue_modules/noble_ecc'; +import { hexToUint8Array, concatUint8Arrays, uint8ArrayToHex } from '../../blue_modules/uint8array-extras'; import { randomBytes } from '../rng'; import { AbstractHDWallet } from './abstract-hd-wallet'; import { CreateTransactionResult, CreateTransactionTarget, CreateTransactionUtxo, Transaction, Utxo } from './types'; @@ -155,14 +156,14 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { async generate() { const buf = await randomBytes(16); - this.secret = bip39.entropyToMnemonic(buf.toString('hex')); + this.secret = bip39.entropyToMnemonic(uint8ArrayToHex(buf)); } - async generateFromEntropy(user: Buffer) { + async generateFromEntropy(user: Uint8Array) { if (user.length !== 32 && user.length !== 16) { throw new Error('Entropy has to be 16 or 32 bytes long'); } - this.secret = bip39.entropyToMnemonic(user.toString('hex')); + this.secret = bip39.entropyToMnemonic(uint8ArrayToHex(user)); } _getExternalWIFByIndex(index: number): string | false { @@ -288,8 +289,8 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { // bitcoinjs does not support zpub yet, so we just convert it from xpub let data = b58.decode(xpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]); - this._xpub = b58.encode(data); + const concatenated = concatUint8Arrays([hexToUint8Array('04b24746'), data]); + this._xpub = b58.encode(concatenated); return this._xpub; } @@ -1228,8 +1229,8 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { if (masterFingerprint) { let masterFingerprintHex = Number(masterFingerprint).toString(16); if (masterFingerprintHex.length < 8) masterFingerprintHex = '0' + masterFingerprintHex; // conversion without explicit zero might result in lost byte - const hexBuffer = Buffer.from(masterFingerprintHex, 'hex'); - masterFingerprintBuffer = Buffer.from(hexBuffer).reverse(); + const hexBuffer = hexToUint8Array(masterFingerprintHex); + masterFingerprintBuffer = Buffer.from(new Uint8Array(hexBuffer).reverse()); } else { masterFingerprintBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00]); } @@ -1255,8 +1256,8 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { if (masterFingerprint) { let masterFingerprintHex = Number(masterFingerprint).toString(16); if (masterFingerprintHex.length < 8) masterFingerprintHex = '0' + masterFingerprintHex; // conversion without explicit zero might result in lost byte - const hexBuffer = Buffer.from(masterFingerprintHex, 'hex'); - masterFingerprintBuffer = Buffer.from(hexBuffer).reverse(); + const hexBuffer = hexToUint8Array(masterFingerprintHex); + masterFingerprintBuffer = Buffer.from(new Uint8Array(hexBuffer).reverse()); } else { masterFingerprintBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00]); } @@ -1537,7 +1538,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { */ static seedToFingerprint(seed: Buffer) { const root = bip32.fromSeed(seed); - let hex = root.fingerprint.toString('hex'); + let hex = uint8ArrayToHex(root.fingerprint); while (hex.length < 8) hex = '0' + hex; // leading zeroes return hex.toUpperCase(); } @@ -1658,7 +1659,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { targetsTemp.push({ value: 0, script: { - hex: Buffer.alloc(83).toString('hex'), // no `address` here, its gonabe op_return. but we pass dummy data here with a correct size just to choose utxo + hex: uint8ArrayToHex(new Uint8Array(83)), // no `address` here, its gonabe op_return. but we pass dummy data here with a correct size just to choose utxo }, }); @@ -1684,7 +1685,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet { bobBip47, keyPair.privateKey as Buffer, // txid is reversed, as well as output number - Buffer.from(inputsTemp[0].txid, 'hex').reverse().toString('hex') + outputNumber.toString('hex'), + uint8ArrayToHex(new Uint8Array(hexToUint8Array(inputsTemp[0].txid)).reverse()) + uint8ArrayToHex(outputNumber), ); // targets: diff --git a/class/wallets/abstract-wallet.ts b/class/wallets/abstract-wallet.ts index 9c1f4436b61..68fd1bd57aa 100644 --- a/class/wallets/abstract-wallet.ts +++ b/class/wallets/abstract-wallet.ts @@ -4,6 +4,7 @@ import wif from 'wif'; import { BitcoinUnit, Chain } from '../../models/bitcoinUnits'; import { CreateTransactionResult, CreateTransactionUtxo, Transaction, Utxo } from './types'; +import { hexToUint8Array, concatUint8Arrays } from '../../blue_modules/uint8array-extras'; type WalletWithPassphrase = AbstractWallet & { getPassphrase: () => string }; type UtxoMetadata = { @@ -441,9 +442,9 @@ export class AbstractWallet { _zpubToXpub(zpub: string): string { let data = b58.decode(zpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('0488b21e', 'hex'), data]); + const concatenated = concatUint8Arrays([hexToUint8Array('0488b21e'), data]); - return b58.encode(data); + return b58.encode(concatenated); } /** @@ -455,25 +456,25 @@ export class AbstractWallet { let data = b58.decode(ypub); if (data.readUInt32BE() !== 0x049d7cb2) throw new Error('Not a valid ypub extended key!'); data = data.slice(4); - data = Buffer.concat([Buffer.from('0488b21e', 'hex'), data]); + const concatenated = concatUint8Arrays([hexToUint8Array('0488b21e'), data]); - return b58.encode(data); + return b58.encode(concatenated); } _xpubToZpub(xpub: string): string { let data = b58.decode(xpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]); + const concatenated = concatUint8Arrays([hexToUint8Array('04b24746'), data]); - return b58.encode(data); + return b58.encode(concatenated); } _xpubToYpub(xpub: string): string { let data = b58.decode(xpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('049d7cb2', 'hex'), data]); + const concatenated = concatUint8Arrays([hexToUint8Array('049d7cb2'), data]); - return b58.encode(data); + return b58.encode(concatenated); } prepareForSerialization(): void {} diff --git a/class/wallets/hd-aezeed-wallet.ts b/class/wallets/hd-aezeed-wallet.ts index 9e561fb3afe..d011afff6b6 100644 --- a/class/wallets/hd-aezeed-wallet.ts +++ b/class/wallets/hd-aezeed-wallet.ts @@ -4,6 +4,7 @@ import * as bitcoin from 'bitcoinjs-lib'; import b58 from 'bs58check'; import ecc from '../../blue_modules/noble_ecc'; +import { concatUint8Arrays, hexToUint8Array } from '../../blue_modules/uint8array-extras'; import { AbstractHDElectrumWallet } from './abstract-hd-electrum-wallet'; const bip32 = BIP32Factory(ecc); @@ -56,8 +57,8 @@ export class HDAezeedWallet extends AbstractHDElectrumWallet { // bitcoinjs does not support zpub yet, so we just convert it from xpub let data = b58.decode(xpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]); - this._xpub = b58.encode(data); + const concatenated = concatUint8Arrays([hexToUint8Array('04b24746'), data]); + this._xpub = b58.encode(concatenated); return this._xpub; } diff --git a/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts b/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts index f06310c1487..0ec4071844d 100644 --- a/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts +++ b/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts @@ -4,6 +4,7 @@ import b58 from 'bs58check'; import * as mn from 'electrum-mnemonic'; import ecc from '../../blue_modules/noble_ecc'; +import { concatUint8Arrays, hexToUint8Array } from '../../blue_modules/uint8array-extras'; import { HDSegwitBech32Wallet } from './hd-segwit-bech32-wallet'; const bip32 = BIP32Factory(ecc); @@ -53,8 +54,8 @@ export class HDSegwitElectrumSeedP2WPKHWallet extends HDSegwitBech32Wallet { // bitcoinjs does not support zpub yet, so we just convert it from xpub let data = b58.decode(xpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]); - this._xpub = b58.encode(data); + const concatenated = concatUint8Arrays([hexToUint8Array('04b24746'), data]); + this._xpub = b58.encode(concatenated); return this._xpub; } diff --git a/class/wallets/hd-segwit-p2sh-wallet.ts b/class/wallets/hd-segwit-p2sh-wallet.ts index f69854a1a47..77e21ed6a4d 100644 --- a/class/wallets/hd-segwit-p2sh-wallet.ts +++ b/class/wallets/hd-segwit-p2sh-wallet.ts @@ -5,6 +5,7 @@ import b58 from 'bs58check'; import { CoinSelectReturnInput } from 'coinselect'; import ecc from '../../blue_modules/noble_ecc'; +import { concatUint8Arrays, hexToUint8Array } from '../../blue_modules/uint8array-extras'; import { AbstractHDElectrumWallet } from './abstract-hd-electrum-wallet'; const bip32 = BIP32Factory(ecc); @@ -72,8 +73,8 @@ export class HDSegwitP2SHWallet extends AbstractHDElectrumWallet { // bitcoinjs does not support ypub yet, so we just convert it from xpub let data = b58.decode(xpub); data = data.slice(4); - data = Buffer.concat([Buffer.from('049d7cb2', 'hex'), data]); - this._xpub = b58.encode(data); + const concatenated = concatUint8Arrays([hexToUint8Array('049d7cb2'), data]); + this._xpub = b58.encode(concatenated); return this._xpub; } diff --git a/class/wallets/legacy-wallet.ts b/class/wallets/legacy-wallet.ts index 3955fb8f6fb..fde1107b0ad 100644 --- a/class/wallets/legacy-wallet.ts +++ b/class/wallets/legacy-wallet.ts @@ -7,6 +7,7 @@ import { ECPairAPI, ECPairFactory, Signer } from 'ecpair'; import * as BlueElectrum from '../../blue_modules/BlueElectrum'; import ecc from '../../blue_modules/noble_ecc'; +import { hexToUint8Array, concatUint8Arrays } from '../../blue_modules/uint8array-extras'; import { HDSegwitBech32Wallet } from '..'; import { randomBytes } from '../rng'; import { AbstractWallet } from './abstract-wallet'; @@ -62,7 +63,7 @@ export class LegacyWallet extends AbstractWallet { this.secret = ECPair.makeRandom({ rng: () => buf }).toWIF(); } - async generateFromEntropy(user: Buffer): Promise { + async generateFromEntropy(user: Uint8Array): Promise { if (user.length !== 32) { throw new Error('Entropy should be 32 bytes'); } @@ -522,7 +523,7 @@ export class LegacyWallet extends AbstractWallet { const decoded = bitcoin.address.fromBech32(address); if (decoded.version === 0) return true; if (decoded.version === 1 && decoded.data.length !== 32) return false; - if (decoded.version === 1 && !ecc.isPoint(Buffer.concat([Buffer.from([2]), decoded.data]))) return false; + if (decoded.version === 1 && !ecc.isPoint(concatUint8Arrays([new Uint8Array([2]), decoded.data]))) return false; if (decoded.version > 1) return false; // ^^^ some day, when versions above 1 will be actually utilized, we would need to unhardcode this return true; @@ -539,7 +540,7 @@ export class LegacyWallet extends AbstractWallet { */ static scriptPubKeyToAddress(scriptPubKey: string): string | false { try { - const scriptPubKey2 = Buffer.from(scriptPubKey, 'hex'); + const scriptPubKey2 = hexToUint8Array(scriptPubKey); return ( bitcoin.payments.p2pkh({ output: scriptPubKey2, diff --git a/class/wallets/multisig-hd-wallet.ts b/class/wallets/multisig-hd-wallet.ts index 372677990d2..69b04a0af6a 100644 --- a/class/wallets/multisig-hd-wallet.ts +++ b/class/wallets/multisig-hd-wallet.ts @@ -13,6 +13,7 @@ import ecc from '../../blue_modules/noble_ecc'; import { decodeUR } from '../../blue_modules/ur'; import { AbstractHDElectrumWallet } from './abstract-hd-electrum-wallet'; import { CreateTransactionResult, CreateTransactionTarget, CreateTransactionUtxo } from './types'; +import { uint8ArrayToHex, hexToUint8Array, concatUint8Arrays } from '../../blue_modules/uint8array-extras'; const ECPair = ECPairFactory(ecc); const bip32 = BIP32Factory(ecc); @@ -249,7 +250,7 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { static convertMultisigXprvToRegularXprv(Zprv: string) { let data = b58.decode(Zprv); data = data.slice(4); - return b58.encode(Buffer.concat([Buffer.from('0488ade4', 'hex'), data])); + return b58.encode(concatUint8Arrays([hexToUint8Array('0488ade4'), data])); } static convertXprvToXpub(xprv: string) { @@ -379,9 +380,9 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { let data = b58.decode(xpub); data = data.slice(4); if (this.isNativeSegwit()) { - return b58.encode(Buffer.concat([Buffer.from('02aa7ed3', 'hex'), data])); + return b58.encode(concatUint8Arrays([hexToUint8Array('02aa7ed3'), data])); } else if (this.isWrappedSegwit()) { - return b58.encode(Buffer.concat([Buffer.from('0295b43f', 'hex'), data])); + return b58.encode(concatUint8Arrays([hexToUint8Array('0295b43f'), data])); } return xpub; @@ -391,9 +392,9 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { let data = b58.decode(xpub); data = data.slice(4); if (this.isNativeSegwit()) { - return b58.encode(Buffer.concat([Buffer.from('02aa7a99', 'hex'), data])); + return b58.encode(concatUint8Arrays([hexToUint8Array('02aa7a99'), data])); } else if (this.isWrappedSegwit()) { - return b58.encode(Buffer.concat([Buffer.from('0295b005', 'hex'), data])); + return b58.encode(concatUint8Arrays([hexToUint8Array('0295b005'), data])); } return xpub; @@ -515,8 +516,8 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { setSecret(secret: string) { if (secret.toUpperCase().startsWith('UR:BYTES')) { const decoded = decodeUR([secret]) as string; - const b = Buffer.from(decoded, 'hex'); - secret = b.toString(); + const b = hexToUint8Array(decoded); + secret = new TextDecoder().decode(b); } // is it Coldcard json file? @@ -630,7 +631,7 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { if (m && m.length === 3) { let hexFingerprint = m[1].split('/')[0]; if (hexFingerprint.length === 8) { - hexFingerprint = Buffer.from(hexFingerprint, 'hex').toString('hex'); + hexFingerprint = uint8ArrayToHex(hexToUint8Array(hexFingerprint)); } let path = 'm/' + m[1].split('/').slice(1).join('/').replace(/[h]/g, "'"); @@ -1070,7 +1071,7 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { } static isPathValid(path: string): boolean { - const root = bip32.fromSeed(Buffer.alloc(32)); + const root = bip32.fromSeed(Buffer.from(new Uint8Array(32))); try { root.derivePath(path); return true; @@ -1131,7 +1132,7 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { // means we failed to get amounts that go in previously, so lets use utxo amounts cache we've build // from non-segwit inputs for (const inp of psbt.txInputs) { - const cacheKey = Buffer.from(inp.hash).reverse().toString('hex') + ':' + inp.index; + const cacheKey = uint8ArrayToHex(new Uint8Array(inp.hash).reverse()) + ':' + inp.index; if (cacheUtxoAmounts[cacheKey]) goesIn += cacheUtxoAmounts[cacheKey]; } } diff --git a/components/TransactionListItem.tsx b/components/TransactionListItem.tsx index ab1325c0a4a..f24079de7ef 100644 --- a/components/TransactionListItem.tsx +++ b/components/TransactionListItem.tsx @@ -26,6 +26,7 @@ import { CommonToolTipActions } from '../typings/CommonToolTipActions'; import { pop } from '../NavigationService'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import HighlightedText from './HighlightedText'; +import { hexToUint8Array, uint8ArrayToHex } from '../blue_modules/uint8array-extras'; const styles = StyleSheet.create({ subtitle: { @@ -262,7 +263,7 @@ export const TransactionListItem: React.FC = memo( const LN = new Lnurl(false, AsyncStorage); let paymentHash = item.payment_hash!; if (typeof paymentHash === 'object') { - paymentHash = Buffer.from(paymentHash.data).toString('hex'); + paymentHash = uint8ArrayToHex(hexToUint8Array(paymentHash.data)); } const loaded = await LN.loadSuccessfulPayment(paymentHash); if (loaded) { diff --git a/screen/send/ScanQRCode.tsx b/screen/send/ScanQRCode.tsx index 7ae3e7ff8aa..bc6a79c0e9c 100644 --- a/screen/send/ScanQRCode.tsx +++ b/screen/send/ScanQRCode.tsx @@ -19,6 +19,7 @@ import presentAlert from '../../components/Alert'; import { SendDetailsStackParamList } from '../../navigation/SendDetailsStackParamList.ts'; import { BlueSpacing40 } from '../../components/BlueSpacing'; import { BlueLoading } from '../../components/BlueLoading.tsx'; +import { hexToUint8Array, uint8ArrayToBase64, uint8ArrayToHex, uint8ArrayToString } from '../../blue_modules/uint8array-extras/index'; let decoder: BlueURDecoder | undefined; @@ -93,7 +94,7 @@ const ScanQRCode = () => { }, []); const HashIt = function (s: string): string { - return Buffer.from(sha256(s)).toString('hex'); + return uint8ArrayToHex(sha256(s)); }; const _onReadUniformResourceV2 = (part: string) => { @@ -139,12 +140,13 @@ const ScanQRCode = () => { const payload = decodeUR(Object.values(animatedQRCodeData)); // lets look inside that data let data: false | string = false; - if (Buffer.from(String(payload), 'hex').toString().startsWith('psbt')) { + const payloadBytes = hexToUint8Array(String(payload)); + if (uint8ArrayToString(payloadBytes).startsWith('psbt')) { // its a psbt, and whoever requested it expects it encoded in base64 - data = Buffer.from(String(payload), 'hex').toString('base64'); + data = uint8ArrayToBase64(payloadBytes); } else { // its something else. probably plain text is expected - data = Buffer.from(String(payload), 'hex').toString(); + data = uint8ArrayToString(payloadBytes); } if (launchedBy) { const merge = true; @@ -203,7 +205,7 @@ const ScanQRCode = () => { try { const hex = Base43.decode(ret.data); bitcoin.Psbt.fromHex(hex); // if it doesnt throw - all good - const data = Buffer.from(hex, 'hex').toString('base64'); + const data = uint8ArrayToBase64(hexToUint8Array(hex)); if (launchedBy) { const merge = true; diff --git a/screen/settings/SelfTest.tsx b/screen/settings/SelfTest.tsx index 6903bf9bdb1..0c4c4232009 100644 --- a/screen/settings/SelfTest.tsx +++ b/screen/settings/SelfTest.tsx @@ -29,6 +29,7 @@ import loc from '../../loc'; import { CreateTransactionUtxo } from '../../class/wallets/types.ts'; import { BlueSpacing20 } from '../../components/BlueSpacing'; import { BlueLoading } from '../../components/BlueLoading.tsx'; +import { hexToUint8Array, uint8ArrayToHex } from '../../blue_modules/uint8array-extras/index'; const bip32 = BIP32Factory(ecc); @@ -332,7 +333,7 @@ export default class SelfTest extends Component { // - assertStrictEqual(Buffer.from('00ff0f', 'hex').reverse().toString('hex'), '0fff00'); + assertStrictEqual(uint8ArrayToHex(hexToUint8Array('00ff0f').reverse()), '0fff00'); // } catch (Err) { diff --git a/screen/wallets/Add.tsx b/screen/wallets/Add.tsx index ee966aa0c2b..5d2c4cc154d 100644 --- a/screen/wallets/Add.tsx +++ b/screen/wallets/Add.tsx @@ -33,6 +33,7 @@ import { AddWalletStackParamList } from '../../navigation/AddWalletStack'; import { RouteProp, useRoute } from '@react-navigation/native'; import SafeAreaScrollView from '../../components/SafeAreaScrollView'; import { BlueSpacing20, BlueSpacing40 } from '../../components/BlueSpacing'; +import { hexToUint8Array, uint8ArrayToHex } from '../../blue_modules/uint8array-extras'; enum ButtonSelected { // @ts-ignore: Return later to update @@ -107,7 +108,7 @@ const WalletsAdd: React.FC = () => { // const { addWallet, saveToDisk } = useStorage(); const { entropy: entropyHex, words } = useRoute().params || {}; - const entropy = entropyHex ? Buffer.from(entropyHex, 'hex') : undefined; + const entropy = entropyHex ? hexToUint8Array(entropyHex) : undefined; const { navigate, goBack, setOptions, setParams } = useExtendedNavigation(); const stylesHook = { advancedText: { @@ -248,9 +249,9 @@ const WalletsAdd: React.FC = () => { } else if (id === LightningCustodianWallet.type) { handleOnLightningButtonPressed(); } else if (id === '12_words') { - navigate('ProvideEntropy', { words: 12, entropy: entropy?.toString('hex') }); + navigate('ProvideEntropy', { words: 12, entropy: entropy ? uint8ArrayToHex(entropy) : undefined }); } else if (id === '24_words') { - navigate('ProvideEntropy', { words: 24, entropy: entropy?.toString('hex') }); + navigate('ProvideEntropy', { words: 24, entropy: entropy ? uint8ArrayToHex(entropy) : undefined }); } else if (id === CommonToolTipActions.ResetToDefault.id) { confirmResetEntropy(ButtonSelected.ONCHAIN); } diff --git a/screen/wallets/ExportMultisigCoordinationSetup.tsx b/screen/wallets/ExportMultisigCoordinationSetup.tsx index 93e112aee4f..b8120f52ed1 100644 --- a/screen/wallets/ExportMultisigCoordinationSetup.tsx +++ b/screen/wallets/ExportMultisigCoordinationSetup.tsx @@ -14,6 +14,7 @@ import { useSettings } from '../../hooks/context/useSettings'; import { useScreenProtect } from '../../hooks/useScreenProtect'; import SafeArea from '../../components/SafeArea'; import { BlueSpacing20 } from '../../components/BlueSpacing'; +import { uint8ArrayToHex, stringToUint8Array } from '../../blue_modules/uint8array-extras'; const enum ActionType { SET_LOADING = 'SET_LOADING', @@ -109,7 +110,7 @@ const ExportMultisigCoordinationSetup: React.FC = () => { try { const walletXpub = await wallet.getXpub(); if (walletXpub) { - const value = Buffer.from(walletXpub, 'ascii').toString('hex'); + const value = uint8ArrayToHex(stringToUint8Array(walletXpub)); dispatch({ type: ActionType.SET_XPUB, xpub: walletXpub }); dispatch({ type: ActionType.SET_QR_CODE_CONTENTS, qrCodeContents: value }); } else { diff --git a/screen/wallets/PaymentCodesList.tsx b/screen/wallets/PaymentCodesList.tsx index 4ab768afc55..e0ef3c710ff 100644 --- a/screen/wallets/PaymentCodesList.tsx +++ b/screen/wallets/PaymentCodesList.tsx @@ -24,6 +24,7 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation'; import { useStorage } from '../../hooks/context/useStorage'; import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList'; import { BlueLoading } from '../../components/BlueLoading'; +import { uint8ArrayToHex } from '../../blue_modules/uint8array-extras'; interface DataSection { title: string; @@ -201,7 +202,7 @@ export default function PaymentCodesList() { const renderItem = (pc: string, index: number) => { if (counterpartyMetadata?.[pc]?.hidden) return null; // hidden contact, do not render - const color = Buffer.from(sha256(pc)).toString('hex').substring(0, 6); + const color = uint8ArrayToHex(sha256(pc)).substring(0, 6); const displayName = shortenContactName(counterpartyMetadata?.[pc]?.label || pc); diff --git a/screen/wallets/ProvideEntropy.tsx b/screen/wallets/ProvideEntropy.tsx index 7393d2683d0..613bcabb331 100644 --- a/screen/wallets/ProvideEntropy.tsx +++ b/screen/wallets/ProvideEntropy.tsx @@ -24,6 +24,7 @@ import { BlueCurrentTheme, useTheme } from '../../components/themes'; import loc from '../../loc'; import { AddWalletStackParamList } from '../../navigation/AddWalletStack'; import { BlueSpacing20 } from '../../components/BlueSpacing'; +import { concatUint8Arrays, uint8ArrayToHex } from '../../blue_modules/uint8array-extras'; type RouteProps = RouteProp; type NavigationProp = NativeStackNavigationProp; @@ -124,9 +125,9 @@ export const getEntropy = (number: number, base: number): TEntropy | null => { return null; }; -// cut entropy to bytes, convert to Buffer -export const convertToBuffer = ({ entropy, bits }: { entropy: BN; bits: number }): Buffer => { - if (bits < 8) return Buffer.from([]); +// cut entropy to bytes, convert to Uint8Array +export const convertToUint8Array = ({ entropy, bits }: { entropy: BN; bits: number }): Uint8Array => { + if (bits < 8) return new Uint8Array([]); const bytes = Math.floor(bits / 8); // convert to byte array @@ -148,7 +149,7 @@ export const convertToBuffer = ({ entropy, bits }: { entropy: BN; bits: number } const zeros = [...Array(bytes - arr2.length)].map(() => 0); arr2 = [...zeros, ...arr2]; } - return Buffer.from(arr2); + return new Uint8Array(arr2); }; const Coin = ({ push }: { push: TPush }) => ( @@ -290,7 +291,7 @@ const ProvideEntropy = () => { }; const handleSave = async () => { - let buf = convertToBuffer(entropy); + let buf = convertToUint8Array(entropy); const bufLength = words === 24 ? 32 : 16; const remaining = bufLength - buf.length; @@ -320,14 +321,14 @@ const ProvideEntropy = () => { onPress: async () => { if (remaining > 0) { const random = await randomBytes(remaining); - buf = Buffer.concat([buf, random], bufLength); + buf = concatUint8Arrays([buf, random], bufLength); } - /* Convert Buffer to hex string before navigating as React Navigation - does not support passing Buffer objects between screens + /* Convert Uint8Array to hex string before navigating as React Navigation + does not support passing Uint8Array objects between screens */ - const popTo = StackActions.popTo('AddWallet', { entropy: buf.toString('hex'), words }, { merge: true }); + const popTo = StackActions.popTo('AddWallet', { entropy: uint8ArrayToHex(buf), words }, { merge: true }); navigation.dispatch(popTo); }, diff --git a/screen/wallets/WalletDetails.tsx b/screen/wallets/WalletDetails.tsx index 120a2cbae24..781fccf0c3a 100644 --- a/screen/wallets/WalletDetails.tsx +++ b/screen/wallets/WalletDetails.tsx @@ -44,6 +44,7 @@ import { CommonToolTipActions } from '../../typings/CommonToolTipActions'; import SafeAreaScrollView from '../../components/SafeAreaScrollView'; import { BlueSpacing10, BlueSpacing20 } from '../../components/BlueSpacing'; import { BlueLoading } from '../../components/BlueLoading'; +import { uint8ArrayToHex } from '../../blue_modules/uint8array-extras'; type RouteProps = RouteProp; const WalletDetails: React.FC = () => { @@ -182,7 +183,7 @@ const WalletDetails: React.FC = () => { memo = transaction.memo || ''; status = transaction.ispaid ? loc._.success : loc.lnd.expired; if (typeof hash !== 'string' && (hash as any)?.type === 'Buffer' && (hash as any)?.data) { - hash = Buffer.from((hash as any).data).toString('hex'); + hash = uint8ArrayToHex(new Uint8Array((hash as any).data)); } } diff --git a/tests/unit/provide-entropy.test.ts b/tests/unit/provide-entropy.test.ts index 8e108938f2e..81a9efed3af 100644 --- a/tests/unit/provide-entropy.test.ts +++ b/tests/unit/provide-entropy.test.ts @@ -1,6 +1,6 @@ import assert from 'assert'; -import { convertToBuffer, EActionType, entropyToHex, eReducer, getEntropy } from '../../screen/wallets/ProvideEntropy'; +import { convertToUint8Array, EActionType, entropyToHex, eReducer, getEntropy } from '../../screen/wallets/ProvideEntropy'; describe('Entropy reducer and format', () => { it('handles push and pop correctly', () => { @@ -102,42 +102,42 @@ describe('getEntropy function', () => { }); }); -describe('convertToBuffer function', () => { +describe('convertToUint8Array function', () => { it('zero bits', () => { const state = eReducer(undefined, { type: EActionType.noop }); - assert.deepEqual(convertToBuffer(state), Buffer.from([])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([])); }); it('8 zero bits', () => { const state = eReducer(undefined, { type: EActionType.push, value: 0, bits: 8 }); - assert.deepEqual(convertToBuffer(state), Buffer.from([0])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([0])); }); it('8 filled bits', () => { const state = eReducer(undefined, { type: EActionType.push, value: 0b11111111, bits: 8 }); - assert.deepEqual(convertToBuffer(state), Buffer.from([0b11111111])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([0b11111111])); }); it('9 zero bits', () => { const state = eReducer(undefined, { type: EActionType.push, value: 0, bits: 9 }); - assert.deepEqual(convertToBuffer(state), Buffer.from([0])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([0])); }); it('9 filled bits', () => { const state = eReducer(undefined, { type: EActionType.push, value: 0b111111111, bits: 9 }); - assert.deepEqual(convertToBuffer(state), Buffer.from([0b11111111])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([0b11111111])); }); it('9 bits', () => { const state = eReducer(undefined, { type: EActionType.push, value: 0b111100111, bits: 9 }); - assert.deepEqual(convertToBuffer(state), Buffer.from([0b11100111])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([0b11100111])); }); it('3 bytes', () => { let state = eReducer(undefined, { type: EActionType.push, value: 1, bits: 8 }); state = eReducer(state, { type: EActionType.push, value: 2, bits: 8 }); state = eReducer(state, { type: EActionType.push, value: 3, bits: 8 }); - assert.deepEqual(convertToBuffer(state), Buffer.from([1, 2, 3])); + assert.deepEqual(convertToUint8Array(state), new Uint8Array([1, 2, 3])); }); it('256 bits or 32bytes', () => { @@ -150,6 +150,6 @@ describe('convertToBuffer function', () => { const bytes = [...Array(32)].map(() => 255); - assert.deepEqual(convertToBuffer(state), Buffer.from(bytes)); + assert.deepEqual(convertToUint8Array(state), new Uint8Array(bytes)); }); });