Tl;dr: Is there a way to improve the code below in any way (including multithreading) as the code will run hundreds of billions of times?
To objective is to find a constant time algorithm (without a for loop) for performing multiplication in Galois Field GF(4). I am not sure if this is even possible but it is worth a try.
Some background: multiplication in GF(2) or base 2 is the equivalent of anding the two values being multiplied. This is because:
| a | b | a × b = a ∧ b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
For example:
10101011010100 × 10011000101101 =
10101011010100
10011000101101 ∧
--------------
10001000000100
When it comes to GF(4), there are four different symbols that can be used: 0, 1, 2 and 3. It is not the same as performing multiplication in base 4 because some digits don't give an expected result when multiplied by other digits. They are bolded in the table below:
| a | b | a × b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 2 | 0 |
| 0 | 3 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 3 | 3 |
| 2 | 0 | 0 |
| 2 | 1 | 2 |
| 2 | 2 | 3 |
| 2 | 3 | 1 |
| 3 | 0 | 0 |
| 3 | 1 | 3 |
| 3 | 2 | 1 |
| 3 | 3 | 2 |
A more compact form of the above table can be summarized using following multiplication table:
| × | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 2 | 3 |
| 2 | 0 | 2 | 3 | 1 |
| 3 | 0 | 3 | 1 | 2 |
We can write each of the four digits in binary as multiplication will be performed on the binary representation of the values:
| Digit | Binary representation |
|---|---|
| 0 | 00 |
| 1 | 01 |
| 2 | 10 |
| 3 | 11 |
In GF(4), multiplication is done by multiplying digit by digit without carry. For example:
21302032 × 31012233 =
21302032
31012233 ×
--------
11003021
We can use the binary representation of the values and perform the multiplication:
21302032 = 1001110010001110 in binary
31012233 = 1101000110101111 in binary
11003021 = 0101000011001001 in binary
1001110010001110
1101000110101111 ×
----------------
0101000011001001
Lastly, here is an implementation of a working java code that performs the multiplication. However, it uses a for loop and the goal is to come up with constant time algorithm:
public class Multiplication {
public static void main(String[] args) {
final byte[][] MUL_ARRAY = new byte[][]{
{0, 0, 0, 0},
{0, 1, 2, 3},
{0, 2, 3, 1},
{0, 3, 1, 2}
};
long mask;
byte shift = 2;
//long is 64 bits which means it can store 32 digits quaternary value.
int n = 8; //# of quaternary digits (ALWAYS given)
long v1 = 0b1001110010001110;//21302012 in base 4
long v2 = 0b1101000110101111;//31012233 in base 4
long result = 0;
for (int i = 0; i < n; i++) {
//get far-right quaternary digit of the two vectors:
mask = 0b11;
mask = mask << 2 * (n - i - 1);
long v1DigitPadded = v1 & mask;//correct digit with zero padding
long v2DigitPadded = v2 & mask;//correct digit with zero padding
//shift the digits so that the digit needed is at far-right
v1DigitPadded = v1DigitPadded >>> 2 * (n - i - 1);
v2DigitPadded = v2DigitPadded >>> 2 * (n - i - 1);
//The actual quaternary digit
byte v1Digit = (byte) v1DigitPadded;
byte v2Digit = (byte) v2DigitPadded;
byte product = MUL_ARRAY[v1Digit][v2Digit];
long resultDigit = product << 2 * (n - i - 1);
result = result | resultDigit;
}
//desired output: 0101000011001001
//prints the value in binary with zeros padding on the left
String s = Long.toBinaryString(result);
String output = String.format("%" + n * 2 + "s", s).replace(" ", "0");
System.out.println("The output is: " + output);
}
}
Is there an algorithm for that? If not, are there some improvements that can help in my logic (maybe an efficient multithreading approach)?