From fe5627bf83d89c7791693be93ccdfd711abbeeac Mon Sep 17 00:00:00 2001 From: Daniel King Date: Sun, 22 Jun 2025 17:14:24 +0100 Subject: [PATCH 1/2] Add tests to check that reflected and normal tables/polynomials produce equivalent CRCs --- .../unit_tests/src/crc_table_test_suites.adb | 3 + tests/unit_tests/src/reflection_tests.adb | 148 ++++++++++++++++++ tests/unit_tests/src/reflection_tests.ads | 26 +++ 3 files changed, 177 insertions(+) create mode 100644 tests/unit_tests/src/reflection_tests.adb create mode 100644 tests/unit_tests/src/reflection_tests.ads diff --git a/tests/unit_tests/src/crc_table_test_suites.adb b/tests/unit_tests/src/crc_table_test_suites.adb index 713dfa3..a36ff85 100644 --- a/tests/unit_tests/src/crc_table_test_suites.adb +++ b/tests/unit_tests/src/crc_table_test_suites.adb @@ -15,6 +15,7 @@ with LibCRC.Predefined_Constant_Tables; with LibCRC.Predefined_Elaborated_Tables; with Generic_CRC_Table_Tests; +with Reflection_Tests; package body CRC_Table_Test_Suites is @@ -393,6 +394,8 @@ is Table_64_Poly_259C84CBA6426349_Tests.Add_To_Suite (S.all); Table_64_Poly_AD93D23594C93659_Tests.Add_To_Suite (S.all); + Reflection_Tests.Add_To_Suite (S.all); + return S; end Suite; diff --git a/tests/unit_tests/src/reflection_tests.adb b/tests/unit_tests/src/reflection_tests.adb new file mode 100644 index 0000000..cb0e5d3 --- /dev/null +++ b/tests/unit_tests/src/reflection_tests.adb @@ -0,0 +1,148 @@ +-- +-- Copyright 2025 (C) Daniel King +-- +-- SPDX-License-Identifier: Apache-2.0 +-- +with Interfaces; use Interfaces; +with AUnit.Assertions; use AUnit.Assertions; + +with LibCRC; +with LibCRC.CRC_32bit; +with LibCRC.Generic_Nbit_CRCs.Table_Based; +with LibCRC.Generic_Nbit_CRCs.Bitwise; + +package body Reflection_Tests is + + -- Use the CRC-32 polynomial for testing + Test_Polynomial : constant Unsigned_32 := 16#04C11DB7#; + + -- Other parameters for testing + Test_Seed : constant Unsigned_32 := 16#12345678#; + Test_Final_XOR : constant Unsigned_32 := 16#87654321#; + + Test_Table : aliased constant LibCRC.CRC_32bit.CRC_Table_Type := + LibCRC.CRC_32bit.Generate_Table (Test_Polynomial); + + Test_Table_Reflected : + aliased constant LibCRC.CRC_32bit.CRC_Table_Type := + LibCRC.CRC_32bit.Generate_Table_Reflected + (LibCRC.CRC_32bit.Bit_Reverse_CRC (Test_Polynomial)); + + --------------------------- + -- Test_Table_Reflection -- + --------------------------- + + -- Test that equivalent CRCs are output for two table-based CRCs that + -- are identical, except one uses a reflected table and the other a + -- normal (non-reflected) table. + -- + -- The test is performed for all possible combinations of Reflect_Input + -- and Reflect_Output. + + procedure Test_Table_Reflection (T : in out Test_Fixture) is + Test_Data : constant LibCRC.Byte_Array := (1, 2, 3, 4, 5, 255, 254, 253); + + begin + for Reflect_Input in Boolean'Range loop + for Reflect_Output in Boolean'Range loop + declare + package Test_CRC is new LibCRC.CRC_32bit.Table_Based + (Seed => Test_Seed, + Final_XOR => Test_Final_XOR, + Reflect_Input => Reflect_Input, + Reflect_Output => Reflect_Output, + CRC_Table_Reflected => False, + CRC_Table => Test_Table'Access); + + package Test_CRC_Reflected is new LibCRC.CRC_32bit.Table_Based + (Seed => Test_Seed, + Final_XOR => Test_Final_XOR, + Reflect_Input => Reflect_Input, + Reflect_Output => Reflect_Output, + CRC_Table_Reflected => True, + CRC_Table => Test_Table_Reflected'Access); + + CRC_1 : Unsigned_32; + CRC_2 : Unsigned_32; + begin + + CRC_1 := Test_CRC.Calculate (Test_Data); + CRC_2 := Test_CRC_Reflected.Calculate (Test_Data); + + Assert (CRC_1 = CRC_2, + "CRC mismatch for Reflect_Input = " + & Reflect_Input'Image & ", Reflect_Output = " + & Reflect_Output'Image & ":" + & CRC_1'Image & " !=" + & CRC_2'Image); + end; + end loop; + end loop; + end Test_Table_Reflection; + + ----------------------------- + -- Test_Bitwise_Reflection -- + ----------------------------- + + -- Test that equivalent CRCs are output for two bitwise CRCs that + -- are identical, except one uses a reflected polynomial and the other a + -- normal (non-reflected) polynomial. + -- + -- The test is performed for all possible combinations of Reflect_Input + -- and Reflect_Output. + + procedure Test_Bitwise_Reflection (T : in out Test_Fixture) is + Test_Data : constant LibCRC.Byte_Array := (1, 2, 3, 4, 5, 255, 254, 253); + + begin + for Reflect_Input in Boolean'Range loop + for Reflect_Output in Boolean'Range loop + declare + package Test_CRC is new LibCRC.CRC_32bit.Bitwise + (Polynomial => Test_Polynomial, + Reflected_Polynomial => False, + Seed => Test_Seed, + Final_XOR => Test_Final_XOR, + Reflect_Input => Reflect_Input, + Reflect_Output => Reflect_Output); + + package Test_CRC_Reflected is new LibCRC.CRC_32bit.Bitwise + (Polynomial => LibCRC.CRC_32bit.Bit_Reverse_CRC + (Test_Polynomial), + Reflected_Polynomial => True, + Seed => Test_Seed, + Final_XOR => Test_Final_XOR, + Reflect_Input => Reflect_Input, + Reflect_Output => Reflect_Output); + + CRC_1 : Unsigned_32; + CRC_2 : Unsigned_32; + begin + + CRC_1 := Test_CRC.Calculate (Test_Data); + CRC_2 := Test_CRC_Reflected.Calculate (Test_Data); + + Assert (CRC_1 = CRC_2, + "CRC mismatch for Reflect_Input = " + & Reflect_Input'Image & ", Reflect_Output = " + & Reflect_Output'Image & ":" + & CRC_1'Image & " !=" + & CRC_2'Image); + end; + end loop; + end loop; + end Test_Bitwise_Reflection; + + ------------------ + -- Add_To_Suite -- + ------------------ + + procedure Add_To_Suite (S : in out Test_Suite'Class) is + begin + S.Add_Test (Caller.Create ("Test table reflection equivalence", + Test_Table_Reflection'Access)); + S.Add_Test (Caller.Create ("Test bitwise reflection equivalence", + Test_Bitwise_Reflection'Access)); + end Add_To_Suite; + +end Reflection_Tests; \ No newline at end of file diff --git a/tests/unit_tests/src/reflection_tests.ads b/tests/unit_tests/src/reflection_tests.ads new file mode 100644 index 0000000..5536c64 --- /dev/null +++ b/tests/unit_tests/src/reflection_tests.ads @@ -0,0 +1,26 @@ +-- +-- Copyright 2025 (C) Daniel King +-- +-- SPDX-License-Identifier: Apache-2.0 +-- +with AUnit.Test_Fixtures; +with AUnit.Test_Suites; use AUnit.Test_Suites; +with AUnit.Test_Caller; + +-- These tests verify that the CRC computation produces the same output +-- regardless of whether the reflected table or polynomial is used. + +package Reflection_Tests is + + type Test_Fixture is new AUnit.Test_Fixtures.Test_Fixture with null record; + + procedure Test_Table_Reflection (T : in out Test_Fixture); + procedure Test_Bitwise_Reflection (T : in out Test_Fixture); + + procedure Add_To_Suite (S : in out Test_Suite'Class); + +private + + package Caller is new AUnit.Test_Caller (Test_Fixture); + +end Reflection_Tests; \ No newline at end of file From 8c627f0ccccdccc8249b42d7b3e13a7bfd62bfeb Mon Sep 17 00:00:00 2001 From: Daniel King Date: Sun, 22 Jun 2025 17:15:41 +0100 Subject: [PATCH 2/2] Fix bit-reversion logic when outputting final CRC. The logic to determine whether the CRC needed to be bit-reversed was only correct when Reflect_Output = CRC_Table_Reflected, but there were other situations when it was also needed. This defect was highlighted by the recently added tests that check such conditions. --- src/libcrc-generic_nbit_crcs-bitwise.adb | 8 +++----- src/libcrc-generic_nbit_crcs-table_based.adb | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/libcrc-generic_nbit_crcs-bitwise.adb b/src/libcrc-generic_nbit_crcs-bitwise.adb index dbca3d2..e653d3d 100644 --- a/src/libcrc-generic_nbit_crcs-bitwise.adb +++ b/src/libcrc-generic_nbit_crcs-bitwise.adb @@ -100,13 +100,11 @@ is Reason => "Statement has effect for different generic instantiations"); - if Reflect_Output then - if not Reflected_Polynomial then + if Reflect_Output /= Reflected_Polynomial then - pragma Warnings (GNATprove, On, "statement has no effect"); + pragma Warnings (GNATprove, On, "statement has no effect"); - CRC := Bit_Reverse_CRC (CRC); - end if; + CRC := Bit_Reverse_CRC (CRC); end if; return CRC xor Final_XOR; diff --git a/src/libcrc-generic_nbit_crcs-table_based.adb b/src/libcrc-generic_nbit_crcs-table_based.adb index afdda6e..969c53c 100644 --- a/src/libcrc-generic_nbit_crcs-table_based.adb +++ b/src/libcrc-generic_nbit_crcs-table_based.adb @@ -97,13 +97,11 @@ package body LibCRC.Generic_Nbit_CRCs.Table_Based with SPARK_Mode is Reason => "Statement has effect for different generic instantiations"); - if Reflect_Output then - if not CRC_Table_Reflected then + if Reflect_Output /= CRC_Table_Reflected then - pragma Warnings (GNATprove, On, "statement has no effect"); + pragma Warnings (GNATprove, On, "statement has no effect"); - CRC := Bit_Reverse_CRC (CRC); - end if; + CRC := Bit_Reverse_CRC (CRC); end if; return CRC xor Final_XOR;