@exodus/bytes 1.0.0-rc.7 → 1.0.0-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -3
- package/base58.js +3 -3
- package/base58check.js +2 -1
- package/base64.js +30 -29
- package/bech32.js +254 -0
- package/encoding.js +234 -0
- package/fallback/_utils.js +111 -8
- package/fallback/base32.js +2 -2
- package/fallback/encoding.labels.js +46 -0
- package/fallback/encoding.util.js +34 -0
- package/fallback/hex.js +2 -70
- package/fallback/latin1.js +11 -4
- package/fallback/multi-byte.encodings.cjs +1 -0
- package/fallback/multi-byte.encodings.json +545 -0
- package/fallback/multi-byte.js +449 -0
- package/fallback/multi-byte.table.js +114 -0
- package/fallback/single-byte.encodings.js +45 -0
- package/fallback/single-byte.js +83 -0
- package/fallback/utf16.js +180 -0
- package/hex.js +6 -4
- package/hex.node.js +2 -0
- package/multi-byte.js +13 -0
- package/multi-byte.node.js +25 -0
- package/package.json +52 -11
- package/single-byte.js +55 -0
- package/single-byte.node.js +62 -0
- package/utf16.js +73 -0
- package/utf16.node.js +79 -0
- package/utf8.js +12 -13
- package/utf8.node.js +28 -7
- package/wif.js +42 -0
package/utf16.node.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { nativeDecoder, isDeno, isLE } from './fallback/_utils.js'
|
|
2
|
+
import { E_STRICT, E_STRICT_UNICODE } from './fallback/utf16.js'
|
|
3
|
+
|
|
4
|
+
if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill')
|
|
5
|
+
|
|
6
|
+
const { isWellFormed } = String.prototype
|
|
7
|
+
const to8 = (a) => new Uint8Array(a.buffer, a.byteOffset, a.byteLength)
|
|
8
|
+
|
|
9
|
+
// Unlike utf8, operates on Uint16Arrays by default
|
|
10
|
+
|
|
11
|
+
function encode(str, loose = false, format = 'uint16') {
|
|
12
|
+
if (typeof str !== 'string') throw new TypeError('Input is not a string')
|
|
13
|
+
if (format !== 'uint16' && format !== 'uint8-le' && format !== 'uint8-be') {
|
|
14
|
+
throw new TypeError('Unknown format')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!isWellFormed.call(str)) {
|
|
18
|
+
if (!loose) throw new TypeError(E_STRICT_UNICODE)
|
|
19
|
+
str = nativeDecoder.decode(Buffer.from(str)) // well, let's fix up (Buffer doesn't do this with utf16 encoding)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const ble = Buffer.from(str, 'utf-16le')
|
|
23
|
+
|
|
24
|
+
if (format === 'uint8-le') return to8(ble)
|
|
25
|
+
if (format === 'uint8-be') return to8(ble.swap16())
|
|
26
|
+
if (format === 'uint16') {
|
|
27
|
+
const b = ble.byteOffset % 2 === 0 ? ble : Buffer.from(ble) // it should be already aligned, but just in case
|
|
28
|
+
if (!isLE) b.swap16()
|
|
29
|
+
return new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new Error('Unreachable')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const swapped = (x, swap) =>
|
|
36
|
+
swap ? Buffer.from(x).swap16() : Buffer.from(x.buffer, x.byteOffset, x.byteLength)
|
|
37
|
+
|
|
38
|
+
// We skip TextDecoder on Node.js, as it's is somewhy significantly slower than Buffer for utf16
|
|
39
|
+
function decodeNode(input, loose = false, format = 'uint16') {
|
|
40
|
+
let ble
|
|
41
|
+
if (format === 'uint16') {
|
|
42
|
+
if (!(input instanceof Uint16Array)) throw new TypeError('Expected an Uint16Array')
|
|
43
|
+
ble = swapped(input, !isLE)
|
|
44
|
+
} else if (format === 'uint8-le' || format === 'uint8-be') {
|
|
45
|
+
if (!(input instanceof Uint8Array)) throw new TypeError('Expected an Uint8Array')
|
|
46
|
+
if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes')
|
|
47
|
+
ble = swapped(input, format === 'uint8-be')
|
|
48
|
+
} else {
|
|
49
|
+
throw new TypeError('Unknown format')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const str = ble.ucs2Slice(0, ble.byteLength)
|
|
53
|
+
if (isWellFormed.call(str)) return str
|
|
54
|
+
if (!loose) throw new TypeError(E_STRICT)
|
|
55
|
+
return nativeDecoder.decode(Buffer.from(str)) // fixup (see above)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function decodeDecoder(input, loose = false, format = 'uint16') {
|
|
59
|
+
let encoding
|
|
60
|
+
if (format === 'uint16') {
|
|
61
|
+
if (!(input instanceof Uint16Array)) throw new TypeError('Expected an Uint16Array')
|
|
62
|
+
encoding = isLE ? 'utf-16le' : 'utf-16be'
|
|
63
|
+
} else if (format === 'uint8-le' || format === 'uint8-be') {
|
|
64
|
+
if (!(input instanceof Uint8Array)) throw new TypeError('Expected an Uint8Array')
|
|
65
|
+
if (input.byteLength % 2 !== 0) throw new TypeError('Expected even number of bytes')
|
|
66
|
+
encoding = format === 'uint8-le' ? 'utf-16le' : 'utf-16be'
|
|
67
|
+
} else {
|
|
68
|
+
throw new TypeError('Unknown format')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return new TextDecoder(encoding, { ignoreBOM: true, fatal: !loose }).decode(input) // TODO: cache decoder?
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const decode = isDeno ? decodeDecoder : decodeNode
|
|
75
|
+
|
|
76
|
+
export const utf16fromString = (str, format = 'uint16') => encode(str, false, format)
|
|
77
|
+
export const utf16fromStringLoose = (str, format = 'uint16') => encode(str, true, format)
|
|
78
|
+
export const utf16toString = (arr, format = 'uint16') => decode(arr, false, format)
|
|
79
|
+
export const utf16toStringLoose = (arr, format = 'uint16') => decode(arr, true, format)
|
package/utf8.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
import { assertUint8 } from './assert.js'
|
|
2
2
|
import { typedView } from './array.js'
|
|
3
|
-
import
|
|
3
|
+
import { isHermes, nativeDecoder, nativeEncoder } from './fallback/_utils.js'
|
|
4
4
|
import { asciiPrefix, decodeLatin1 } from './fallback/latin1.js'
|
|
5
|
+
import * as js from './fallback/utf8.js'
|
|
5
6
|
|
|
6
|
-
const {
|
|
7
|
-
const haveNativeBuffer = Buffer && !Buffer.TYPED_ARRAY_SUPPORT
|
|
8
|
-
const isNative = (x) => x && (haveNativeBuffer || `${x}`.includes('[native code]')) // we consider Node.js TextDecoder/TextEncoder native
|
|
9
|
-
const haveDecoder = isNative(TextDecoder)
|
|
10
|
-
const nativeEncoder = isNative(TextEncoder) ? new TextEncoder() : null
|
|
7
|
+
const { TextDecoder, decodeURIComponent, escape } = globalThis // Buffer is optional
|
|
11
8
|
// ignoreBOM: true means that BOM will be left as-is, i.e. will be present in the output
|
|
12
9
|
// We don't want to strip anything unexpectedly
|
|
13
|
-
const
|
|
14
|
-
const
|
|
10
|
+
const decoderLoose = nativeDecoder
|
|
11
|
+
const decoderFatal = nativeDecoder
|
|
12
|
+
? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true })
|
|
13
|
+
: null
|
|
15
14
|
const { isWellFormed } = String.prototype
|
|
16
15
|
|
|
17
16
|
const { E_STRICT, E_STRICT_UNICODE } = js
|
|
18
17
|
|
|
19
|
-
const shouldUseEscapePath =
|
|
18
|
+
const shouldUseEscapePath = isHermes // faster only on Hermes, js path beats it on normal engines
|
|
20
19
|
|
|
21
20
|
function deLoose(str, loose, res) {
|
|
22
21
|
if (loose || str.length === res.length) return res // length is equal only for ascii, which is automatically fine
|
|
@@ -46,16 +45,16 @@ function deLoose(str, loose, res) {
|
|
|
46
45
|
|
|
47
46
|
function encode(str, loose = false) {
|
|
48
47
|
if (typeof str !== 'string') throw new TypeError('Input is not a string')
|
|
49
|
-
if (
|
|
50
|
-
if (nativeEncoder) return deLoose(str, loose, nativeEncoder.encode(str))
|
|
48
|
+
if (str.length === 0) return new Uint8Array() // faster than Uint8Array.of
|
|
49
|
+
if (nativeEncoder) return deLoose(str, loose, nativeEncoder.encode(str))
|
|
51
50
|
// No reason to use unescape + encodeURIComponent: it's slower than JS on normal engines, and modern Hermes already has TextEncoder
|
|
52
51
|
return js.encode(str, loose)
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
function decode(arr, loose = false) {
|
|
56
55
|
assertUint8(arr)
|
|
57
|
-
if (
|
|
58
|
-
|
|
56
|
+
if (arr.byteLength === 0) return ''
|
|
57
|
+
if (nativeDecoder) return loose ? decoderLoose.decode(arr) : decoderFatal.decode(arr) // Node.js and browsers
|
|
59
58
|
|
|
60
59
|
// Fast path for ASCII prefix, this is faster than all alternatives below
|
|
61
60
|
const prefix = decodeLatin1(arr, 0, asciiPrefix(arr))
|
package/utf8.node.js
CHANGED
|
@@ -5,23 +5,44 @@ import { isAscii } from 'node:buffer'
|
|
|
5
5
|
|
|
6
6
|
if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill')
|
|
7
7
|
|
|
8
|
-
const decoderFatal = new TextDecoder('
|
|
9
|
-
const decoderLoose = new TextDecoder('
|
|
8
|
+
const decoderFatal = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true })
|
|
9
|
+
const decoderLoose = new TextDecoder('utf-8', { ignoreBOM: true })
|
|
10
10
|
const { isWellFormed } = String.prototype
|
|
11
|
+
const isDeno = Boolean(globalThis.Deno)
|
|
11
12
|
|
|
12
13
|
function encode(str, loose = false) {
|
|
13
14
|
if (typeof str !== 'string') throw new TypeError('Input is not a string')
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
const strLength = str.length
|
|
16
|
+
if (strLength === 0) return new Uint8Array() // faster than Uint8Array.of
|
|
17
|
+
let res
|
|
18
|
+
if (strLength > 0x4_00 && !isDeno) {
|
|
19
|
+
// Faster for large strings
|
|
20
|
+
const byteLength = Buffer.byteLength(str)
|
|
21
|
+
res = Buffer.allocUnsafe(byteLength)
|
|
22
|
+
const ascii = byteLength === strLength
|
|
23
|
+
const written = ascii ? res.latin1Write(str) : res.utf8Write(str)
|
|
24
|
+
if (written !== byteLength) throw new Error('Failed to write all bytes') // safeguard just in case
|
|
25
|
+
if (ascii || loose) return res // no further checks needed
|
|
26
|
+
} else {
|
|
27
|
+
res = Buffer.from(str)
|
|
28
|
+
if (res.length === strLength || loose) return res
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!isWellFormed.call(str)) throw new TypeError(E_STRICT_UNICODE)
|
|
32
|
+
return res
|
|
17
33
|
}
|
|
18
34
|
|
|
19
35
|
function decode(arr, loose = false) {
|
|
20
36
|
assertUint8(arr)
|
|
21
|
-
|
|
37
|
+
const byteLength = arr.byteLength
|
|
38
|
+
if (byteLength === 0) return ''
|
|
39
|
+
if (byteLength > 0x6_00 && !(isDeno && loose) && isAscii(arr)) {
|
|
22
40
|
// On non-ascii strings, this loses ~10% * [relative position of the first non-ascii byte] (up to 10% total)
|
|
23
41
|
// On ascii strings, this wins 1.5x on loose = false and 1.3x on loose = true
|
|
24
|
-
|
|
42
|
+
// Only makes sense for large enough strings
|
|
43
|
+
const buf = Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength)
|
|
44
|
+
if (isDeno) return buf.toString() // Deno suffers from .latin1Slice
|
|
45
|
+
return buf.latin1Slice(0, arr.byteLength) // .latin1Slice is faster than .asciiSlice
|
|
25
46
|
}
|
|
26
47
|
|
|
27
48
|
return loose ? decoderLoose.decode(arr) : decoderFatal.decode(arr)
|
package/wif.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { toBase58checkSync, fromBase58checkSync } from './base58check.js'
|
|
2
|
+
import { assertUint8 } from './assert.js'
|
|
3
|
+
|
|
4
|
+
// Mostly matches npmjs.com/wif, but with extra checks + using our base58check
|
|
5
|
+
// Also no inconsistent behavior on Buffer/Uint8Array input
|
|
6
|
+
|
|
7
|
+
function from(arr, expectedVersion) {
|
|
8
|
+
assertUint8(arr)
|
|
9
|
+
const version = arr[0]
|
|
10
|
+
if (expectedVersion !== undefined && version !== expectedVersion) {
|
|
11
|
+
throw new Error('Invalid network version')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Makes a copy, regardless of input being a Buffer or a Uint8Array (unlike .slice)
|
|
15
|
+
const privateKey = Uint8Array.from(arr.subarray(1, 33))
|
|
16
|
+
if (arr.length === 33) return { version, privateKey, compressed: false }
|
|
17
|
+
if (arr.length !== 34) throw new Error('Invalid WIF length')
|
|
18
|
+
if (arr[33] !== 1) throw new Error('Invalid compression flag')
|
|
19
|
+
return { version, privateKey, compressed: true }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function to({ version: v, privateKey, compressed }) {
|
|
23
|
+
if (!Number.isSafeInteger(v) || v < 0 || v > 0xff) throw new Error('Missing or invalid version')
|
|
24
|
+
assertUint8(privateKey, { length: 32, name: 'privateKey' })
|
|
25
|
+
if (privateKey.length !== 32) throw new TypeError('Invalid privateKey length')
|
|
26
|
+
const out = new Uint8Array(compressed ? 34 : 33)
|
|
27
|
+
out[0] = v
|
|
28
|
+
out.set(privateKey, 1)
|
|
29
|
+
if (compressed) out[33] = 1
|
|
30
|
+
return out
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Async performance is worse here, so expose the same internal methods as sync for now
|
|
34
|
+
// ./base58check is sync internally anyway for now, so doesn't matter until that is changed
|
|
35
|
+
|
|
36
|
+
export const fromWifStringSync = (string, version) => from(fromBase58checkSync(string), version)
|
|
37
|
+
// export const fromWifString = async (string, version) => from(await fromBase58check(string), version)
|
|
38
|
+
export const fromWifString = async (string, version) => from(fromBase58checkSync(string), version)
|
|
39
|
+
|
|
40
|
+
export const toWifStringSync = (wif) => toBase58checkSync(to(wif))
|
|
41
|
+
// export const toWifString = async (wif) => toBase58check(to(wif))
|
|
42
|
+
export const toWifString = async (wif) => toBase58checkSync(to(wif))
|