Files
comet/src/cometcrc.pas
Ken Johnson 0d19afe3f1 Move source to src/, add cometcrypt + contrib, update build system
- Move all .pas source files from root to src/ directory
- Add cometcrypt.pas (X25519 key exchange + ChaCha20 encryption)
- Add test_crypt.pas and test_outbound.pas
- Add contrib/ (systemd service, install script)
- Add COMET.QA quality assurance checklist
- Update Makefile for src/ layout
- Update FSP-COMET.001 protocol spec
- Remove comet.exe binary from repo
2026-04-01 11:11:27 -07:00

130 lines
2.8 KiB
ObjectPascal

{
Comet - Direct TCP File Transfer for FidoNet
cometcrc.pas - CRC-32 calculation
Standard reflected CRC-32 (ISO 3309 / ITU-T V.42):
Polynomial: 0xEDB88320 (reflected form of 0x04C11DB7)
Initial: 0xFFFFFFFF
Post-process: XOR with 0xFFFFFFFF (bitwise inversion)
Byte order: little-endian on wire
Same algorithm as ZModem, Janus, Hydra, PKZip, Ethernet, and Nova.
Output is byte-identical to Xenia's crc32block() and Fimail's CRC32Block().
Test vectors:
CRC32("") = 0x00000000 (empty input returns 0, not post-processed)
CRC32("123456789") = 0xCBF43926
Copyright (C) 2026 Ken Johnson
License: GPL-2.0
}
unit cometcrc;
{$mode objfpc}{$H+}
interface
{ Update CRC-32 with a single byte }
function CRC32Update(CRC: LongWord; B: Byte): LongWord;
{ Compute CRC-32 of a buffer. Init and post-process are handled internally.
Returns the final CRC-32 value ready for use on the wire. }
function CRC32Block(const Buf; Len: LongInt): LongWord;
{ Compute CRC-32 of a string }
function CRC32String(const S: string): LongWord;
{ Incremental CRC-32: start with this value }
function CRC32Init: LongWord;
{ Incremental CRC-32: update with a buffer of bytes }
function CRC32UpdateBlock(CRC: LongWord; const Buf; Len: LongInt): LongWord;
{ Incremental CRC-32: finalize (XOR with $FFFFFFFF) }
function CRC32Finish(CRC: LongWord): LongWord;
implementation
var
CRC32Tab: array[0..255] of LongWord;
TabReady: Boolean = False;
procedure InitTable;
var
I, J: Integer;
CRC: LongWord;
begin
if TabReady then Exit;
for I := 0 to 255 do
begin
CRC := LongWord(I);
for J := 0 to 7 do
begin
if (CRC and 1) <> 0 then
CRC := (CRC shr 1) xor $EDB88320
else
CRC := CRC shr 1;
end;
CRC32Tab[I] := CRC;
end;
TabReady := True;
end;
function CRC32Update(CRC: LongWord; B: Byte): LongWord;
begin
if not TabReady then InitTable;
Result := CRC32Tab[(CRC xor B) and $FF] xor (CRC shr 8);
end;
function CRC32Init: LongWord;
begin
Result := $FFFFFFFF;
end;
function CRC32UpdateBlock(CRC: LongWord; const Buf; Len: LongInt): LongWord;
var
P: PByte;
I: LongInt;
begin
if not TabReady then InitTable;
Result := CRC;
P := @Buf;
for I := 0 to Len - 1 do
begin
Result := CRC32Tab[(Result xor P^) and $FF] xor (Result shr 8);
Inc(P);
end;
end;
function CRC32Finish(CRC: LongWord): LongWord;
begin
Result := CRC xor $FFFFFFFF;
end;
function CRC32Block(const Buf; Len: LongInt): LongWord;
begin
if not TabReady then InitTable;
if Len <= 0 then
begin
Result := 0;
Exit;
end;
Result := CRC32UpdateBlock($FFFFFFFF, Buf, Len);
Result := Result xor $FFFFFFFF;
end;
function CRC32String(const S: string): LongWord;
begin
if Length(S) = 0 then
Result := 0
else
Result := CRC32Block(S[1], Length(S));
end;
end.