1
$\begingroup$

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 < len; i = i + 1){
        A0 |= (1 << i) & (???);
        A1 |= (1 << i) & (???);
        A2 |= (1 << i) & (???);
        A3 |= (1 << i) & (???);
        A4 |= (1 << i) & (???);
        A5 |= (1 << i) & (???);
        A6 |= (1 << i) & (???);
        A7 |= (1 << i) & (???);
    };
    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?

$\endgroup$
6
  • $\begingroup$ When you say that tfunc1 is an arbitrary "T-function", what does this mean? $\endgroup$
    – Mark Schultz-Wu
    Commented Oct 30 at 7:14
  • $\begingroup$ @MarkSchultzWu: I have edited the question so that the algorithm (tfunc) defines a particular function. $\endgroup$ Commented Oct 30 at 8:04
  • $\begingroup$ Using the inverse matrix you can find the low-order bit of the Aj (you are there). Then you can compute the low-order bits of the the maj(…) terms, that is the second low-order bits of the (maj(…) << 1)terms, then use the inverse matrix to get the second low-order bits of the Aj. And so on for each bit. The rest is merely coding. $\endgroup$
    – fgrieu
    Commented Oct 30 at 8:25
  • $\begingroup$ @fgrieu: I am unable to find the expressions for A0 = ... and A1 = ... in the loop to compute the remaining bits. Given only these two expressions, I will probably be able to write the rest of the algorithm. But what are these expressions? $\endgroup$ Commented Oct 30 at 9:42
  • $\begingroup$ Rewrite B0 = A0^A1^A2^(maj(A3,A4,A5)<<1) into A0^A1^A2 = B0^(maj(A3,A4,A5)<<1) and so on for the other 7 equations. Knowing the Bj and the low-order i bits of the Aj you compute the RHS (thus the LHS) to i+1 low order bits. Then you compute the Aj to i+1 low order bits using the matrix/equations already in the answer. Apply that for i from 0 to n-1 and you have all the n bits of the Aj. I suggest you write the code and answer your own question. I'd rather not, because this could be homework, and making it is the only (or at least the best) way to learn that skill. $\endgroup$
    – fgrieu
    Commented Oct 30 at 10:23

1 Answer 1

4
$\begingroup$

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.

$\endgroup$
3
  • 1
    $\begingroup$ This algorithm outputs correct results (I tested for all inputs with $n=3$, i.e. $2^{24}$ inputs, setting M=3). What I do not understand is the expression for M. If its value must be equal to $n$ consecutive non-zero bits, this can be done by setting M = (1 << n) - 1, so I do not see the need for a more complex expression... If ((1<<(3-1)-1)<<1)+1 evaluates to 5, it can make the algorithm output incorrect results for 3-bit words. $\endgroup$ Commented Nov 1 at 5:13
  • $\begingroup$ @lyricallywicked: There was a missing pair of parenthesis in my expression for M, that's now fixed, sorry for the confusion I caused. On C implementations with 32-bit int, with n = 32, the expression (1<<n)-1 tends to be 0 because the shift count is taken modulo 32; or/and cause a warning. But (((1<<(n-1))-1)<<1)+1 is consistently 0xFFFFFFFF. For n = 3 both methods give M = 7, not M = 3. $\endgroup$
    – fgrieu
    Commented Nov 1 at 9:37
  • $\begingroup$ Thank you for explanations. I tested using Javascript. In this programming language, (1 << 3) - 1 evaluates to 7. $\endgroup$ Commented Nov 1 at 10:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.