How to perform binary operations on a nibble/tetrad in php?

514 views Asked by At

So, I have numeric values from 0 to 15, so I saved them in hex codes (0 to f). Now I have a string of data containing hex code values of my nibbles.

Data looks like this:

a0fc3d78270db962e4ba525cf3acd

What is the accurate/elegant/fast way of performing binary xor on two nibbles and what would be the fastest way of performing a binary not on a nibble?

What I have in mind right now is to first convert the nibbles into full bytes:

$nibble = "c";
$numeric = ord($nibble);
$byte = ($numeric<58)?chr($numeric-48):chr($numeric-55);

Then perform the desired operation (xor or not) on these bytes, and reconvert the resultant value into a nibble again.

$byte1 = chr(7); $byte2=chr(12);
$xor_val = $byte1 ^ $byte2;
$numeric = ord($xor_val);
$nibble = ($numeric<58)?chr($numeric+48):chr($numeric+55);

The problem with this approach is that if I apply a not (~) operation on a byte, it reverses the first 4 bits too (hence adding 1111 to the left side of the nibble), and I have to get into an extra complexity of subtracting 240 from the ord() value of the result before I reconvert it into a nibble with the code presented above. This does not only make it cumbersome for future upgrades to the code, but also makes it harder to interpret the functionality of the code in the future.

What is the best/accurate way of performing bitwise xor and not on nibbles and having the resultant value as a hex code (string)?

Examples:

'3' xnor 'a' = '6'  
'c' xnor '5' = '6'  
'b' xnor '8' = 'c'
1

There are 1 answers

0
Pieter van den Ham On

Using a binary AND operation to only select relevant bits:

$nibble1 = hexdec('3');
$nibble2 = hexdec('a');

// nibble1 xnor nibble2
$r = ~($nibble1 ^ $nibble2) & 0x0F;

echo dechex($r); // '6'

This is called "masking off" bits, where 0x0F is called the "mask".

Without masking, the result of the operation ~(0x0b ^ 0x08) would be ffffffffffffffffc, due to PHP representing integers as 64-bit longs.

Now when we apply the mask, the following happens (I left out the 4 upper bytes for easier visualization):

11111111 11111111 11111111 11111100 (ffffffffc)
00000000 00000000 00000000 00001111 (00000000f)
----------------------------------- & (binary AND)
00000000 00000000 00000000 00001100 (00000000c)

We "select" only the lower last nibble.

To mask the upper nibble, use 0xF0 and (optionally) shift right 4.

$byte1 = hexdec('3f');
$byte2 = hexdec('a5');

$r = (~($byte1 ^ $byte2) & 0xF0) >> 4;

echo dechex($r); // Also '6'