@@ -43,6 +43,8 @@ subroutine collect_hash_functions(testsuite)
4343 , new_unittest(" spooky_hash" , test_spooky_hash) &
4444 , new_unittest(" hash_determinism" , test_hash_determinism) &
4545 , new_unittest(" hash_distribution" , test_hash_distribution) &
46+ , new_unittest(" nmhash32_kat" , test_nmhash32_kat) &
47+ , new_unittest(" nmhash32x_kat" , test_nmhash32x_kat) &
4648 ]
4749
4850 end subroutine collect_hash_functions
@@ -67,6 +69,15 @@ subroutine test_nmhash32(error)
6769 integer (int8) :: key_array(size_key_array)
6870 integer (int32) :: c_hash(0 :size_key_array)
6971
72+ ! The C reference implementation (nmhash.h) does not support
73+ ! big-endian. Skip C-comparison on BE; value-correctness is
74+ ! verified by the test_nmhash32_kat known-answer test instead.
75+ if (.not. little_endian) then
76+ call skip_test(error, &
77+ " NMHASH32 C-comparison skipped on Big-Endian (see KAT test)" )
78+ return
79+ end if
80+
7081 call read_array(" key_array.bin" , key_array )
7182
7283 ! Read hash array generated from key array by the C version of nmhash32
@@ -88,6 +99,15 @@ subroutine test_nmhash32x(error)
8899 integer (int8) :: key_array(size_key_array)
89100 integer (int32) :: c_hash(0 :size_key_array)
90101
102+ ! The C reference implementation (nmhash.h) does not support
103+ ! big-endian. Skip C-comparison on BE; value-correctness is
104+ ! verified by the test_nmhash32x_kat known-answer test instead.
105+ if (.not. little_endian) then
106+ call skip_test(error, &
107+ " NMHASH32X C-comparison skipped on Big-Endian (see KAT test)" )
108+ return
109+ end if
110+
91111 call read_array(" key_array.bin" , key_array )
92112
93113 ! Read hash array generated from key array by the C version of nmhash32x
@@ -269,6 +289,97 @@ subroutine test_hash_distribution(error)
269289 end subroutine test_hash_distribution
270290
271291
292+ ! > Known-Answer Test for NMHASH32.
293+ ! > Verifies the Fortran implementation produces the exact canonical
294+ ! > LE-normalized hash values across all code paths. Reference values
295+ ! > were computed on a little-endian platform using the upstream C code.
296+ ! > This test runs on ALL platforms (LE and BE).
297+ subroutine test_nmhash32_kat (error )
298+ ! > Error handling
299+ type (error_type), allocatable , intent (out ) :: error
300+
301+ ! Number of test vectors
302+ integer , parameter :: num_kat = 14
303+
304+ ! Input lengths covering every code path:
305+ ! 0=zero, 1/2/3/4=small, 7/8=5-8 path, 9/32=9-32 path,
306+ ! 33/100/255=33-255 path, 256/300=long path (256+)
307+ integer , parameter :: kat_lengths(num_kat) = [ &
308+ 0 , 1 , 2 , 3 , 4 , 7 , 8 , &
309+ 9 , 32 , 33 , 100 , 255 , 256 , 300 ]
310+
311+ ! Reference NMHASH32 values (computed on LE with seed=0xDEADBEEF)
312+ integer (int32), parameter :: kat_expected(num_kat) = [ &
313+ int (z' B0D9C845' , int32), int (z' D52AD23F' , int32), &
314+ int (z' E909FDFF' , int32), int (z' FF1A009C' , int32), &
315+ int (z' 097D4183' , int32), int (z' 55CC8BBF' , int32), &
316+ int (z' 660D67B4' , int32), int (z' CB939B94' , int32), &
317+ int (z' 4CBE45F8' , int32), int (z' 2FD88BD0' , int32), &
318+ int (z' 83AC6B02' , int32), int (z' CC0E4E26' , int32), &
319+ int (z' 567D6B58' , int32), int (z' 865F0BC9' , int32) ]
320+
321+ ! Deterministic key: key(i) = IAND(i, 255)
322+ integer (int8) :: key(300 )
323+ integer :: i
324+ integer (int32) :: got
325+
326+ do i = 1 , 300
327+ key(i) = int (iand (i, 255 ), int8)
328+ end do
329+
330+ do i = 1 , num_kat
331+ got = nmhash32(key(1 :kat_lengths(i)), nm_seed)
332+ call check(error, got == kat_expected(i), &
333+ " NMHASH32 KAT failed" )
334+ if (allocated (error)) return
335+ end do
336+
337+ end subroutine test_nmhash32_kat
338+
339+ ! > Known-Answer Test for NMHASH32X.
340+ ! > Same approach as test_nmhash32_kat but for the NMHASH32X variant.
341+ ! > This test runs on ALL platforms (LE and BE).
342+ subroutine test_nmhash32x_kat (error )
343+ ! > Error handling
344+ type (error_type), allocatable , intent (out ) :: error
345+
346+ ! Number of test vectors
347+ integer , parameter :: num_kat = 14
348+
349+ ! Input lengths covering every code path
350+ integer , parameter :: kat_lengths(num_kat) = [ &
351+ 0 , 1 , 2 , 3 , 4 , 7 , 8 , &
352+ 9 , 32 , 33 , 100 , 255 , 256 , 300 ]
353+
354+ ! Reference NMHASH32X values (computed on LE with seed=0xDEADBEEF)
355+ integer (int32), parameter :: kat_expected(num_kat) = [ &
356+ int (z' 76844735' , int32), int (z' B7AE2C90' , int32), &
357+ int (z' EE2224FD' , int32), int (z' BBE39609' , int32), &
358+ int (z' 08467EE3' , int32), int (z' 10E572DA' , int32), &
359+ int (z' 2570CFA8' , int32), int (z' 1A06128A' , int32), &
360+ int (z' EABBF1B8' , int32), int (z' 9B1B3428' , int32), &
361+ int (z' F6F0233D' , int32), int (z' 7EB7CAFC' , int32), &
362+ int (z' B34D6C45' , int32), int (z' E89BEE9E' , int32) ]
363+
364+ ! Deterministic key: key(i) = IAND(i, 255)
365+ integer (int8) :: key(300 )
366+ integer :: i
367+ integer (int32) :: got
368+
369+ do i = 1 , 300
370+ key(i) = int (iand (i, 255 ), int8)
371+ end do
372+
373+ do i = 1 , num_kat
374+ got = nmhash32x(key(1 :kat_lengths(i)), nm_seed)
375+ call check(error, got == kat_expected(i), &
376+ " NMHASH32X KAT failed" )
377+ if (allocated (error)) return
378+ end do
379+
380+ end subroutine test_nmhash32x_kat
381+
382+
272383 subroutine generate_key_array ()
273384
274385 integer :: i, lun
0 commit comments