Files
openlaunch/app/scripts/lib/keccak256.mjs
Kevin Codex 312489a7b4 Initial commit
openlaunch — launch a token. Free. Open source. On Base or Robinhood Chain.
Contracts (LaunchFactory / LaunchLocker / LaunchToken, Foundry), the site (Next.js),
brand assets. No platform fee, liquidity locked forever.
2026-09-07 11:28:24 +08:00

74 lines
2.9 KiB
JavaScript

/**
* Dependency-free Keccak-256 (the Ethereum flavour: 0x01 padding, NOT SHA3's
* 0x06) for scripts that run inside the standalone image, where viem is not
* available (Next bundles it into the server chunks). src/lib/keccak.test.ts
* asserts parity with viem's keccak256 on the seed urls + known vectors.
* BigInt lanes: slow-ish (~µs per block) but trivially correct; only used for
* ~30 urls at seed time.
*/
const M64 = (1n << 64n) - 1n;
const RC = [
0x0000000000000001n, 0x0000000000008082n, 0x800000000000808an, 0x8000000080008000n,
0x000000000000808bn, 0x0000000080000001n, 0x8000000080008081n, 0x8000000000008009n,
0x000000000000008an, 0x0000000000000088n, 0x0000000080008009n, 0x000000008000000an,
0x000000008000808bn, 0x800000000000008bn, 0x8000000000008089n, 0x8000000000008003n,
0x8000000000008002n, 0x8000000000000080n, 0x000000000000800an, 0x800000008000000an,
0x8000000080008081n, 0x8000000000008080n, 0x0000000080000001n, 0x8000000080008008n,
];
// rotation offsets r[x][y]
const ROT = [
[0, 36, 3, 41, 18],
[1, 44, 10, 45, 2],
[62, 6, 43, 15, 61],
[28, 55, 25, 21, 56],
[27, 20, 39, 8, 14],
];
const rotl = (v, n) => (n === 0 ? v : ((v << BigInt(n)) | (v >> BigInt(64 - n))) & M64);
/** @param {bigint[]} A 25 lanes, index x + 5y */
function keccakF1600(A) {
const C = new Array(5);
const D = new Array(5);
const B = new Array(25);
for (let round = 0; round < 24; round++) {
for (let x = 0; x < 5; x++) C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];
for (let x = 0; x < 5; x++) D[x] = C[(x + 4) % 5] ^ rotl(C[(x + 1) % 5], 1);
for (let i = 0; i < 25; i++) A[i] ^= D[i % 5];
for (let x = 0; x < 5; x++) for (let y = 0; y < 5; y++) B[y + 5 * ((2 * x + 3 * y) % 5)] = rotl(A[x + 5 * y], ROT[x][y]);
for (let x = 0; x < 5; x++) for (let y = 0; y < 5; y++) A[x + 5 * y] = B[x + 5 * y] ^ (~B[((x + 1) % 5) + 5 * y] & M64 & B[((x + 2) % 5) + 5 * y]);
A[0] ^= RC[round];
}
}
/** @param {Uint8Array} bytes @returns {`0x${string}`} 0x + 64 lowercase hex */
export function keccak256(bytes) {
const rate = 136; // (1600 - 2*256) / 8
const padded = new Uint8Array(Math.ceil((bytes.length + 1) / rate) * rate);
padded.set(bytes);
padded[bytes.length] ^= 0x01;
padded[padded.length - 1] ^= 0x80;
const A = new Array(25).fill(0n);
for (let off = 0; off < padded.length; off += rate) {
for (let i = 0; i < rate / 8; i++) {
let lane = 0n;
for (let b = 7; b >= 0; b--) lane = (lane << 8n) | BigInt(padded[off + i * 8 + b]);
A[i] ^= lane;
}
keccakF1600(A);
}
let out = "0x";
for (let i = 0; i < 4; i++) {
let lane = A[i];
for (let b = 0; b < 8; b++) {
out += Number(lane & 0xffn).toString(16).padStart(2, "0");
lane >>= 8n;
}
}
return /** @type {`0x${string}`} */ (out);
}
/** keccak256(bytes(url)) — the contract's entry id for a canonical url string. */
export function entryIdOf(url) {
return keccak256(new TextEncoder().encode(url));
}