package udp // EQ2EMu uses a specific CRC32 polynomial (reversed) const crcPolynomial = 0xEDB88320 // Pre-computed CRC32 lookup table for fast calculation var crcTable [256]uint32 // init builds the CRC lookup table at package initialization func init() { for i := range crcTable { crc := uint32(i) for range 8 { if crc&1 == 1 { crc = (crc >> 1) ^ crcPolynomial } else { crc >>= 1 } } crcTable[i] = crc } } // CalculateCRC32 computes CRC32 using EQ2EMu's algorithm // Returns 16-bit value by truncating the upper bits func CalculateCRC32(data []byte) uint16 { crc := uint32(0xFFFFFFFF) // Use lookup table for efficient calculation for _, b := range data { crc = crcTable[byte(crc)^b] ^ (crc >> 8) } // Return inverted result truncated to 16 bits return uint16(^crc) } // ValidateCRC checks if packet has valid CRC // Expects CRC to be the last 2 bytes of data func ValidateCRC(data []byte) bool { if len(data) < 2 { return false } // Split payload and CRC payload := data[:len(data)-2] expectedCRC := uint16(data[len(data)-2]) | (uint16(data[len(data)-1]) << 8) // Calculate and compare actualCRC := CalculateCRC32(payload) return expectedCRC == actualCRC } // AppendCRC adds 16-bit CRC to the end of data func AppendCRC(data []byte) []byte { crc := CalculateCRC32(data) result := make([]byte, len(data)+2) copy(result, data) // Append CRC in little-endian format result[len(data)] = byte(crc) result[len(data)+1] = byte(crc >> 8) return result } // ValidateAndStrip validates CRC and returns data without CRC suffix func ValidateAndStrip(data []byte) ([]byte, bool) { if !ValidateCRC(data) { return nil, false } return data[:len(data)-2], true }