Skip to main content

rns_core/
constants.rs

1// =============================================================================
2// Reticulum protocol constants
3// Ported from Python RNS source
4// =============================================================================
5
6// --- From Reticulum.py ---
7
8/// Maximum transmission unit in bytes
9pub const MTU: usize = 500;
10
11/// Truncated hash length in bits
12pub const TRUNCATED_HASHLENGTH: usize = 128;
13
14/// Minimum header size: 2 (flags + hops) + 1 (context) + 16 (dest hash)
15pub const HEADER_MINSIZE: usize = 2 + 1 + (TRUNCATED_HASHLENGTH / 8);
16
17/// Maximum header size: 2 (flags + hops) + 1 (context) + 32 (transport_id + dest hash)
18pub const HEADER_MAXSIZE: usize = 2 + 1 + (TRUNCATED_HASHLENGTH / 8) * 2;
19
20/// Minimum IFAC size
21pub const IFAC_MIN_SIZE: usize = 1;
22
23/// Maximum data unit: MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
24pub const MDU: usize = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE;
25
26// --- From Identity.py ---
27
28/// Full key size in bits (256 X25519 + 256 Ed25519)
29pub const KEYSIZE: usize = 512;
30
31/// Ratchet key size in bits
32pub const RATCHETSIZE: usize = 256;
33
34/// Token overhead in bytes (16 IV + 32 HMAC)
35pub const TOKEN_OVERHEAD: usize = 48;
36
37/// AES-128 block size in bytes
38pub const AES128_BLOCKSIZE: usize = 16;
39
40/// Full hash length in bits (SHA-256)
41pub const HASHLENGTH: usize = 256;
42
43/// Signature length in bits (Ed25519)
44pub const SIGLENGTH: usize = KEYSIZE;
45
46/// Name hash length in bits
47pub const NAME_HASH_LENGTH: usize = 80;
48
49/// Derived key length in bytes
50pub const DERIVED_KEY_LENGTH: usize = 64;
51
52// --- From Packet.py ---
53
54/// Packet types
55pub const PACKET_TYPE_DATA: u8 = 0x00;
56pub const PACKET_TYPE_ANNOUNCE: u8 = 0x01;
57pub const PACKET_TYPE_LINKREQUEST: u8 = 0x02;
58pub const PACKET_TYPE_PROOF: u8 = 0x03;
59
60/// Header types
61pub const HEADER_1: u8 = 0x00;
62pub const HEADER_2: u8 = 0x01;
63
64/// Packet context types
65pub const CONTEXT_NONE: u8 = 0x00;
66pub const CONTEXT_RESOURCE: u8 = 0x01;
67pub const CONTEXT_RESOURCE_ADV: u8 = 0x02;
68pub const CONTEXT_RESOURCE_REQ: u8 = 0x03;
69pub const CONTEXT_RESOURCE_HMU: u8 = 0x04;
70pub const CONTEXT_RESOURCE_PRF: u8 = 0x05;
71pub const CONTEXT_RESOURCE_ICL: u8 = 0x06;
72pub const CONTEXT_RESOURCE_RCL: u8 = 0x07;
73pub const CONTEXT_CACHE_REQUEST: u8 = 0x08;
74pub const CONTEXT_REQUEST: u8 = 0x09;
75pub const CONTEXT_RESPONSE: u8 = 0x0A;
76pub const CONTEXT_PATH_RESPONSE: u8 = 0x0B;
77pub const CONTEXT_COMMAND: u8 = 0x0C;
78pub const CONTEXT_COMMAND_STATUS: u8 = 0x0D;
79pub const CONTEXT_CHANNEL: u8 = 0x0E;
80pub const CONTEXT_KEEPALIVE: u8 = 0xFA;
81pub const CONTEXT_LINKIDENTIFY: u8 = 0xFB;
82pub const CONTEXT_LINKCLOSE: u8 = 0xFC;
83pub const CONTEXT_LINKPROOF: u8 = 0xFD;
84pub const CONTEXT_LRRTT: u8 = 0xFE;
85pub const CONTEXT_LRPROOF: u8 = 0xFF;
86
87/// Context flag values
88pub const FLAG_SET: u8 = 0x01;
89pub const FLAG_UNSET: u8 = 0x00;
90
91/// Encrypted MDU: floor((MDU - TOKEN_OVERHEAD - KEYSIZE/16) / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
92pub const ENCRYPTED_MDU: usize = {
93    let numerator = MDU - TOKEN_OVERHEAD - KEYSIZE / 16;
94    (numerator / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
95};
96
97/// Plain MDU (same as MDU)
98pub const PLAIN_MDU: usize = MDU;
99
100/// Explicit proof length: HASHLENGTH/8 + SIGLENGTH/8 = 32 + 64 = 96
101pub const EXPL_LENGTH: usize = HASHLENGTH / 8 + SIGLENGTH / 8;
102
103/// Implicit proof length: SIGLENGTH/8 = 64
104pub const IMPL_LENGTH: usize = SIGLENGTH / 8;
105
106/// Receipt status constants
107pub const RECEIPT_FAILED: u8 = 0x00;
108pub const RECEIPT_SENT: u8 = 0x01;
109pub const RECEIPT_DELIVERED: u8 = 0x02;
110pub const RECEIPT_CULLED: u8 = 0xFF;
111
112// --- From Destination.py ---
113
114/// Destination types
115pub const DESTINATION_SINGLE: u8 = 0x00;
116pub const DESTINATION_GROUP: u8 = 0x01;
117pub const DESTINATION_PLAIN: u8 = 0x02;
118pub const DESTINATION_LINK: u8 = 0x03;
119
120/// Destination directions
121pub const DESTINATION_IN: u8 = 0x11;
122pub const DESTINATION_OUT: u8 = 0x12;
123
124// --- From Transport.py ---
125
126/// Transport types
127pub const TRANSPORT_BROADCAST: u8 = 0x00;
128pub const TRANSPORT_TRANSPORT: u8 = 0x01;
129pub const TRANSPORT_RELAY: u8 = 0x02;
130pub const TRANSPORT_TUNNEL: u8 = 0x03;
131
132/// Maximum hops
133pub const PATHFINDER_M: u8 = 128;
134
135// --- PATHFINDER algorithm ---
136
137/// Retransmit retries (total sends = PATHFINDER_R + 1)
138pub const PATHFINDER_R: u8 = 1;
139
140/// Grace period between retries (seconds)
141pub const PATHFINDER_G: f64 = 5.0;
142
143/// Random window for announce rebroadcast (seconds)
144pub const PATHFINDER_RW: f64 = 0.5;
145
146/// Path expiry = 7 days (seconds)
147pub const PATHFINDER_E: f64 = 604800.0;
148
149// --- Path expiry by interface mode ---
150
151/// Access Point path expiry = 1 day
152pub const AP_PATH_TIME: f64 = 86400.0;
153
154/// Roaming path expiry = 6 hours
155pub const ROAMING_PATH_TIME: f64 = 21600.0;
156
157// --- Announce bandwidth cap ---
158
159/// Default announce bandwidth cap (2% of interface bandwidth)
160pub const ANNOUNCE_CAP: f64 = 0.02;
161
162/// Maximum queued announces per interface
163pub const MAX_QUEUED_ANNOUNCES: usize = 16384;
164
165/// Queued announce lifetime (24 hours)
166pub const QUEUED_ANNOUNCE_LIFE: f64 = 86400.0;
167
168// --- Table limits ---
169
170/// How many local rebroadcasts of an announce is allowed
171pub const LOCAL_REBROADCASTS_MAX: u8 = 2;
172
173/// Maximum number of random blobs per destination to keep in memory
174pub const MAX_RANDOM_BLOBS: usize = 64;
175
176/// Maximum number of announce timestamps to keep per destination
177pub const MAX_RATE_TIMESTAMPS: usize = 16;
178
179/// Maximum packet hashlist size before rotation
180pub const HASHLIST_MAXSIZE: usize = 1_000_000;
181
182// --- Timeouts ---
183
184/// Reverse table entry timeout (8 minutes)
185pub const REVERSE_TIMEOUT: f64 = 480.0;
186
187/// Destination table entry timeout (7 days)
188pub const DESTINATION_TIMEOUT: f64 = 604800.0;
189
190/// Link stale time = 2 * KEEPALIVE(360) = 720 seconds
191pub const LINK_STALE_TIME: f64 = 720.0;
192
193/// Link timeout = STALE_TIME * 1.25 = 900 seconds
194pub const LINK_TIMEOUT: f64 = 900.0;
195
196/// Link establishment timeout per hop (seconds)
197pub const LINK_ESTABLISHMENT_TIMEOUT_PER_HOP: f64 = 6.0;
198
199// --- Path request ---
200
201/// Default timeout for path requests (seconds)
202pub const PATH_REQUEST_TIMEOUT: f64 = 15.0;
203
204/// Grace time before a path announcement is made (seconds)
205pub const PATH_REQUEST_GRACE: f64 = 0.4;
206
207/// Extra grace time for roaming-mode interfaces (seconds)
208pub const PATH_REQUEST_RG: f64 = 1.5;
209
210/// Minimum interval for automated path requests (seconds)
211pub const PATH_REQUEST_MI: f64 = 20.0;
212
213/// Maximum amount of unique path request tags to remember
214pub const MAX_PR_TAGS: usize = 32000;
215
216// --- Job intervals ---
217
218/// Announce check interval (seconds)
219pub const ANNOUNCES_CHECK_INTERVAL: f64 = 1.0;
220
221/// Table culling interval (seconds)
222pub const TABLES_CULL_INTERVAL: f64 = 5.0;
223
224/// Link check interval (seconds)
225pub const LINKS_CHECK_INTERVAL: f64 = 1.0;
226
227// --- Interface modes (from Interface.py) ---
228
229pub const MODE_FULL: u8 = 0x01;
230pub const MODE_POINT_TO_POINT: u8 = 0x02;
231pub const MODE_ACCESS_POINT: u8 = 0x03;
232pub const MODE_ROAMING: u8 = 0x04;
233pub const MODE_BOUNDARY: u8 = 0x05;
234pub const MODE_GATEWAY: u8 = 0x06;
235
236// --- Path states ---
237
238pub const STATE_UNKNOWN: u8 = 0x00;
239pub const STATE_UNRESPONSIVE: u8 = 0x01;
240pub const STATE_RESPONSIVE: u8 = 0x02;
241
242// --- From Link.py ---
243
244/// Link ephemeral public key size: 32 (X25519) + 32 (Ed25519)
245pub const LINK_ECPUBSIZE: usize = 64;
246
247/// Link key size in bytes
248pub const LINK_KEYSIZE: usize = 32;
249
250/// Link MTU signalling bytes size
251pub const LINK_MTU_SIZE: usize = 3;
252
253/// Maximum keepalive interval in seconds
254pub const LINK_KEEPALIVE_MAX: f64 = 360.0;
255
256/// Minimum keepalive interval in seconds
257pub const LINK_KEEPALIVE_MIN: f64 = 5.0;
258
259/// Maximum RTT used for keepalive scaling
260pub const LINK_KEEPALIVE_MAX_RTT: f64 = 1.75;
261
262/// RTT timeout factor for stale→close transition
263pub const LINK_KEEPALIVE_TIMEOUT_FACTOR: f64 = 4.0;
264
265/// Grace period for stale→close transition
266pub const LINK_STALE_GRACE: f64 = 5.0;
267
268/// Factor to compute stale_time from keepalive
269pub const LINK_STALE_FACTOR: f64 = 2.0;
270
271/// Traffic timeout factor
272pub const LINK_TRAFFIC_TIMEOUT_FACTOR: f64 = 6.0;
273
274/// Link MDU: floor((MTU - IFAC_MIN_SIZE - HEADER_MINSIZE - TOKEN_OVERHEAD) / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
275pub const LINK_MDU: usize = {
276    let numerator = MTU - IFAC_MIN_SIZE - HEADER_MINSIZE - TOKEN_OVERHEAD;
277    (numerator / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
278};
279
280/// Link MTU bytemask (21-bit MTU field)
281pub const LINK_MTU_BYTEMASK: u32 = 0x1FFFFF;
282
283/// Link mode bytemask (3-bit mode field in upper byte)
284pub const LINK_MODE_BYTEMASK: u8 = 0xE0;
285
286// --- From Channel.py ---
287
288/// Initial window size at channel setup
289pub const CHANNEL_WINDOW: u16 = 2;
290
291/// Absolute minimum window size
292pub const CHANNEL_WINDOW_MIN: u16 = 2;
293
294/// Minimum window limit for slow links
295pub const CHANNEL_WINDOW_MIN_LIMIT_SLOW: u16 = 2;
296
297/// Minimum window limit for medium-speed links
298pub const CHANNEL_WINDOW_MIN_LIMIT_MEDIUM: u16 = 5;
299
300/// Minimum window limit for fast links
301pub const CHANNEL_WINDOW_MIN_LIMIT_FAST: u16 = 16;
302
303/// Maximum window size for slow links
304pub const CHANNEL_WINDOW_MAX_SLOW: u16 = 5;
305
306/// Maximum window size for medium-speed links
307pub const CHANNEL_WINDOW_MAX_MEDIUM: u16 = 12;
308
309/// Maximum window size for fast links
310pub const CHANNEL_WINDOW_MAX_FAST: u16 = 48;
311
312/// Minimum flexibility between window_max and window_min
313pub const CHANNEL_WINDOW_FLEXIBILITY: u16 = 4;
314
315/// Maximum sequence number
316pub const CHANNEL_SEQ_MAX: u16 = 0xFFFF;
317
318/// Sequence number modulus
319pub const CHANNEL_SEQ_MODULUS: u32 = 0x10000;
320
321/// Maximum number of send tries per envelope
322pub const CHANNEL_MAX_TRIES: u8 = 5;
323
324/// RTT threshold for fast links
325pub const CHANNEL_RTT_FAST: f64 = 0.18;
326
327/// RTT threshold for medium links
328pub const CHANNEL_RTT_MEDIUM: f64 = 0.75;
329
330/// RTT threshold for slow links
331pub const CHANNEL_RTT_SLOW: f64 = 1.45;
332
333/// Number of consecutive fast rounds to upgrade window
334pub const CHANNEL_FAST_RATE_THRESHOLD: u16 = 10;
335
336/// Channel envelope overhead: msgtype(2) + seq(2) + len(2)
337pub const CHANNEL_ENVELOPE_OVERHEAD: usize = 6;
338
339// --- From Buffer.py ---
340
341/// System message type for stream data
342pub const STREAM_DATA_MSGTYPE: u16 = 0xFF00;
343
344/// Maximum stream ID (14 bits)
345pub const STREAM_ID_MAX: u16 = 0x3FFF;
346
347/// Stream data overhead: 2 (stream header) + 6 (channel envelope)
348pub const STREAM_DATA_OVERHEAD: usize = 2 + CHANNEL_ENVELOPE_OVERHEAD;
349
350// --- From Resource.py ---
351
352/// Initial window size at beginning of transfer
353pub const RESOURCE_WINDOW: usize = 4;
354
355/// Absolute minimum window size during transfer
356pub const RESOURCE_WINDOW_MIN: usize = 2;
357
358/// Maximum window size for slow links
359pub const RESOURCE_WINDOW_MAX_SLOW: usize = 10;
360
361/// Maximum window size for very slow links
362pub const RESOURCE_WINDOW_MAX_VERY_SLOW: usize = 4;
363
364/// Maximum window size for fast links
365pub const RESOURCE_WINDOW_MAX_FAST: usize = 75;
366
367/// Global maximum window (for calculations)
368pub const RESOURCE_WINDOW_MAX: usize = RESOURCE_WINDOW_MAX_FAST;
369
370/// Minimum flexibility between window_max and window_min
371pub const RESOURCE_WINDOW_FLEXIBILITY: usize = 4;
372
373/// Sustained fast-rate rounds before enabling fast window
374/// = WINDOW_MAX_SLOW - WINDOW - 2 = 10 - 4 - 2 = 4
375pub const RESOURCE_FAST_RATE_THRESHOLD: usize = RESOURCE_WINDOW_MAX_SLOW - RESOURCE_WINDOW - 2;
376
377/// Sustained very-slow-rate rounds before capping to very slow
378pub const RESOURCE_VERY_SLOW_RATE_THRESHOLD: usize = 2;
379
380/// Fast rate threshold: 50 Kbps in bytes/sec = 50000 / 8 = 6250.0
381pub const RESOURCE_RATE_FAST: f64 = (50 * 1000) as f64 / 8.0;
382
383/// Very slow rate threshold: 2 Kbps in bytes/sec = 2000 / 8 = 250.0
384pub const RESOURCE_RATE_VERY_SLOW: f64 = (2 * 1000) as f64 / 8.0;
385
386/// Number of bytes in a map hash
387pub const RESOURCE_MAPHASH_LEN: usize = 4;
388
389/// Resource SDU = Packet.MDU (NOT ENCRYPTED_MDU)
390pub const RESOURCE_SDU: usize = MDU;
391
392/// Random hash size prepended to resource data
393pub const RESOURCE_RANDOM_HASH_SIZE: usize = 4;
394
395/// Maximum efficient resource size (1 MB - 1)
396pub const RESOURCE_MAX_EFFICIENT_SIZE: usize = 1 * 1024 * 1024 - 1;
397
398/// Maximum metadata size (16 MB - 1)
399pub const RESOURCE_METADATA_MAX_SIZE: usize = 16 * 1024 * 1024 - 1;
400
401/// Maximum auto-compress size (64 MB)
402pub const RESOURCE_AUTO_COMPRESS_MAX_SIZE: usize = 64 * 1024 * 1024;
403
404/// Part timeout factor (before RTT measured)
405pub const RESOURCE_PART_TIMEOUT_FACTOR: f64 = 4.0;
406
407/// Part timeout factor (after first RTT measured)
408pub const RESOURCE_PART_TIMEOUT_FACTOR_AFTER_RTT: f64 = 2.0;
409
410/// Proof timeout factor (reduced when awaiting proof)
411pub const RESOURCE_PROOF_TIMEOUT_FACTOR: f64 = 3.0;
412
413/// Maximum retries for part transfers
414pub const RESOURCE_MAX_RETRIES: usize = 16;
415
416/// Maximum retries for advertisement
417pub const RESOURCE_MAX_ADV_RETRIES: usize = 4;
418
419/// Sender grace time (seconds)
420pub const RESOURCE_SENDER_GRACE_TIME: f64 = 10.0;
421
422/// Processing grace for advertisement response (seconds)
423pub const RESOURCE_PROCESSING_GRACE: f64 = 1.0;
424
425/// Retry grace time (seconds)
426pub const RESOURCE_RETRY_GRACE_TIME: f64 = 0.25;
427
428/// Per-retry delay (seconds)
429pub const RESOURCE_PER_RETRY_DELAY: f64 = 0.5;
430
431/// Maximum watchdog sleep interval (seconds)
432pub const RESOURCE_WATCHDOG_MAX_SLEEP: f64 = 1.0;
433
434/// Response max grace time (seconds)
435pub const RESOURCE_RESPONSE_MAX_GRACE_TIME: f64 = 10.0;
436
437/// Advertisement overhead in bytes (fixed msgpack overhead)
438pub const RESOURCE_ADVERTISEMENT_OVERHEAD: usize = 134;
439
440/// Maximum hashmap entries per advertisement segment
441/// = floor((LINK_MDU - ADVERTISEMENT_OVERHEAD) / MAPHASH_LEN)
442pub const RESOURCE_HASHMAP_MAX_LEN: usize = (LINK_MDU - RESOURCE_ADVERTISEMENT_OVERHEAD) / RESOURCE_MAPHASH_LEN;
443
444/// Collision guard size = 2 * WINDOW_MAX + HASHMAP_MAX_LEN
445pub const RESOURCE_COLLISION_GUARD_SIZE: usize = 2 * RESOURCE_WINDOW_MAX + RESOURCE_HASHMAP_MAX_LEN;
446
447/// Hashmap not exhausted flag
448pub const RESOURCE_HASHMAP_IS_NOT_EXHAUSTED: u8 = 0x00;
449
450/// Hashmap exhausted flag
451pub const RESOURCE_HASHMAP_IS_EXHAUSTED: u8 = 0xFF;
452
453#[cfg(test)]
454mod tests {
455    use super::*;
456
457    #[test]
458    fn test_derived_constants() {
459        // MTU = 500
460        assert_eq!(MTU, 500);
461
462        // HEADER_MINSIZE = 2 + 1 + 16 = 19
463        assert_eq!(HEADER_MINSIZE, 19);
464
465        // HEADER_MAXSIZE = 2 + 1 + 32 = 35
466        assert_eq!(HEADER_MAXSIZE, 35);
467
468        // MDU = 500 - 35 - 1 = 464
469        assert_eq!(MDU, 464);
470
471        // ENCRYPTED_MDU = floor((464 - 48 - 32) / 16) * 16 - 1 = floor(384/16)*16 - 1 = 24*16 - 1 = 383
472        assert_eq!(ENCRYPTED_MDU, 383);
473
474        // PLAIN_MDU = MDU = 464
475        assert_eq!(PLAIN_MDU, 464);
476
477        // EXPL_LENGTH = 32 + 64 = 96
478        assert_eq!(EXPL_LENGTH, 96);
479
480        // IMPL_LENGTH = 64
481        assert_eq!(IMPL_LENGTH, 64);
482
483        // NAME_HASH_LENGTH = 80 bits = 10 bytes
484        assert_eq!(NAME_HASH_LENGTH / 8, 10);
485
486        // KEYSIZE = 512 bits = 64 bytes
487        assert_eq!(KEYSIZE / 8, 64);
488
489        // SIGLENGTH = 512 bits = 64 bytes
490        assert_eq!(SIGLENGTH / 8, 64);
491
492        // TRUNCATED_HASHLENGTH = 128 bits = 16 bytes
493        assert_eq!(TRUNCATED_HASHLENGTH / 8, 16);
494    }
495
496    #[test]
497    fn test_link_constants() {
498        assert_eq!(LINK_ECPUBSIZE, 64);
499        assert_eq!(LINK_MTU_SIZE, 3);
500        // LINK_MDU = floor((500 - 1 - 19 - 48) / 16) * 16 - 1 = floor(432/16)*16 - 1 = 27*16 - 1 = 431
501        assert_eq!(LINK_MDU, 431);
502        assert_eq!(CHANNEL_ENVELOPE_OVERHEAD, 6);
503        assert_eq!(STREAM_DATA_OVERHEAD, 8);
504        assert_eq!(STREAM_ID_MAX, 0x3FFF);
505    }
506
507    #[test]
508    fn test_transport_constants() {
509        // PATHFINDER_E = 7 days in seconds
510        assert_eq!(PATHFINDER_E, 60.0 * 60.0 * 24.0 * 7.0);
511
512        // AP_PATH_TIME = 1 day
513        assert_eq!(AP_PATH_TIME, 60.0 * 60.0 * 24.0);
514
515        // ROAMING_PATH_TIME = 6 hours
516        assert_eq!(ROAMING_PATH_TIME, 60.0 * 60.0 * 6.0);
517
518        // LINK_STALE_TIME = 2 * 360
519        assert_eq!(LINK_STALE_TIME, 720.0);
520
521        // LINK_TIMEOUT = STALE_TIME * 1.25
522        assert_eq!(LINK_TIMEOUT, LINK_STALE_TIME * 1.25);
523
524        // REVERSE_TIMEOUT = 8 minutes
525        assert_eq!(REVERSE_TIMEOUT, 8.0 * 60.0);
526
527        // DESTINATION_TIMEOUT = 7 days
528        assert_eq!(DESTINATION_TIMEOUT, 60.0 * 60.0 * 24.0 * 7.0);
529    }
530
531    #[test]
532    fn test_resource_constants() {
533        // SDU = MDU = 464 (NOT ENCRYPTED_MDU)
534        assert_eq!(RESOURCE_SDU, 464);
535        assert_eq!(RESOURCE_SDU, MDU);
536
537        // FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2 = 10 - 4 - 2 = 4
538        assert_eq!(RESOURCE_FAST_RATE_THRESHOLD, 4);
539
540        // RATE_FAST = 50000 / 8 = 6250.0
541        assert_eq!(RESOURCE_RATE_FAST, 6250.0);
542
543        // RATE_VERY_SLOW = 2000 / 8 = 250.0
544        assert_eq!(RESOURCE_RATE_VERY_SLOW, 250.0);
545
546        // HASHMAP_MAX_LEN = floor((431 - 134) / 4) = floor(297/4) = 74
547        assert_eq!(RESOURCE_HASHMAP_MAX_LEN, 74);
548
549        // COLLISION_GUARD_SIZE = 2 * 75 + 74 = 224
550        assert_eq!(RESOURCE_COLLISION_GUARD_SIZE, 224);
551
552        // Window constants
553        assert_eq!(RESOURCE_WINDOW, 4);
554        assert_eq!(RESOURCE_WINDOW_MIN, 2);
555        assert_eq!(RESOURCE_WINDOW_MAX_SLOW, 10);
556        assert_eq!(RESOURCE_WINDOW_MAX_VERY_SLOW, 4);
557        assert_eq!(RESOURCE_WINDOW_MAX_FAST, 75);
558        assert_eq!(RESOURCE_WINDOW_MAX, 75);
559        assert_eq!(RESOURCE_WINDOW_FLEXIBILITY, 4);
560    }
561}