diff --git a/GCryptLib/include/GCrypt/Block.h b/GCryptLib/include/GCrypt/Block.h index d6c2b8c..f2d5bc3 100644 --- a/GCryptLib/include/GCrypt/Block.h +++ b/GCryptLib/include/GCrypt/Block.h @@ -126,6 +126,12 @@ namespace Leonetienne::GCrypt { //! Will return the state of any given bit [[nodiscard]] bool GetBit(const std::size_t index) const; + //! Will set the state of any given bit + void SetBit(const std::size_t index, const bool state); + + //! Will flip the state of any given bit + void FlipBit(const std::size_t index); + //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) [[nodiscard]] std::uint32_t& Get(const std::uint8_t row, const std::uint8_t column); //! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3) diff --git a/GCryptLib/src/Block.cpp b/GCryptLib/src/Block.cpp index b2b5660..ac5a648 100644 --- a/GCryptLib/src/Block.cpp +++ b/GCryptLib/src/Block.cpp @@ -455,7 +455,47 @@ namespace Leonetienne::GCrypt { // Fetch bit index relative to that int const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); - return data[intIndex] & (1 << (CHUNK_SIZE_BITS - relBitIndex - 1)); + // Pre-calculate the bitmask to use + const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1); + + return data[intIndex] & bitmask; + } + + void Block::SetBit(const std::size_t index, const bool state) { + // Fetch index of integer the bit is located in + const std::size_t intIndex = index / CHUNK_SIZE_BITS; + + // Fetch bit index relative to that int + const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); + + // Pre-calculate the bitmask to use + const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1); + + // Set the bit + if (state) { + data[intIndex] |= bitmask; + } + // Clear the bit + else { + data[intIndex] &= ~bitmask; + } + + return; + } + + void Block::FlipBit(const std::size_t index) { + // Fetch index of integer the bit is located in + const std::size_t intIndex = index / CHUNK_SIZE_BITS; + + // Fetch bit index relative to that int + const std::size_t relBitIndex = index - (intIndex * CHUNK_SIZE_BITS); + + // Pre-calculate the bitmask to use + const std::size_t bitmask = 1 << (CHUNK_SIZE_BITS - relBitIndex - 1); + + data[intIndex] ^= bitmask; + + return; } std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){ diff --git a/GCryptLib/test/Block.cpp b/GCryptLib/test/Block.cpp index 0a9976b..1de73c9 100644 --- a/GCryptLib/test/Block.cpp +++ b/GCryptLib/test/Block.cpp @@ -648,3 +648,60 @@ TEST_CASE(__FILE__"/get-bit", "[Block]") { REQUIRE(ss.str() == a.ToString()); } +// Tests that the set-bit to-false method works +TEST_CASE(__FILE__"/set-bit-to-false", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + // Exercise + a.SetBit(5, 0); + a.SetBit(15, 0); + a.SetBit(105, 0); + a.SetBit(205, 0); + + // Verify + REQUIRE(a.GetBit(5) == false); + REQUIRE(a.GetBit(15) == false); + REQUIRE(a.GetBit(105) == false); + REQUIRE(a.GetBit(205) == false); +} + +// Tests that the set-bit to-true method works +TEST_CASE(__FILE__"/set-bit-to-true", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + // Exercise + a.SetBit(5, 1); + a.SetBit(15, 1); + a.SetBit(105, 1); + a.SetBit(205, 1); + + // Verify + REQUIRE(a.GetBit(5) == true); + REQUIRE(a.GetBit(15) == true); + REQUIRE(a.GetBit(105) == true); + REQUIRE(a.GetBit(205) == true); +} + +// Tests that the flip-bit method works +TEST_CASE(__FILE__"/flip-bit", "[Block]") { + // Setup + Block a = Key::FromPassword("Halleluja"); + + std::string compare = a.ToString(); + compare[5] = compare[5] == '1' ? '0' : '1'; + compare[15] = compare[15] == '1' ? '0' : '1'; + compare[105] = compare[105] == '1' ? '0' : '1'; + compare[205] = compare[205] == '1' ? '0' : '1'; + + // Exercise + a.FlipBit(5); + a.FlipBit(15); + a.FlipBit(105); + a.FlipBit(205); + + // Verify + REQUIRE(a.ToString() == compare); +} +