UNPKG

@hqtsm/crc

Version:

CRC functions with a parameterized engine optimized for both speed and size

299 lines (279 loc) 5.31 kB
/** * @module * * The core CRC functions and types. */ /** * An array-like object of 8-bit numbers. */ export type CrcData = { /** * Number of bytes. */ length: number; /** * Bytes. */ [index: number]: number; }; /** * CRC table. */ export type CrcTable<T extends number | bigint> = () => T[]; /** * CRC reflect. * * @param data Bits to reflect. * @param size Number of bits. * @returns Reflected bits. */ export type CrcReflect<T extends number | bigint> = ( data: T, size: number | bigint, ) => T; /** * CRC init. * * @returns Initial value. */ export type CrcInit<T extends number | bigint> = () => T; /** * CRC update. * * @param crc Current value. * @param data Bytes. * @returns Updated value. */ export type CrcUpdate<T extends number | bigint> = ( crc: T, data: Readonly<CrcData>, ) => T; /** * CRC finalize. * * @param crc Value to finalize. * @returns Finalized CRC. */ export type CrcFinalize<T extends number | bigint> = (crc: T) => T; /** * CRC interface. */ export type CrcInterface<T extends number | bigint> = { /** * Bit size. */ readonly size: T; /** * Polynomial. */ readonly poly: T; /** * Reflect input. */ readonly refi: boolean; /** * XOR input. */ readonly xori: T; /** * Reflect output. */ readonly refo: boolean; /** * XOR output. */ readonly xoro: T; /** * CRC reflect. */ readonly reflect: CrcReflect<T>; /** * CRC table. */ readonly table: CrcTable<T>; /** * CRC init. */ readonly init: CrcInit<T>; /** * CRC update. */ readonly update: CrcUpdate<T>; /** * CRC finalize. */ readonly finalize: CrcFinalize<T>; }; /** * CRC factory. * * @param size Bit size. * @param poly Polynomial. * @param refi Reflect input. * @param xori XOR input. * @param refo Reflect output. * @param xoro XOR output. */ export function crc<T extends number>( size: number, poly: number, refi: boolean, xori: number, refo: boolean, xoro: number, ): CrcInterface<number>; export function crc<T extends bigint>( size: bigint, poly: bigint, refi: boolean, xori: bigint, refo: boolean, xoro: bigint, ): CrcInterface<bigint>; export function crc<T extends number | bigint>( size: T, poly: T, refi: boolean, xori: T, refo: boolean, xoro: T, ): CrcInterface<T> { let t: T[]; let s: number; let i8 = size - size; let i0 = i8++; let i1 = i8++; let i255 = (i1 << (i8 <<= i8)) - i1; let h = i1 << size - i1; let m = h - i1 << i1 | i1; let n = i0 === 0; let reflect = (data: T, width: number | bigint) => { let r = data & i1; while (--width) { r = r << i1 | ((data as number) >>= i1) & i1; } return (n ? r >>> 0 : r) as T; }; let table = () => { let r = size < i8 ? i8 - size : i0; let l = size - i8 + r; let a = h << r; let x = poly << r; let t = [i0]; let c; for (let i = i255; i;) { c = (refi ? reflect(i as T, 8) : i) << l; for (let j = 8; j--;) { c = c & a ? c << i1 ^ x : c << i1; } c >>= r; c = refi ? reflect(c as T, size) as number : (c & m); t[i--] = n ? c >>> 0 : c; } return t as T[]; }; return { size, poly, refi, xori, refo, xoro, reflect, table, init: refi ? () => reflect(xori, size) : () => xori, update: refi ? ( n ? (crc: T, data: Readonly<CrcData>) => { t ??= table(); for (let i = 0, l = data.length; i < l;) { crc = ( t[ (crc ^ data[i++]) & i255 ] ^ crc >>> i8 ) as T; } return crc >>> 0 as T; } : (crc: T, data: Readonly<CrcData>) => { t ??= table(); for (let i = 0, l = data.length; i < l;) { crc = ( t[ Number(crc & i255) ^ data[i++] & 255 ] ^ crc >> i8 ) as T; } return crc; } ) : ( (s = size - i8) > 0 ? ( n ? (crc: T, data: Readonly<CrcData>) => { t ??= table(); for (let i = 0, l = data.length; i < l;) { crc = ( t[ (crc >>> s ^ data[i++]) & i255 ] ^ crc << i8 & m ) as T; } return crc >>> 0 as T; } : (crc: T, data: Readonly<CrcData>) => { t ??= table(); for (let i = 0, l = data.length; i < l;) { crc = ( t[ Number(crc >> s & i255) ^ data[i++] & 255 ] ^ crc << i8 & m ) as T; } return crc as T; } ) : ( (s = -s, n) ? (crc: T, data: Readonly<CrcData>) => { t ??= table(); for (let i = 0, l = data.length; i < l;) { crc = ( t[ (crc << s ^ data[i++]) & i255 ] ) as T; } return crc as T; } : (crc: T, data: Readonly<CrcData>) => { t ??= table(); for (let i = 0, l = data.length; i < l;) { crc = ( t[ Number(crc << s & i255) ^ data[i++] & 255 ] ) as T; } return crc as T; } ) ), finalize: refo === refi ? ( n ? (crc: T) => (crc ^ xoro) >>> 0 as T : (crc: T) => (crc ^ xoro) as T ) : ( n ? (crc: T) => (reflect(crc, size) ^ xoro) >>> 0 as T : (crc: T) => (reflect(crc, size) ^ xoro) as T ), }; }