Added bitshift methods to block class
This commit is contained in:
parent
9a9cd05bed
commit
b5369a3c32
@ -132,6 +132,18 @@ namespace Leonetienne::GCrypt {
|
||||
//! Will flip the state of any given bit
|
||||
void FlipBit(const std::size_t index);
|
||||
|
||||
//! Will shift all bits to the left by 1
|
||||
[[nodiscard]] Block ShiftBitsLeft() const;
|
||||
|
||||
//! Will shift all bits to the left by 1, inplace
|
||||
void ShiftBitsLeftInplace();
|
||||
|
||||
//! Will shift all bits to the right by 1
|
||||
[[nodiscard]] Block ShiftBitsRight() const;
|
||||
|
||||
//! Will shift all bits to the right by 1, inplace
|
||||
void ShiftBitsRightInplace();
|
||||
|
||||
//! 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)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "GCrypt/Block.h"
|
||||
#include <iostream>
|
||||
#include "GCrypt/Config.h"
|
||||
#include "GCrypt/Util.h"
|
||||
#include <sstream>
|
||||
#include <bitset>
|
||||
#include <cassert>
|
||||
@ -134,9 +134,7 @@ namespace Leonetienne::GCrypt {
|
||||
|
||||
Block& Block::operator^=(const Block& other) {
|
||||
XorInplace(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
return *this; }
|
||||
Block Block::Add(const Block& other) const {
|
||||
|
||||
Block m;
|
||||
@ -498,6 +496,132 @@ namespace Leonetienne::GCrypt {
|
||||
return;
|
||||
}
|
||||
|
||||
Block Block::ShiftBitsLeft() const {
|
||||
Block b;
|
||||
|
||||
// First, copy this block over
|
||||
b = *this;
|
||||
|
||||
// Then, shift all integers individually
|
||||
for (std::size_t i = 0; i < data.size(); i++) {
|
||||
b.data[i] <<= 1;
|
||||
}
|
||||
|
||||
// Current state: the LSB is zero everywhere. We have to carry
|
||||
// it over manually from the previous state.
|
||||
|
||||
// Carry over the MSB of data[i] to LSB of data[i-1]
|
||||
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
|
||||
constexpr std::size_t bitmaskLsb = 1;
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
const bool msb = data[i] & bitmaskMsb;
|
||||
|
||||
// Set the lsb
|
||||
if (msb) {
|
||||
b.data[Mod(i-1, data.size())] |= bitmaskLsb;
|
||||
}
|
||||
// Clear the lsb
|
||||
else {
|
||||
b.data[Mod(i-1, data.size())] &= ~bitmaskLsb;
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void Block::ShiftBitsLeftInplace() {
|
||||
Block tmp = *this;
|
||||
|
||||
// Then, shift all integers individually
|
||||
for (std::size_t i = 0; i < data.size(); i++) {
|
||||
data[i] <<= 1;
|
||||
}
|
||||
|
||||
// Current state: the LSB is zero everywhere. We have to carry
|
||||
// it over manually from the previous state.
|
||||
|
||||
// Carry over the MSB of data[i] to LSB of data[i-1]
|
||||
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
|
||||
constexpr std::size_t bitmaskLsb = 1;
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
const bool msb = tmp.data[i] & bitmaskMsb;
|
||||
|
||||
// Set the lsb
|
||||
if (msb) {
|
||||
data[Mod(i-1, data.size())] |= bitmaskLsb;
|
||||
}
|
||||
// Clear the lsb
|
||||
else {
|
||||
data[Mod(i-1, data.size())] &= ~bitmaskLsb;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Block Block::ShiftBitsRight() const {
|
||||
Block b;
|
||||
|
||||
// First, copy this block over
|
||||
b = *this;
|
||||
|
||||
// Then, shift all integers individually
|
||||
for (std::size_t i = 0; i < data.size(); i++) {
|
||||
b.data[i] >>= 1;
|
||||
}
|
||||
|
||||
// Current state: the LSB is zero everywhere. We have to carry
|
||||
// it over manually from the previous state.
|
||||
|
||||
// Carry over the LSB of data[i] to MSB of data[i+1]
|
||||
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
|
||||
constexpr std::size_t bitmaskLsb = 1;
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
const bool lsb = data[i] & bitmaskLsb;
|
||||
|
||||
// Set the msb
|
||||
if (lsb) {
|
||||
b.data[Mod(i+1, data.size())] |= bitmaskMsb;
|
||||
}
|
||||
// Clear the msb
|
||||
else {
|
||||
b.data[Mod(i+1, data.size())] &= ~bitmaskMsb;
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void Block::ShiftBitsRightInplace() {
|
||||
Block tmp = *this;
|
||||
|
||||
// Then, shift all integers individually
|
||||
for (std::size_t i = 0; i < data.size(); i++) {
|
||||
data[i] >>= 1;
|
||||
}
|
||||
|
||||
// Current state: the LSB is zero everywhere. We have to carry
|
||||
// it over manually from the previous state.
|
||||
|
||||
// Carry over the LSB of data[i] to MSB of data[i+1]
|
||||
constexpr std::size_t bitmaskMsb = 1 << (CHUNK_SIZE_BITS - 1);
|
||||
constexpr std::size_t bitmaskLsb = 1;
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
const bool lsb = tmp.data[i] & bitmaskLsb;
|
||||
|
||||
// Set the msb
|
||||
if (lsb) {
|
||||
data[Mod(i+1, data.size())] |= bitmaskMsb;
|
||||
}
|
||||
// Clear the msb
|
||||
else {
|
||||
data[Mod(i+1, data.size())] &= ~bitmaskMsb;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){
|
||||
return data[MAT_INDEX(row, column)];
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <cstdlib>
|
||||
#include <time.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace Leonetienne::GCrypt;
|
||||
|
||||
@ -705,3 +706,125 @@ TEST_CASE(__FILE__"/flip-bit", "[Block]") {
|
||||
REQUIRE(a.ToString() == compare);
|
||||
}
|
||||
|
||||
// Tests that bitshifts (to the left) work
|
||||
TEST_CASE(__FILE__"/bitshift-left", "[Block]") {
|
||||
|
||||
// Setup
|
||||
srand(time(0));
|
||||
std::stringstream ss;
|
||||
|
||||
for (std::size_t i = 0; i < 512; i++) {
|
||||
ss << (rand()%2 == 0 ? '1' : '0');
|
||||
}
|
||||
const std::string originalBits = ss.str();
|
||||
ss.str("");
|
||||
|
||||
// Shift string manually
|
||||
std::string shiftedBits = originalBits;
|
||||
shiftedBits.erase(0, 1);
|
||||
ss << shiftedBits << originalBits[0];
|
||||
shiftedBits = ss.str();
|
||||
|
||||
// Create block of original bits
|
||||
Block block(originalBits);
|
||||
|
||||
// Exercise
|
||||
block = block.ShiftBitsLeft();
|
||||
|
||||
// Verify
|
||||
REQUIRE(block.ToString().length() == shiftedBits.length());
|
||||
REQUIRE(block.ToString() == shiftedBits);
|
||||
}
|
||||
|
||||
// Tests that inplace-bitshifts to the left do the exact same as copy bitshifts
|
||||
TEST_CASE(__FILE__"/bitshift-left-inplace", "[Block]") {
|
||||
|
||||
// Setup
|
||||
srand(time(0));
|
||||
std::stringstream ss;
|
||||
|
||||
for (std::size_t i = 0; i < 512; i++) {
|
||||
ss << (rand()%2 == 0 ? '1' : '0');
|
||||
}
|
||||
Block a(ss.str());
|
||||
|
||||
// Exercise
|
||||
Block b = a.ShiftBitsLeft();
|
||||
a.ShiftBitsLeftInplace();
|
||||
|
||||
// Verify
|
||||
REQUIRE(a == b);
|
||||
}
|
||||
|
||||
// Tests that bitshifts (to the right) work
|
||||
TEST_CASE(__FILE__"/bitshift-right", "[Block]") {
|
||||
|
||||
// Setup
|
||||
srand(time(0));
|
||||
std::stringstream ss;
|
||||
|
||||
for (std::size_t i = 0; i < 512; i++) {
|
||||
ss << (rand()%2 == 0 ? '1' : '0');
|
||||
}
|
||||
const std::string originalBits = ss.str();
|
||||
ss.str("");
|
||||
|
||||
// Shift string manually
|
||||
std::string shiftedBits = originalBits;
|
||||
shiftedBits.erase(shiftedBits.length() - 1);
|
||||
ss << originalBits[originalBits.length()-1] << shiftedBits;
|
||||
shiftedBits = ss.str();
|
||||
|
||||
// Create block of original bits
|
||||
Block block(originalBits);
|
||||
|
||||
// Exercise
|
||||
block = block.ShiftBitsRight();
|
||||
|
||||
// Verify
|
||||
REQUIRE(block.ToString().length() == shiftedBits.length());
|
||||
REQUIRE(block.ToString() == shiftedBits);
|
||||
}
|
||||
|
||||
// Tests that inplace-bitshifts to the right do the exact same as copy bitshifts
|
||||
TEST_CASE(__FILE__"/bitshift-right-inplace", "[Block]") {
|
||||
|
||||
// Setup
|
||||
srand(time(0));
|
||||
std::stringstream ss;
|
||||
|
||||
for (std::size_t i = 0; i < 512; i++) {
|
||||
ss << (rand()%2 == 0 ? '1' : '0');
|
||||
}
|
||||
Block a(ss.str());
|
||||
|
||||
// Exercise
|
||||
Block b = a.ShiftBitsRight();
|
||||
a.ShiftBitsRightInplace();
|
||||
|
||||
// Verify
|
||||
REQUIRE(a == b);
|
||||
}
|
||||
|
||||
// Tests that bitshifting undoes itself
|
||||
TEST_CASE(__FILE__"/bitshifting-undoes-itself", "[Block]") {
|
||||
|
||||
// Setup
|
||||
Block a = Key::FromPassword("Halleluja");
|
||||
|
||||
const Block initial_a = a;
|
||||
|
||||
// Exercise (mix-up)
|
||||
for (std::size_t i = 0; i < 100; i++) {
|
||||
a.ShiftBitsLeftInplace();
|
||||
}
|
||||
|
||||
// Exercise (un-mix)
|
||||
for (std::size_t i = 0; i < 100; i++) {
|
||||
a.ShiftBitsRightInplace();
|
||||
}
|
||||
|
||||
// Verify
|
||||
REQUIRE(a == initial_a);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user