Files
rea/src/evm/EvmBytecodeCarrier.ts
T
Dragolone 48e7470041 fix(evm): trim hex carrier whitespace in linear time (#5200)
The hex carrier trimmed outer ASCII whitespace with a global
start|end-anchored regex. For an invalid carrier with a long interior
whitespace run, the end branch was retried at every position of the run,
so rejection took quadratic time (about 18 s for a 200 KB run) and a few
hundred KB could exhaust the worker deadline instead of returning the
documented invalid-format error. Trim with index scans over the same
ASCII whitespace set.

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
2026-10-22 03:17:50 +08:00

35 lines
1.4 KiB
TypeScript

/** Expected carrier encoding failure, independent of the analysis engine. */
export class EvmCarrierFailure extends Error {}
/** Outer ASCII whitespace only; BOM and other Unicode spaces stay invalid. */
const asciiWhitespace = (code: number): boolean =>
code === 0x20 || (code >= 0x09 && code <= 0x0d);
/** Decode only the explicitly selected representation; source carrier bytes are retained separately. */
export const decodeEvmBytecodeCarrier = (
bytes: Uint8Array,
encoding: "raw" | "hex",
): Uint8Array => {
if (encoding === "raw") return Uint8Array.from(bytes);
let text: string;
try {
text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
bytes,
);
} catch (cause: unknown) {
throw new EvmCarrierFailure("Hex carrier must be valid UTF-8.", { cause });
}
// Index scans keep trimming linear; a global start|end regex backtracks
// through every interior whitespace run.
let start = 0;
let end = text.length;
while (start < end && asciiWhitespace(text.charCodeAt(start))) start += 1;
while (end > start && asciiWhitespace(text.charCodeAt(end - 1))) end -= 1;
const code = text.slice(start, end).replace(/^0x/i, "");
if (!/^(?:[a-fA-F0-9]{2})*$/.test(code))
throw new EvmCarrierFailure(
"Hex carrier requires complete hexadecimal byte pairs, an optional 0x prefix and outer ASCII whitespace; interior separators are invalid.",
);
return Uint8Array.from(Buffer.from(code, "hex"));
};