An ulta-paranoid tinfoil hat implementation of reasonably safe storage for numerical types

Consider a number stored in memory that is crucially important to the functionality of your application. First of all, that number needs to be encapsulated in a class private, so that you can't accidentally modify it yourself within the code. Exposing it with getter and setter would be better, you could control the access to them by declaring friend class or a function, severly limiting number of possible accidental modifications. But there is still a danger of accidentally modifying it by returning a reference to it or do some other silly thing within the class itself. For this reason this private member needs to be const and initialised in constructor, once and for all. Now, if you managed to write the important number correctly once, it should be safe. Double check the line where it is initialised!

At this point it is, of course, far from being safe from ultra-paranoid perspective. High-energy radiation might flip a bit in your RAM chip, for instance. EEC chips won't do. They are expensive and you might not need to protect the whole memory, just some important value. They don't protect you from programming mistakes, like casting variables around in a silly way, buffer overruns, rogue pointer aritmetics, and similar. For these reasons there is another value stored alongside the important number in the same class and I will call that value a "control". This control is derived from the important number we are storing. On every read, the number that is about to be returned is checked against control to determine if it is still untampered with.

What should this control number be? For one, it can't be equal to the number itself: freed heap memory for instance, 0xfeeefeee 0xfeeefeee ..., would not be distinguishable from a valid value. It also can't be a constant magic number because how could that enable us to detect changes in original number? It must not be a result of a complicated calculation either, as user would not expect a long operation from simply retrieving a number from a container. Therefore, operation needs to use the number as an input and calculation needs to be done with one CPU instruction to reduce performance impact. Which operation that is irrelevant to the cause. Simply adding a third number is probably most straightforward one; xor-ing and the likes which don't need additional numbers for this would in my opinion imply something more clever is going on and that would be misleading to maintainers. I will call this additional third number a "key". If this key was static and equal for all numbers it would be easier to backengineer how to properly modify the number than if it the key was changing. For this reason I used randomly generated key. This also makes it different for every number in the program, on every run of the program.

To make a step forward I added a vector of such controls and keys. A vector of controls also enables you to know which value was modified and you can do on the spot error correction, but that is not paranoid enough. If the value is changed than the whole operation is in jeopardy, program needs to exit immediately!

Now that I am done with rationalising the motivation, enjoy the implementation:

Implementation


class compromised_number : 
  public std::exception {};

template <typename T>
class csupersafe_number
{
private:
  const std::vector<double> m_keys;
  // not the first data in memory layout
  const T m_number; // important value
  const std::vector<double> m_controls;

  double calculate_control_value(
    const unsigned short index) const 
  {
    return (m_number + m_keys[index]);
  }

public:
  csupersafe_number(const T number) :
    m_keys{
      get_random_double(),
      get_random_double()},
    m_number{number},
    m_controls{
      calculate_control_value(0),
      calculate_control_value(1)}
  {
  }

  operator T() const
  {
    if(dbl(calculate_control_value(0))
         .equals(m_controls[0]) &&
       dbl(calculate_control_value(1))
         .equals(m_controls[1]))
    {
      // passed integrity control!
      return m_number;
    }
    else
    {
      // Didn't pass integrity control!
      // Nice try, Illuminati! HHAHAahha!!!11
      throw compromised_number(); // Abort the mission!
    }
  }
};

All these values would of course be safer if they were stored in random locations using free store. I thought this would cause too many cache misses so I didn't do it. Some additional cache misses will be caused anyway just because fewer numbers will fit each cache line because of the small amount of data in each object, the key takes a significant share of storage as well. if you feel extra paranoid you are free to implement the suggestion. For extra randomness, allocate random number of bytes before new-ing the numbers, then free it.

Demo


typedef csupersafe_number<int>    s_int; // supersafe int
typedef csupersafe_number<double> s_double; // supersafe double

// store number on creation, after that it can't change
s_int i_number = 12; 

// because assignment doesn't compile
//i_number = 13; 

// and copy constructor doesn't compile
s_int i_number2 = 13;
//i_number = i_number2; 
 
// can do math operations though, but if result is copied to another number
s_int i_number3 = i_number + 2; 
ASSERT_EQ(14, i_number3);
  
// but if anyone or anything changed the original value ...
  
// Though even if you hack access modifiers to get access to private member, it is still const.
// Will remain unchanged or might not even compile.
// i_number.m_number = 14;

// will take some creativity to change it
int i;
int* number_address = (int*)&i_number;
// get access: 4th int in memory layout is the number that is protected
number_address += 3; 
// access unmodified number: OK
ASSERT_NO_THROW(i = i_number);
// modify it outside the class that protects it
*number_address = 14; 
// access unmodified number: throws
ASSERT_THROW(i = i_number, compromised_number); 


Previous: A way to compare floating point values
Next: Unfair lock optimisation