1

Let maj(a, b, c) denote the majority function. The T-function (called tfunc) operates on eight $n$-bit words and outputs eight $n$-bit words. The majority function outputs 1 bit from 3 bits (i.e. a single $n$-bit word from three $n$-bit words).

In the following pseudocode, ^ denotes the bitwise XOR operation, & denotes the bitwise AND operation, | denotes the bitwise OR operation, X |= Y denotes the X = X | Y operation, << denotes the left non-cyclic shift modulo $2^n$.

function tfunc([A0, A1, A2, A3, A4, A5, A6, A7]) {
    B0 = A0 ^ A1 ^ A2 ^ (maj(A3, A4, A5) << 1);
    B1 = A1 ^ A2 ^ A3 ^ (maj(B0, A6, A7) << 1);
    B2 = A2 ^ A3 ^ A4 ^ (maj(B1, A0, A1) << 1);
    B3 = A3 ^ A4 ^ A5 ^ (maj(B2, A2, A3) << 1);
    B4 = A4 ^ A5 ^ A6 ^ (maj(B3, A4, A5) << 1);
    B5 = A5 ^ A6 ^ A7 ^ (maj(B4, A6, A7) << 1);
    B6 = A6 ^ A7 ^ A0 ^ (maj(B5, A0, A1) << 1);
    B7 = A7 ^ A0 ^ A1 ^ (maj(B6, A2, A3) << 1);
    return [B0, B1, B2, B3, B4, B5, B6, B7];
};

This algorithm uses the circular binary matrix $M$:

1, 1, 1, 0, 0, 0, 0, 0
0, 1, 1, 1, 0, 0, 0, 0
0, 0, 1, 1, 1, 0, 0, 0
0, 0, 0, 1, 1, 1, 0, 0
0, 0, 0, 0, 1, 1, 1, 0
0, 0, 0, 0, 0, 1, 1, 1
1, 0, 0, 0, 0, 0, 1, 1
1, 1, 0, 0, 0, 0, 0, 1

The inverse of $M$ is

0, 1, 1, 0, 1, 1, 0, 1
1, 0, 1, 1, 0, 1, 1, 0
0, 1, 0, 1, 1, 0, 1, 1
1, 0, 1, 0, 1, 1, 0, 1
1, 1, 0, 1, 0, 1, 1, 0
0, 1, 1, 0, 1, 0, 1, 1
1, 0, 1, 1, 0, 1, 0, 1
1, 1, 0, 1, 1, 0, 1, 0

But what is the correct algorithm (in the C-like pseudocode) for the inverse of tfunc? The algorithm would look like the one in this answer (here len denotes the number of bits in a word, which corresponds to the number $n$ mentioned in the first paragraph of the post):

function inv_tfunc([B0, B1, B2, B3, B4, B5, B6, B7]) {
    A0 = (B1 ^ B2 ^ B4 ^ B5 ^ B7) & 1; 
    A1 = (B2 ^ B3 ^ B5 ^ B6 ^ B0) & 1; 
    A2 = (B3 ^ B4 ^ B6 ^ B7 ^ B1) & 1; 
    A3 = (B4 ^ B5 ^ B7 ^ B0 ^ B2) & 1; 
    A4 = (B5 ^ B6 ^ B0 ^ B1 ^ B3) & 1; 
    A5 = (B6 ^ B7 ^ B1 ^ B2 ^ B4) & 1; 
    A6 = (B7 ^ B0 ^ B2 ^ B3 ^ B5) & 1; 
    A7 = (B0 ^ B1 ^ B3 ^ B4 ^ B6) & 1;
for (i = 1; i &lt; len; i = i + 1){
    A0 |= (1 &lt;&lt; i) &amp; (???);
    A1 |= (1 &lt;&lt; i) &amp; (???);
    A2 |= (1 &lt;&lt; i) &amp; (???);
    A3 |= (1 &lt;&lt; i) &amp; (???);
    A4 |= (1 &lt;&lt; i) &amp; (???);
    A5 |= (1 &lt;&lt; i) &amp; (???);
    A6 |= (1 &lt;&lt; i) &amp; (???);
    A7 |= (1 &lt;&lt; i) &amp; (???);
};
return [A0, A1, A2, A3, A4, A5, A6, A7];

}

I can only compute the least significant (linear) bits of each word. How to obtain the remaining bits?

lyrically wicked
  • 1,379
  • 7
  • 11

1 Answers1

4

We can convert tfunc equations to

    A0^A1^A2 = B0^(maj(A3,A4,A5)<<1)
    A1^A2^A3 = B1^(maj(B0,A6,A7)<<1)
    A2^A3^A4 = B2^(maj(B1,A0,A1)<<1)
    A3^A4^A5 = B3^(maj(B2,A2,A3)<<1)
    A4^A5^A6 = B4^(maj(B3,A4,A5)<<1)
    A5^A6^A7 = B5^(maj(B4,A6,A7)<<1)
    A6^A7^A0 = B6^(maj(B5,A0,A1)<<1)
    A7^A0^A1 = B7^(maj(B6,A2,A3)<<1)

In these, knowing the Bj and the i low-order bits of the Aj lets us compute the right-hand side to i+1 low-order bits, thus the left-hand side to i+1 low-order bits, thus the Ai to ì+1 low-order bits using the invert matrix/equations already in the question.

We can apply this for ì from 0 to n-1 to fully invert the function. Baring mistakes, code could be (not tested):

function inv_tfunc([B0, B1, B2, B3, B4, B5, B6, B7]) {
    M = (((1<<(n-1))-1)<<1)+1; // mask for  n  bits
    A0 = A1 = A2 = A3 = A4 = A5 = A6 = A7 = 0; // initial value is immaterial
    for (i = 0; i < n; i = i + 1) {
        C0 = (B0^(maj(A3,A4,A5)<<1))&M;
        C1 = (B1^(maj(B0,A6,A7)<<1))&M;
        C2 = (B2^(maj(B1,A0,A1)<<1))&M;
        C3 = (B3^(maj(B2,A2,A3)<<1))&M;
        C4 = (B4^(maj(B3,A4,A5)<<1))&M;
        C5 = (B5^(maj(B4,A6,A7)<<1))&M;
        C6 = (B6^(maj(B5,A0,A1)<<1))&M;
        C7 = (B7^(maj(B6,A2,A3)<<1))&M;
        A0 = C1^C2^C4^C5^C7;
        A1 = C2^C3^C5^C6^C0;
        A2 = C3^C4^C6^C7^C1;
        A3 = C4^C5^C7^C0^C2;
        A4 = C5^C6^C0^C1^C3;
        A5 = C6^C7^C1^C2^C4;
        A6 = C7^C0^C2^C3^C5;
        A7 = C0^C1^C3^C4^C6;
    }
    return [A0, A1, A2, A3, A4, A5, A6, A7];
}

Note: The (corrected) expression for M builds a mask with the low-order n bit(s) set, assuming that the type of integers has at least (and including) n bits. The &M insures that variables stay within n bits. If variables have exactly n bits (e.g. in C uint32_t variables with n = 32), we can do without M and &M. If variables have some fixed width larger than n, we can deffer the &M to the return step.

fgrieu
  • 149,326
  • 13
  • 324
  • 622