Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Commit

Permalink
Refactor a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Dec 23, 2023
1 parent 1acfbad commit 86466b1
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 40 deletions.
61 changes: 44 additions & 17 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,57 @@
/*! micro-password-generator - MIT License (c) 2022 Paul Miller (paulmillr.com) */
export type Bytes = Uint8Array;

function isBytes(a: unknown): a is Uint8Array {
return (
a instanceof Uint8Array ||
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')
);
}

// generic utils
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
function bytesToHex(uint8a: Uint8Array): string {
// Array where index 0xf0 (240) is mapped to string 'f0'
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
i.toString(16).padStart(2, '0')
);
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
export function bytesToHex(bytes: Uint8Array): string {
if (!isBytes(bytes)) throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
if (!(uint8a instanceof Uint8Array)) throw new Error('Uint8Array expected');
let hex = '';
for (let i = 0; i < uint8a.length; i++) {
hex += hexes[uint8a[i]];
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}

function hexToBytes(hex: string): Uint8Array {
if (typeof hex !== 'string') {
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
}
if (hex.length % 2) throw new Error('hexToBytes: received invalid unpadded hex');
const array = new Uint8Array(hex.length / 2);
for (let i = 0; i < array.length; i++) {
const j = i * 2;
const hexByte = hex.slice(j, j + 2);
const byte = Number.parseInt(hexByte, 16);
if (Number.isNaN(byte) || byte < 0) throw new Error('Invalid byte sequence');
array[i] = byte;
// We use optimized technique to convert hex string to byte array
const asciis = { _0: 48, _9: 57, _A: 65, _F: 70, _a: 97, _f: 102 } as const;
function asciiToBase16(char: number): number | undefined {
if (char >= asciis._0 && char <= asciis._9) return char - asciis._0;
if (char >= asciis._A && char <= asciis._F) return char - (asciis._A - 10);
if (char >= asciis._a && char <= asciis._f) return char - (asciis._a - 10);
return;
}

/**
* @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])
*/
export function hexToBytes(hex: string): Uint8Array {
if (typeof hex !== 'string') throw new Error('hex string expected, got ' + typeof hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2) throw new Error('padded hex string expected, got unpadded hex of length ' + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === undefined || n2 === undefined) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2;
}
return array;
}
Expand Down
7 changes: 1 addition & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,5 @@
"macos",
"secure"
],
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
"funding": "https://paulmillr.com/funding/"
}
36 changes: 19 additions & 17 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
{
"compilerOptions": {
"strict": true,
"declaration": true,
"declarationMap": true,
"target": "es2020",
"lib": ["es2020"],
"module": "node16",
"moduleResolution": "node16",
"outDir": ".",
"noImplicitAny": true,
"preserveConstEnums": true,
"resolveJsonModule": true,
"strict": true,
"sourceMap": false,
"allowSyntheticDefaultImports": false,
"allowUnreachableCode": false,
"esModuleInterop": false,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": ".",

"module": "es2020",
"outDir": ".",
"moduleResolution": "bundler",
"declaration": true,
"declarationMap": true
},
"include": [
"index.ts"
],
"exclude": [
"node_modules",
"lib"
]
}
"include": ["index.ts"],
"exclude": ["node_modules", "lib"]
}

0 comments on commit 86466b1

Please sign in to comment.