Skip to content

Instantly share code, notes, and snippets.

@Amxx
Created September 1, 2025 16:13
Show Gist options
  • Select an option

  • Save Amxx/ae43dc9dc24427f364c9d5789ad65896 to your computer and use it in GitHub Desktop.

Select an option

Save Amxx/ae43dc9dc24427f364c9d5789ad65896 to your computer and use it in GitHub Desktop.
const { ethers } = require("ethers");
const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values.at(0));
const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values.at(0));
const buildLookup = (...tables) => {
const bTables = tables.map(table => Array.from(ethers.toUtf8Bytes(table)));
const MINIMUM = min(...bTables.flatMap(x => x));
const MAXIMUM = max(...bTables.flatMap(x => x));
const filter = [].concat(...bTables).reduce((acc, x) => acc | (1n << BigInt(x - MINIMUM)), 0n);
const lookup = Uint8Array.from(Array.from({ length: MAXIMUM - MINIMUM + 1 }).map((_, i) => bTables.map(table => table.indexOf(i + MINIMUM)).find(x => x != -1) ?? 0xff));
const valid = tables.every(table => Object.entries(table).every(([ i, c]) => i == lookup.at(c.charCodeAt(0) - MINIMUM)));
return valid ? { tables, lookup: ethers.hexlify(lookup), filter: ethers.toBeHex(filter), MINIMUM, MAXIMUM } : undefined;
}
console.log(buildLookup(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", // base64
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", // base64url
"=", // padding
));
console.log(buildLookup(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", // base32
"=", // padding
));
console.log(buildLookup(
"0123456789ABCDEFGHIJKLMNOPQRSTUV", // base32
"=", // padding
));
console.log(buildLookup(
"0123456789abcdef", // base16 / hex
"0123456789ABDCEF", // base16 / hex
));
console.log(buildLookup(
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", // base58
));
@Amxx
Copy link
Author

Amxx commented Sep 1, 2025

output is

{
  tables: [
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
    '='
  ],
  lookup: '0x3eff3eff3f3435363738393a3b3c3dffffff00ffffff000102030405060708090a0b0c0d0e0f10111213141516171819ffffffff3fff1a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233',
  filter: '0xffffffd0ffffffc47ff5',
  MINIMUM: 43,
  MAXIMUM: 122
}
{
  tables: [ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', '=' ],
  lookup: '0x1a1b1c1d1e1fffffffffff00ffffff000102030405060708090a0b0c0d0e0f10111213141516171819',
  filter: '0x01ffffff883f',
  MINIMUM: 50,
  MAXIMUM: 90
}
{
  tables: [ '0123456789ABCDEFGHIJKLMNOPQRSTUV', '=' ],
  lookup: '0x00010203040506070809ffffff00ffffff0a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
  filter: '0x7ffffe23ff',
  MINIMUM: 48,
  MAXIMUM: 86
}
{
  tables: [ '0123456789abcdef', '0123456789ABDCEF' ],
  lookup: '0x00010203040506070809ffffffffffffff0a0b0d0c0e0fffffffffffffffffffffffffffffffffffffffffffffffffffff0a0b0c0d0e0f',
  filter: '0x7e0000007e03ff',
  MINIMUM: 48,
  MAXIMUM: 102
}
{
  tables: [ '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' ],
  lookup: '0x000102030405060708ffffffffffffff090a0b0c0d0e0f10ff1112131415ff161718191a1b1c1d1e1f20ffffffffffff2122232425262728292a2bff2c2d2e2f30313233343536373839',
  filter: '0x03fff7ff03ffbeff01ff',
  MINIMUM: 49,
  MAXIMUM: 122
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment