-
Notifications
You must be signed in to change notification settings - Fork 12.1k
Add Base58 library #5762
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add Base58 library #5762
Conversation
🦋 Changeset detectedLatest commit: da84743 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
contracts/utils/Base58.sol
Outdated
|
||
bytes internal constant _TABLE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | ||
bytes internal constant _LOOKUP_TABLE = | ||
hex"000102030405060708ffffffffffffff090a0b0c0d0e0f10ff1112131415ff161718191a1b1c1d1e1f20ffffffffffff2122232425262728292a2bff2c2d2e2f30313233343536373839"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For anyone curious, here is how you build these lookup tables:
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 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), MINIMUM, MAXIMUM } : undefined;
}
console.log(buildLookup(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", // base64
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", // base64url
));
console.log(buildLookup(
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", // base58
));
contracts/utils/Base58.sol
Outdated
for (uint256 i = 0; i < data.length; ++i) { | ||
// get b58 char | ||
uint8 chr = _mload8i(data, i); | ||
require(chr > 48 && chr < 123, InvalidBase56Digit(chr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
48 and 123 are derived from the minimum and maximum values taken by b58 chars, see https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5762/files#r2160061084
Co-authored-by: Vectorized <webby1111@hotmail.com>
Fixes #5760
Includes (depends on) #5733
This probably deserves some assembly. It feels like the decoding could be optimized a lot. Note that base58 is notoriously loop (and memory ops) heavy.
PR Checklist
npx changeset add
)