Using bitwise operator | to manage access rights

When digging into the Appaloosa backend code, I saw in different places that we were using bitwise operators to manage access rights.

Actually, we implemented the guidelines of Apple Mobile Device Management Protocol Reference documentation.

Bitwise

Each right is defined with an integer.

  • The first is 1,
  • the second is 2,
  • the third is 4,
  • the fourth is 8…

Why are we using bitwise operators and power of 2 to manage access rights ? We could go with 1, 2, 3, 4, 5… instead of using power of 2s.

The power of Power of 2

For the record, binaries representations of each integers are:

> 4096.to_s(2)
=> "1000000000000"

> 2048.to_s(2)
=> "100000000000"

> 1024.to_s(2)
=> "10000000000"

> 512.to_s(2)
=> "1000000000"

> 128.to_s(2)
=> "10000000"

> 64.to_s(2)
=> "1000000"

> 32.to_s(2)
=> "100000"

> 16.to_s(2)
=> "10000"

> 8.to_s(2)
=> "1000"

> 4.to_s(2)
=> "100"

> 2.to_s(2)
=> "10"

> 1.to_s(2)
=> "1"

The pattern being that a bit is added with each power of 2.

Super Power Example

Taking a simple example, the benefit of using bitwise operators becomes really clear (performance benefits apart).

First case scenario

Let’s define 3 powers, associated with different rights:

WEAK_POWER = 1
POOR_POWER = 2
SUPER_POWER = 3

In this example, we don’t use powers of two. Now let’s see what happens if we want to create a new power that would give access to the rights of the weak power and the poor power.

VAIN_POWER = WEAK_POWER | POOR_POWER

If we replace the constant with their values.

VAIN_POWER = 1 | 2 = 3

Under the hood, the binary representations work like so,

01 # the binary representation of 1 is 01
10 # the binary representation of 2 is 10

11 # 01 OR 10 is 11, and 11 is the binary representation of 3

The problem with this, is that when creating a vain power, a power that gives the access of the weak power or the poor power, we are reaching the value 3, which appears to be the right of the super power !

We never want to do that !

We should be able to create whatever power we want, and never access any other power rights.

Second case scenario

Let’s define 3 powers, associated with different rights. This time, let’s use power of twos.

WEAK_POWER = 1
POOR_POWER = 2
SUPER_POWER = 4

Now, taking our vain power back,

VAIN_POWER = WEAK_POWER | POOR_POWER

If we replace the constant with their values.

VAIN_POWER = 1 | 2 = 3 # 3 is different from 4

We see that now creating the vain power does not give access to the super power.

Under the hood, the binary representations work like so,

01 # the binary representation of 1 is 01
10 # the binary representation of 2 is 10

11 # 01 OR 10 is 11, and 11 is the binary representation of 3
   # the binary representation of 4 is 100.

Whatever we do with values using the OR operator, we can’t access superior powers. As it always differs from 1 bit from the superior power (see the binary representations of each integer above).

Going back to the inital definition of constant. Let’s now try to cumulate the poor power to access super power.

WEAK_POWER = 1
POOR_POWER = 2
SUPER_POWER = 4

NEW_POWER = POOR_POWER | POOR_POWER
NEW_POWER = 2 | 2
NEW_POWER = 2

Under the hood, the binary representations work like so,

10 # the binary representation of 2 is 10
10 # the binary representation of 2 is 10

10 # 10 OR 10 is 10, and 10 is the binary representation of 2
   # the binary representation of 4 is 100.

So, using bitwise operators | to manage acess rights is just perfect to safely create new access rights without risking to create access to superior rights.

Sources:

Updated: