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
|
//! Will flip the state of any given bit
|
||||||
void FlipBit(const std::size_t index);
|
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)
|
//! 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);
|
[[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)
|
//! Returns 32-bit chunks of data, indexed by matrix coordinates (0-3)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "GCrypt/Block.h"
|
#include "GCrypt/Block.h"
|
||||||
#include <iostream>
|
|
||||||
#include "GCrypt/Config.h"
|
#include "GCrypt/Config.h"
|
||||||
|
#include "GCrypt/Util.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -134,9 +134,7 @@ namespace Leonetienne::GCrypt {
|
|||||||
|
|
||||||
Block& Block::operator^=(const Block& other) {
|
Block& Block::operator^=(const Block& other) {
|
||||||
XorInplace(other);
|
XorInplace(other);
|
||||||
return *this;
|
return *this; }
|
||||||
}
|
|
||||||
|
|
||||||
Block Block::Add(const Block& other) const {
|
Block Block::Add(const Block& other) const {
|
||||||
|
|
||||||
Block m;
|
Block m;
|
||||||
@ -498,6 +496,132 @@ namespace Leonetienne::GCrypt {
|
|||||||
return;
|
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){
|
std::uint32_t& Block::Get(const std::uint8_t row, const std::uint8_t column){
|
||||||
return data[MAT_INDEX(row, column)];
|
return data[MAT_INDEX(row, column)];
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace Leonetienne::GCrypt;
|
using namespace Leonetienne::GCrypt;
|
||||||
|
|
||||||
@ -705,3 +706,125 @@ TEST_CASE(__FILE__"/flip-bit", "[Block]") {
|
|||||||
REQUIRE(a.ToString() == compare);
|
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