Use micro-base for base{32, 58, 64} (#1209)

This commit is contained in:
Jaco
2021-11-19 11:27:47 +02:00
committed by GitHub
parent 222bb74a81
commit 4d77bf3c5b
15 changed files with 89 additions and 87 deletions
+1
View File
@@ -12,6 +12,7 @@ Changes:
- Add `has*` detection shortcuts (e.g. `hasWasm` or `hasBuffer`)
- Optimize for `hexToU8a` and `u8aToHex` functions
- Optimize `u8aEq` to use `DataView` for compares
- Align base{32, 58, 64} around (audited) `micro-base`
- Space optimization for bip39 wordlists
- Sync with upstream Substrate ss58 registry
- Expand tests for uncovered functions
+1 -2
View File
@@ -30,8 +30,6 @@
"@polkadot/util": "7.8.3-30",
"@polkadot/wasm-crypto": "^4.2.1",
"@polkadot/x-randomvalues": "7.8.3-30",
"base-x": "^3.0.9",
"base64-js": "^1.5.1",
"blakejs": "^1.1.1",
"bn.js": "^4.12.0",
"create-hash": "^1.2.0",
@@ -39,6 +37,7 @@
"elliptic": "^6.5.4",
"hash.js": "^1.1.7",
"js-sha3": "^0.8.0",
"micro-base": "^0.9.0",
"scryptsy": "^2.1.0",
"tweetnacl": "^1.0.3",
"xxhashjs": "^0.2.2"
+12 -2
View File
@@ -1,6 +1,16 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// https://github.com/multiformats/js-multibase/blob/master/src/constants.js
import { utils } from 'micro-base';
export const BASE32_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
export const BITS_PER_CHAR = 5;
// We define our own chain, the default base32 has padding
export const base32 = utils.chain(
utils.radix2(5),
utils.alphabet(BASE32_ALPHABET),
{
decode: (input: string) => input.split(''),
encode: (input: string[]) => input.join('')
}
);
+5 -40
View File
@@ -1,39 +1,9 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// adapted from https://github.com/multiformats/js-multibase/blob/424709195b46ffb1d6f2f69a7707598ebe751e5e/src/rfc4648.js
import { assert } from '@polkadot/util';
import { BASE32_ALPHABET, BITS_PER_CHAR } from './bs32';
import { base32 } from './bs32';
import { base32Validate } from './validate';
// Build the character lookup table:
const LOOKUP = BASE32_ALPHABET.split('').reduce<Record<string, number>>((lookup, a, i) => {
lookup[a] = i;
return lookup;
}, {});
/** @internal */
function decode (output: Uint8Array, input: string, offset: number): [Uint8Array, number, number] {
let bits = 0;
let buffer = 0;
let written = 0;
for (let i = offset; i < input.length; i++) {
buffer = (buffer << BITS_PER_CHAR) | LOOKUP[input[i]];
bits += BITS_PER_CHAR;
if (bits >= 8) {
bits -= 8;
output[written++] = 0xff & (buffer >> bits);
}
}
return [output, bits, buffer];
}
/**
* @name base32Decode
* @summary Delookup a base32 value.
@@ -43,14 +13,9 @@ function decode (output: Uint8Array, input: string, offset: number): [Uint8Array
export function base32Decode (value: string, ipfsCompat = false): Uint8Array {
base32Validate(value, ipfsCompat);
const offset = (ipfsCompat ? 1 : 0);
const [output, bits, buffer] = decode(
new Uint8Array(((value.length - offset) * BITS_PER_CHAR / 8) | 0),
value,
offset
return base32.decode(
ipfsCompat
? value.substr(1)
: value
);
assert(!(bits >= BITS_PER_CHAR || 0xff & (buffer << (8 - bits))), 'Unexpected end of data');
return output;
}
@@ -11,6 +11,12 @@ describe('base32Encode', (): void => {
).toEqual('irswgzloorzgc3djpjssazlwmvzhs5dinfxgoijb');
});
it('encodes to a base32 (ipfs-compat)', (): void => {
expect(
base32Encode('Decentralize everything!!', true)
).toEqual('birswgzloorzgc3djpjssazlwmvzhs5dinfxgoijb');
});
it('encodes a base58 to a base32', (): void => {
expect(
base32Encode(
+2 -23
View File
@@ -1,15 +1,11 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
// adapted from https://github.com/multiformats/js-multibase/blob/424709195b46ffb1d6f2f69a7707598ebe751e5e/src/rfc4648.js
import type { U8aLike } from '@polkadot/util/types';
import { u8aToU8a } from '@polkadot/util';
import { BASE32_ALPHABET, BITS_PER_CHAR } from './bs32';
const MASK = (1 << BITS_PER_CHAR) - 1;
import { base32 } from './bs32';
/**
* @name base32Encode
@@ -18,24 +14,7 @@ const MASK = (1 << BITS_PER_CHAR) - 1;
* From the provided input, create the base32 and return the result as a string.
*/
export function base32Encode (value: U8aLike, ipfsCompat = false): string {
const u8a = u8aToU8a(value);
let out = '';
let bits = 0;
let buffer = 0;
for (let i = 0; i < u8a.length; ++i) {
buffer = (buffer << 8) | u8a[i];
bits += 8;
while (bits > BITS_PER_CHAR) {
bits -= BITS_PER_CHAR;
out += BASE32_ALPHABET[MASK & (buffer >> bits)];
}
}
if (bits) {
out += BASE32_ALPHABET[MASK & (buffer << (BITS_PER_CHAR - bits))];
}
const out = base32.encode(u8aToU8a(value));
return ipfsCompat
? `b${out}`
+1 -3
View File
@@ -1,9 +1,7 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import baseX from 'base-x';
export { base58 } from 'micro-base';
// https://github.com/cryptocoinjs/base-x#alphabets
export const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
export const bs58 = baseX(BASE58_ALPHABET);
@@ -0,0 +1,23 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { base32Decode } from '../base32';
import { base58Decode } from './';
describe('base58Encode', (): void => {
it('encodes a base58 to a base32', (): void => {
expect(
base58Decode('b2rhk6GMPQF3hfzwXTaNYFLKomMeC6UXdUt6jZKPpeVirLtV')
).toEqual(
base32Decode('afkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy')
);
});
it('encodes a base58 to a base32 (ipfs-compat)', (): void => {
expect(
base58Decode('zb2rhk6GMPQF3hfzwXTaNYFLKomMeC6UXdUt6jZKPpeVirLtV', true)
).toEqual(
base32Decode('bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy', true)
);
});
});
+6 -4
View File
@@ -1,9 +1,7 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { bufferToU8a } from '@polkadot/util';
import { bs58 } from './bs58';
import { base58 } from './bs58';
import { base58Validate } from './validate';
/**
@@ -15,5 +13,9 @@ import { base58Validate } from './validate';
export function base58Decode (value: string, ipfsCompat?: boolean): Uint8Array {
base58Validate(value, ipfsCompat);
return bufferToU8a(bs58.decode(value.substr(ipfsCompat ? 1 : 0)));
return base58.decode(
ipfsCompat
? value.substr(1)
: value
);
}
@@ -5,7 +5,15 @@ import { base32Decode } from '../base32';
import { base58Encode } from './';
describe('base58Encode', (): void => {
it('encodes a base32 to a base38', (): void => {
it('encodes a base32 to a base58', (): void => {
expect(
base58Encode(
base32Decode('bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy', true)
)
).toEqual('b2rhk6GMPQF3hfzwXTaNYFLKomMeC6UXdUt6jZKPpeVirLtV');
});
it('encodes a base32 to a base58 (ipfs-compat)', (): void => {
expect(
base58Encode(
base32Decode('bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy', true),
+2 -2
View File
@@ -5,7 +5,7 @@ import type { U8aLike } from '@polkadot/util/types';
import { u8aToU8a } from '@polkadot/util';
import { bs58 } from './bs58';
import { base58 } from './bs58';
/**
* @name base58Encode
@@ -14,7 +14,7 @@ import { bs58 } from './bs58';
* From the provided input, create the base58 and return the result as a string.
*/
export function base58Encode (value: U8aLike, ipfsCompat?: boolean): string {
const out = bs58.encode(u8aToU8a(value));
const out = base58.encode(u8aToU8a(value));
return ipfsCompat
? `z${out}`
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
export { base64 } from 'micro-base';
export const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+2 -3
View File
@@ -1,8 +1,7 @@
// Copyright 2017-2021 @polkadot/util-crypto authors & contributors
// SPDX-License-Identifier: Apache-2.0
import base64 from 'base64-js';
import { base64 } from './bs64';
import { base64Validate } from './validate';
/**
@@ -14,5 +13,5 @@ import { base64Validate } from './validate';
export function base64Decode (value: string): Uint8Array {
base64Validate(value);
return base64.toByteArray(value);
return base64.decode(value);
}
+3 -3
View File
@@ -3,10 +3,10 @@
import type { U8aLike } from '@polkadot/util/types';
import base64 from 'base64-js';
import { u8aToU8a } from '@polkadot/util';
import { base64 } from './bs64';
/**
* @name base64Encode
* @summary Creates a base64 value.
@@ -14,5 +14,5 @@ import { u8aToU8a } from '@polkadot/util';
* From the provided input, create the base64 and return the result as a string.
*/
export function base64Encode (value: U8aLike): string {
return base64.fromByteArray(u8aToU8a(value));
return base64.encode(u8aToU8a(value));
}
+10 -4
View File
@@ -2093,8 +2093,6 @@ __metadata:
"@types/elliptic": ^6.4.14
"@types/scryptsy": ^2.0.0
"@types/xxhashjs": ^0.2.2
base-x: ^3.0.9
base64-js: ^1.5.1
blakejs: ^1.1.1
bn.js: ^4.12.0
create-hash: ^1.2.0
@@ -2102,6 +2100,7 @@ __metadata:
elliptic: ^6.5.4
hash.js: ^1.1.7
js-sha3: ^0.8.0
micro-base: ^0.9.0
scryptsy: ^2.1.0
tweetnacl: ^1.0.3
xxhashjs: ^0.2.2
@@ -3367,7 +3366,7 @@ __metadata:
languageName: node
linkType: hard
"base-x@npm:^3.0.2, base-x@npm:^3.0.9":
"base-x@npm:^3.0.2":
version: 3.0.9
resolution: "base-x@npm:3.0.9"
dependencies:
@@ -3376,7 +3375,7 @@ __metadata:
languageName: node
linkType: hard
"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1":
"base64-js@npm:^1.3.1":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005
@@ -7693,6 +7692,13 @@ fsevents@~2.1.2:
languageName: node
linkType: hard
"micro-base@npm:^0.9.0":
version: 0.9.0
resolution: "micro-base@npm:0.9.0"
checksum: a223a83239782189fbc281c7836f30491ec120ace2a2c634290a9dc3efb82edc591ffd68e375e2c60c2fde64b84f9576a3064a42ece25e98b6ac4ff2610d6ad7
languageName: node
linkType: hard
"micromatch@npm:^4.0.2, micromatch@npm:^4.0.4":
version: 4.0.4
resolution: "micromatch@npm:4.0.4"