diff --git a/CHANGELOG.md b/CHANGELOG.md index bdae1c7c..3a9d74c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Changes: - Adjust and optimize WASM function JS interface construction +- Simplify base64 bytes decoding ## 4.4.1 Nov 22, 2021 diff --git a/packages/wasm-crypto-wasm/src/base64.ts b/packages/wasm-crypto-wasm/src/base64.ts index 400188e7..fae50b3b 100644 --- a/packages/wasm-crypto-wasm/src/base64.ts +++ b/packages/wasm-crypto-wasm/src/base64.ts @@ -1,86 +1,22 @@ // Copyright 2019-2021 @polkadot/wasm-crypto authors & contributors // SPDX-License-Identifier: Apache-2.0 -// MIT License -// -// Copyright (c) 2014 Jameson Little -// -// https://github.com/beatgammit/base64-js/blob/88957c9943c7e2a0f03cdf73e71d579e433627d3/index.js -// This only contains the toByteArray function (no encoding) -// -// Only tweaks make here are some TS adjustments (we use strict null checks), the code is otherwise as-is with -// only the single required function provided +const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; -const CODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +export function base64Decode (data: string): Uint8Array { + const bytes = []; + let byte = 0; + let bits = 0; -const lookup: string[] = []; -const revLookup: number[] = []; + for (let i = 0; i < data.length && data[i] !== '='; i++) { + // each character represents 6 bits + byte = (byte << 6) | chars.indexOf(data[i]); -for (let i = 0; i < CODE.length; ++i) { - lookup[i] = CODE[i]; - revLookup[CODE.charCodeAt(i)] = i; -} - -// Support decoding URL-safe base64 strings, as Node.js does. -// See: https://en.wikipedia.org/wiki/Base64#URL_applications -revLookup['-'.charCodeAt(0)] = 62; -revLookup['_'.charCodeAt(0)] = 63; - -function getLens (b64: string): [number, number] { - const len = b64.length; - - if (len % 4 > 0) { - throw new Error('Invalid string. Length must be a multiple of 4'); + // each byte needs to contain 8 bits + if ((bits += 6) >= 8) { + bytes.push((byte >>> (bits -= 8)) & 0xff); + } } - // Trim off extra bytes after placeholder bytes are found - // See: https://github.com/beatgammit/base64-js/issues/42 - const validLen = b64.indexOf('='); - - return validLen === -1 - ? [len, 0] - : [validLen, 4 - (validLen % 4)]; -} - -export function toByteArray (b64: string): Uint8Array { - const [validLen, placeHoldersLen] = getLens(b64); - const arr = new Uint8Array(((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen); - let curByte = 0; - let i: number; - let tmp: number; - - // if there are placeholders, only get up to the last complete 4 chars - const len = placeHoldersLen > 0 - ? validLen - 4 - : validLen; - - for (i = 0; i < len; i += 4) { - tmp = - (revLookup[b64.charCodeAt(i)] << 18) | - (revLookup[b64.charCodeAt(i + 1)] << 12) | - (revLookup[b64.charCodeAt(i + 2)] << 6) | - revLookup[b64.charCodeAt(i + 3)]; - - arr[curByte++] = (tmp >> 16) & 0xFF; - arr[curByte++] = (tmp >> 8) & 0xFF; - arr[curByte++] = tmp & 0xFF; - } - - if (placeHoldersLen === 2) { - tmp = - (revLookup[b64.charCodeAt(i)] << 2) | - (revLookup[b64.charCodeAt(i + 1)] >> 4); - - arr[curByte++] = tmp & 0xFF; - } else if (placeHoldersLen === 1) { - tmp = - (revLookup[b64.charCodeAt(i)] << 10) | - (revLookup[b64.charCodeAt(i + 1)] << 4) | - (revLookup[b64.charCodeAt(i + 2)] >> 2); - - arr[curByte++] = (tmp >> 8) & 0xFF; - arr[curByte++] = tmp & 0xFF; - } - - return arr; + return Uint8Array.from(bytes); } diff --git a/packages/wasm-crypto-wasm/src/data.ts b/packages/wasm-crypto-wasm/src/data.ts index 5e4eee78..c495c048 100644 --- a/packages/wasm-crypto-wasm/src/data.ts +++ b/packages/wasm-crypto-wasm/src/data.ts @@ -1,8 +1,8 @@ // Copyright 2019-2021 @polkadot/wasm-crypto-wasm authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { toByteArray } from './base64'; +import { base64Decode } from './base64'; import { bytes, sizeUncompressed } from './bytes'; import { unzlibSync } from './fflate'; -export const wasmBytes = unzlibSync(toByteArray(bytes), new Uint8Array(sizeUncompressed)); +export const wasmBytes = unzlibSync(base64Decode(bytes), new Uint8Array(sizeUncompressed));