Skip to content

Commit

Permalink
add ct_reverse_bits<>
Browse files Browse the repository at this point in the history
Co-Authored-By: Fabian Albert <fabian.albert@rohde-schwarz.com>
  • Loading branch information
reneme and FAlbertDev committed Jul 12, 2024
1 parent 5171cc3 commit 60bd9fb
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/lib/utils/bit_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include <botan/types.h>

#include <botan/internal/bswap.h>

namespace Botan {

/**
Expand Down Expand Up @@ -217,6 +219,29 @@ inline constexpr T majority(T a, T b, T c) {
return choose(a ^ b, c, b);
}

/**
* @returns the reversed bits in @p b.
*/
template <std::unsigned_integral T>
constexpr T ct_reverse_bits(T b) {
auto extend = [](uint8_t m) -> T {
T mask = 0;
for(size_t i = 0; i < sizeof(T); ++i) {
mask |= T(m) << i * 8;
}
return mask;
};

// First reverse bits in each byte...
// From: https://stackoverflow.com/a/2602885
b = (b & extend(0xF0)) >> 4 | (b & extend(0x0F)) << 4;
b = (b & extend(0xCC)) >> 2 | (b & extend(0x33)) << 2;
b = (b & extend(0xAA)) >> 1 | (b & extend(0x55)) << 1;

// ... then swap the bytes
return reverse_bytes(b);
}

/**
* Calculates the number of 1-bits in an unsigned integer in constant-time.
* This operation is also known as "population count" or hamming weight.
Expand Down
29 changes: 29 additions & 0 deletions src/tests/test_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ class BitOps_Tests final : public Test {
results.push_back(test_ctz());
results.push_back(test_sig_bytes());
results.push_back(test_popcount());
results.push_back(test_reverse_bits());

return results;
}
Expand Down Expand Up @@ -899,6 +900,34 @@ class BitOps_Tests final : public Test {

return result;
}

Test::Result test_reverse_bits() {
Test::Result result("reverse_bits");

result.test_is_eq<uint8_t>("rev(0u8)", Botan::ct_reverse_bits<uint8_t>(0b00000000), 0b00000000);
result.test_is_eq<uint8_t>("rev(1u8)", Botan::ct_reverse_bits<uint8_t>(0b01010101), 0b10101010);
result.test_is_eq<uint8_t>("rev(2u8)", Botan::ct_reverse_bits<uint8_t>(0b01001011), 0b11010010);

result.test_is_eq<uint16_t>(
"rev(0u16)", Botan::ct_reverse_bits<uint16_t>(0b0000000000000000), 0b0000000000000000);
result.test_is_eq<uint16_t>(
"rev(1u16)", Botan::ct_reverse_bits<uint16_t>(0b0101010101010101), 0b1010101010101010);
result.test_is_eq<uint16_t>(
"rev(2u16)", Botan::ct_reverse_bits<uint16_t>(0b0100101101011010), 0b0101101011010010);

result.test_is_eq<uint32_t>("rev(0u32)", Botan::ct_reverse_bits<uint32_t>(0xFFFFFFFF), 0xFFFFFFFF);
result.test_is_eq<uint32_t>("rev(1u32)", Botan::ct_reverse_bits<uint32_t>(0x55555555), 0xAAAAAAAA);
result.test_is_eq<uint32_t>("rev(2u32)", Botan::ct_reverse_bits<uint32_t>(0x4B6A2C1D), 0xB83456D2);

result.test_is_eq<uint64_t>(
"rev(0u64)", Botan::ct_reverse_bits<uint64_t>(0xF0E0D0C005040302), 0x40C020A0030B070F);
result.test_is_eq<uint64_t>(
"rev(1u64)", Botan::ct_reverse_bits<uint64_t>(0x5555555555555555), 0xAAAAAAAAAAAAAAAA);
result.test_is_eq<uint64_t>(
"rev(2u64)", Botan::ct_reverse_bits<uint64_t>(0x4B6A2C1D5E7F8A90), 0x951FE7AB83456D2);

return result;
}
};

BOTAN_REGISTER_TEST("utils", "bit_ops", BitOps_Tests);
Expand Down

0 comments on commit 60bd9fb

Please sign in to comment.