openigtlink_rust/protocol/
crc.rs

1//! CRC64 checksum calculation for OpenIGTLink messages
2//!
3//! This implementation uses the exact lookup table from the official
4//! C++ OpenIGTLink library to ensure byte-level compatibility.
5
6/// CRC64 lookup table from OpenIGTLink C++ implementation (igtl_util.c)
7///
8/// This table must match exactly with the official implementation for
9/// compatibility with other OpenIGTLink implementations.
10const CRC64_TABLE: [u64; 256] = [
11    0x0000000000000000,
12    0x42F0E1EBA9EA3693,
13    0x85E1C3D753D46D26,
14    0xC711223CFA3E5BB5,
15    0x493366450E42ECDF,
16    0x0BC387AEA7A8DA4C,
17    0xCCD2A5925D9681F9,
18    0x8E224479F47CB76A,
19    0x9266CC8A1C85D9BE,
20    0xD0962D61B56FEF2D,
21    0x17870F5D4F51B498,
22    0x5577EEB6E6BB820B,
23    0xDB55AACF12C73561,
24    0x99A54B24BB2D03F2,
25    0x5EB4691841135847,
26    0x1C4488F3E8F96ED4,
27    0x663D78FF90E185EF,
28    0x24CD9914390BB37C,
29    0xE3DCBB28C335E8C9,
30    0xA12C5AC36ADFDE5A,
31    0x2F0E1EBA9EA36930,
32    0x6DFEFF5137495FA3,
33    0xAAEFDD6DCD770416,
34    0xE81F3C86649D3285,
35    0xF45BB4758C645C51,
36    0xB6AB559E258E6AC2,
37    0x71BA77A2DFB03177,
38    0x334A9649765A07E4,
39    0xBD68D2308226B08E,
40    0xFF9833DB2BCC861D,
41    0x388911E7D1F2DDA8,
42    0x7A79F00C7818EB3B,
43    0xCC7AF1FF21C30BDE,
44    0x8E8A101488293D4D,
45    0x499B3228721766F8,
46    0x0B6BD3C3DBFD506B,
47    0x854997BA2F81E701,
48    0xC7B97651866BD192,
49    0x00A8546D7C558A27,
50    0x4258B586D5BFBCB4,
51    0x5E1C3D753D46D260,
52    0x1CECDC9E94ACE4F3,
53    0xDBFDFEA26E92BF46,
54    0x990D1F49C77889D5,
55    0x172F5B3033043EBF,
56    0x55DFBADB9AEE082C,
57    0x92CE98E760D05399,
58    0xD03E790CC93A650A,
59    0xAA478900B1228E31,
60    0xE8B768EB18C8B8A2,
61    0x2FA64AD7E2F6E317,
62    0x6D56AB3C4B1CD584,
63    0xE374EF45BF6062EE,
64    0xA1840EAE168A547D,
65    0x66952C92ECB40FC8,
66    0x2465CD79455E395B,
67    0x3821458AADA7578F,
68    0x7AD1A461044D611C,
69    0xBDC0865DFE733AA9,
70    0xFF3067B657990C3A,
71    0x711223CFA3E5BB50,
72    0x33E2C2240A0F8DC3,
73    0xF4F3E018F031D676,
74    0xB60301F359DBE0E5,
75    0xDA050215EA6C212F,
76    0x98F5E3FE438617BC,
77    0x5FE4C1C2B9B84C09,
78    0x1D14202910527A9A,
79    0x93366450E42ECDF0,
80    0xD1C685BB4DC4FB63,
81    0x16D7A787B7FAA0D6,
82    0x5427466C1E109645,
83    0x4863CE9FF6E9F891,
84    0x0A932F745F03CE02,
85    0xCD820D48A53D95B7,
86    0x8F72ECA30CD7A324,
87    0x0150A8DAF8AB144E,
88    0x43A04931514122DD,
89    0x84B16B0DAB7F7968,
90    0xC6418AE602954FFB,
91    0xBC387AEA7A8DA4C0,
92    0xFEC89B01D3679253,
93    0x39D9B93D2959C9E6,
94    0x7B2958D680B3FF75,
95    0xF50B1CAF74CF481F,
96    0xB7FBFD44DD257E8C,
97    0x70EADF78271B2539,
98    0x321A3E938EF113AA,
99    0x2E5EB66066087D7E,
100    0x6CAE578BCFE24BED,
101    0xABBF75B735DC1058,
102    0xE94F945C9C3626CB,
103    0x676DD025684A91A1,
104    0x259D31CEC1A0A732,
105    0xE28C13F23B9EFC87,
106    0xA07CF2199274CA14,
107    0x167FF3EACBAF2AF1,
108    0x548F120162451C62,
109    0x939E303D987B47D7,
110    0xD16ED1D631917144,
111    0x5F4C95AFC5EDC62E,
112    0x1DBC74446C07F0BD,
113    0xDAAD56789639AB08,
114    0x985DB7933FD39D9B,
115    0x84193F60D72AF34F,
116    0xC6E9DE8B7EC0C5DC,
117    0x01F8FCB784FE9E69,
118    0x43081D5C2D14A8FA,
119    0xCD2A5925D9681F90,
120    0x8FDAB8CE70822903,
121    0x48CB9AF28ABC72B6,
122    0x0A3B7B1923564425,
123    0x70428B155B4EAF1E,
124    0x32B26AFEF2A4998D,
125    0xF5A348C2089AC238,
126    0xB753A929A170F4AB,
127    0x3971ED50550C43C1,
128    0x7B810CBBFCE67552,
129    0xBC902E8706D82EE7,
130    0xFE60CF6CAF321874,
131    0xE224479F47CB76A0,
132    0xA0D4A674EE214033,
133    0x67C58448141F1B86,
134    0x253565A3BDF52D15,
135    0xAB1721DA49899A7F,
136    0xE9E7C031E063ACEC,
137    0x2EF6E20D1A5DF759,
138    0x6C0603E6B3B7C1CA,
139    0xF6FAE5C07D3274CD,
140    0xB40A042BD4D8425E,
141    0x731B26172EE619EB,
142    0x31EBC7FC870C2F78,
143    0xBFC9838573709812,
144    0xFD39626EDA9AAE81,
145    0x3A28405220A4F534,
146    0x78D8A1B9894EC3A7,
147    0x649C294A61B7AD73,
148    0x266CC8A1C85D9BE0,
149    0xE17DEA9D3263C055,
150    0xA38D0B769B89F6C6,
151    0x2DAF4F0F6FF541AC,
152    0x6F5FAEE4C61F773F,
153    0xA84E8CD83C212C8A,
154    0xEABE6D3395CB1A19,
155    0x90C79D3FEDD3F122,
156    0xD2377CD44439C7B1,
157    0x15265EE8BE079C04,
158    0x57D6BF0317EDAA97,
159    0xD9F4FB7AE3911DFD,
160    0x9B041A914A7B2B6E,
161    0x5C1538ADB04570DB,
162    0x1EE5D94619AF4648,
163    0x02A151B5F156289C,
164    0x4051B05E58BC1E0F,
165    0x87409262A28245BA,
166    0xC5B073890B687329,
167    0x4B9237F0FF14C443,
168    0x0962D61B56FEF2D0,
169    0xCE73F427ACC0A965,
170    0x8C8315CC052A9FF6,
171    0x3A80143F5CF17F13,
172    0x7870F5D4F51B4980,
173    0xBF61D7E80F251235,
174    0xFD913603A6CF24A6,
175    0x73B3727A52B393CC,
176    0x31439391FB59A55F,
177    0xF652B1AD0167FEEA,
178    0xB4A25046A88DC879,
179    0xA8E6D8B54074A6AD,
180    0xEA16395EE99E903E,
181    0x2D071B6213A0CB8B,
182    0x6FF7FA89BA4AFD18,
183    0xE1D5BEF04E364A72,
184    0xA3255F1BE7DC7CE1,
185    0x64347D271DE22754,
186    0x26C49CCCB40811C7,
187    0x5CBD6CC0CC10FAFC,
188    0x1E4D8D2B65FACC6F,
189    0xD95CAF179FC497DA,
190    0x9BAC4EFC362EA149,
191    0x158E0A85C2521623,
192    0x577EEB6E6BB820B0,
193    0x906FC95291867B05,
194    0xD29F28B9386C4D96,
195    0xCEDBA04AD0952342,
196    0x8C2B41A1797F15D1,
197    0x4B3A639D83414E64,
198    0x09CA82762AAB78F7,
199    0x87E8C60FDED7CF9D,
200    0xC51827E4773DF90E,
201    0x020905D88D03A2BB,
202    0x40F9E43324E99428,
203    0x2CFFE7D5975E55E2,
204    0x6E0F063E3EB46371,
205    0xA91E2402C48A38C4,
206    0xEBEEC5E96D600E57,
207    0x65CC8190991CB93D,
208    0x273C607B30F68FAE,
209    0xE02D4247CAC8D41B,
210    0xA2DDA3AC6322E288,
211    0xBE992B5F8BDB8C5C,
212    0xFC69CAB42231BACF,
213    0x3B78E888D80FE17A,
214    0x7988096371E5D7E9,
215    0xF7AA4D1A85996083,
216    0xB55AACF12C735610,
217    0x724B8ECDD64D0DA5,
218    0x30BB6F267FA73B36,
219    0x4AC29F2A07BFD00D,
220    0x08327EC1AE55E69E,
221    0xCF235CFD546BBD2B,
222    0x8DD3BD16FD818BB8,
223    0x03F1F96F09FD3CD2,
224    0x41011884A0170A41,
225    0x86103AB85A2951F4,
226    0xC4E0DB53F3C36767,
227    0xD8A453A01B3A09B3,
228    0x9A54B24BB2D03F20,
229    0x5D45907748EE6495,
230    0x1FB5719CE1045206,
231    0x919735E51578E56C,
232    0xD367D40EBC92D3FF,
233    0x1476F63246AC884A,
234    0x568617D9EF46BED9,
235    0xE085162AB69D5E3C,
236    0xA275F7C11F7768AF,
237    0x6564D5FDE549331A,
238    0x279434164CA30589,
239    0xA9B6706FB8DFB2E3,
240    0xEB46918411358470,
241    0x2C57B3B8EB0BDFC5,
242    0x6EA7525342E1E956,
243    0x72E3DAA0AA188782,
244    0x30133B4B03F2B111,
245    0xF7021977F9CCEAA4,
246    0xB5F2F89C5026DC37,
247    0x3BD0BCE5A45A6B5D,
248    0x79205D0E0DB05DCE,
249    0xBE317F32F78E067B,
250    0xFCC19ED95E6430E8,
251    0x86B86ED5267CDBD3,
252    0xC4488F3E8F96ED40,
253    0x0359AD0275A8B6F5,
254    0x41A94CE9DC428066,
255    0xCF8B0890283E370C,
256    0x8D7BE97B81D4019F,
257    0x4A6ACB477BEA5A2A,
258    0x089A2AACD2006CB9,
259    0x14DEA25F3AF9026D,
260    0x562E43B4931334FE,
261    0x913F6188692D6F4B,
262    0xD3CF8063C0C759D8,
263    0x5DEDC41A34BBEEB2,
264    0x1F1D25F19D51D821,
265    0xD80C07CD676F8394,
266    0x9AFCE626CE85B507,
267];
268
269/// Calculate CRC64 checksum for data
270///
271/// This is compatible with the OpenIGTLink C++ implementation.
272///
273/// # Arguments
274/// * `data` - Byte slice to calculate CRC for
275///
276/// # Returns
277/// 64-bit CRC checksum
278pub fn calculate_crc(data: &[u8]) -> u64 {
279    calculate_crc_with_initial(data, 0)
280}
281
282/// Calculate CRC64 checksum with an initial CRC value
283///
284/// This allows for incremental CRC calculation.
285///
286/// # Arguments
287/// * `data` - Byte slice to calculate CRC for
288/// * `initial_crc` - Initial CRC value (use 0 for new calculation)
289///
290/// # Returns
291/// 64-bit CRC checksum
292pub fn calculate_crc_with_initial(data: &[u8], initial_crc: u64) -> u64 {
293    let mut crc = initial_crc;
294    for &byte in data {
295        let index = (byte ^ (crc >> 56) as u8) as usize;
296        crc = CRC64_TABLE[index] ^ (crc << 8);
297    }
298    crc
299}
300
301/// Verify CRC64 checksum
302///
303/// # Arguments
304/// * `data` - Byte slice to verify
305/// * `expected_crc` - Expected CRC value
306///
307/// # Returns
308/// `true` if CRC matches, `false` otherwise
309pub fn verify_crc(data: &[u8], expected_crc: u64) -> bool {
310    calculate_crc(data) == expected_crc
311}
312
313#[cfg(test)]
314mod tests {
315    use super::*;
316
317    #[test]
318    fn test_crc_deterministic() {
319        // CRC should be deterministic
320        let data = b"test data";
321        let crc1 = calculate_crc(data);
322        let crc2 = calculate_crc(data);
323        assert_eq!(crc1, crc2);
324    }
325
326    #[test]
327    fn test_crc_with_initial_value() {
328        let data = b"hello";
329        let initial = 0x1234567890ABCDEF;
330        let crc_with_initial = calculate_crc_with_initial(data, initial);
331        let crc_from_zero = calculate_crc(data);
332        assert_ne!(crc_with_initial, crc_from_zero);
333    }
334
335    #[test]
336    fn test_empty_data() {
337        let empty: &[u8] = &[];
338        let crc = calculate_crc(empty);
339        assert_eq!(crc, 0);
340    }
341
342    #[test]
343    fn test_verify_crc_valid() {
344        let data = b"OpenIGTLink";
345        let crc = calculate_crc(data);
346        assert!(verify_crc(data, crc));
347    }
348
349    #[test]
350    fn test_verify_crc_invalid() {
351        let data = b"OpenIGTLink";
352        let crc = calculate_crc(data);
353        assert!(!verify_crc(data, crc + 1));
354    }
355
356    #[test]
357    fn test_different_data_different_crc() {
358        let data1 = b"test1";
359        let data2 = b"test2";
360        let crc1 = calculate_crc(data1);
361        let crc2 = calculate_crc(data2);
362        assert_ne!(crc1, crc2);
363    }
364
365    #[test]
366    fn test_single_byte() {
367        let data = b"A";
368        let crc = calculate_crc(data);
369        // CRC should not be zero for non-empty data (in most cases)
370        assert_ne!(crc, 0);
371    }
372
373    #[test]
374    fn test_incremental_crc() {
375        let data = b"hello world";
376        let full_crc = calculate_crc(data);
377
378        // Calculate incrementally
379        let part1_crc = calculate_crc_with_initial(&data[0..5], 0);
380        let full_incremental_crc = calculate_crc_with_initial(&data[5..], part1_crc);
381
382        assert_eq!(full_crc, full_incremental_crc);
383    }
384}