Skip to content

Instantly share code, notes, and snippets.

@robey
Created September 22, 2016 21:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robey/fc79f39e13771124d4efd31d709fd0ac to your computer and use it in GitHub Desktop.
Save robey/fc79f39e13771124d4efd31d709fd0ac to your computer and use it in GitHub Desktop.
fast browser-friendly base32 codec
// base32 implementation for fun.
const alphabet = "0123456789abcdefghjkmnpqrtuvwxyz";
if (alphabet.length != 32) throw new Error("Base 32 requires a 32-character alphabet");
// chars that look similar (dwim):
const alias = { o: 0, i: 1, l: 1, s: 5 };
const reverseLookup = buildReverseTable();
function buildReverseTable() {
const table = new Uint8Array(128);
for (let i = 0; i < 128; i++) table[i] = 0;
for (let i = 0; i < alphabet.length; i++) table[alphabet.charCodeAt(i)] = i;
Object.keys(alias).forEach(k => {
table[k.charCodeAt(0)] = alias[k];
});
// capitals should alias to lowercase:
for (let i = 0x40; i < 0x60; i++) table[i] = table[i + 0x20];
return table;
}
function encode(buffer: Uint8Array): string {
// can't use Uint8Array here, because there's no way to map it into a string. :(
const outBuffer: number[] = new Array(Math.ceil(1.6 * buffer.length));
let acc = 0, bits = 0, j = 0;
for (let i = 0; i < buffer.length; i++) {
acc = (acc << 8) | buffer[i];
bits += 8;
while (bits >= 5) {
outBuffer[j++] = (acc >> (bits - 5)) & 0x1f;
acc = (acc & 0xfff);
bits -= 5;
}
}
if (bits > 0) outBuffer[j++] = (acc << (5 - bits)) & 0x1f;
return outBuffer.map(c => alphabet[c]).join("");
}
function decode(buffer: string): Uint8Array {
const outBuffer = new Uint8Array(Math.ceil(buffer.length * 0.625));
let acc = 0, bits = 0, j = 0;
for (let i = 0; i < buffer.length; i++) {
acc = (acc << 5) | reverseLookup[buffer.charCodeAt(i) & 0x7f];
bits += 5;
while (bits >= 8) {
outBuffer[j++] = (acc >> (bits - 8)) & 0xff;
acc = (acc & 0xffff);
bits -= 8;
}
}
if (bits > 0) outBuffer[j++] = (acc << (8 - bits)) & 0xff;
return outBuffer;
}
// quick demo/test, you can erase this part.
const data = new Uint8Array([
0x17, 0x05, 0x76, 0x84, 0xbe, 0xa1, 0xf9, 0x33, 0x14, 0x18,
0xb6, 0x33, 0xa8, 0xf3, 0x73, 0x11, 0x9d, 0x76, 0x5f, 0xd4
]);
const encoded = "2w2qd15ym7wk650rprtuhwvk26eqcqym";
console.log(data, encode(data));
console.log(encoded, decode(encoded));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment