plzin / mba-wasm

Mixed Boolean-Arithmetic in Rust for WebAssembly
https://plzin.github.io/mba-wasm/
23 stars 3 forks source link

Generation issue #1

Open Deniskore opened 2 weeks ago

Deniskore commented 2 weeks ago

Hey! Thanks for the interesting project!

  1. To eliminate warnings such as 'integer constant is too large,' it's necessary to generate specific type modifiers for constant integers in the expression.

  2. I believe there are occasions when you might encounter an obfuscation issue, such as:

(100 * 1) / 1

64bit
Number of auxiliary variables: 2
Number of rewrite operations: 4
Depth of rewrite operations: 3

Generated code:

uint64_t f(uint64_t aux0, uint64_t aux1) {
    return (18446744073709551516 * ~(aux0 & aux0 & (aux0 | aux1)) +
        18446744073709551516 * aux0) * (((aux0 & aux1 ^ aux1) &
        ~(aux0 & aux0)) + 18446744073709551615 * ((aux1 ^ aux0) &
        ~aux0 | aux1 ^ aux0 | aux1 | aux1) + 18446744073709551615 *
        ~aux0) / 18446744073709551615 * ((~aux0 | aux0 | aux0) &
        ((aux1 | aux1) ^ ~aux1));
}

int main () {
    std::cout << "Result is " << f(1,111);
}

GCC:

Output ``` :6:17: warning: integer constant is so large that it is unsigned 6 | return (18446744073709551516 * ~(aux0 & aux0 & (aux0 | aux1)) + | ^~~~~~~~~~~~~~~~~~~~ :7:17: warning: integer constant is so large that it is unsigned 7 | 18446744073709551516 * aux0) * (((aux0 & aux1 ^ aux1) & | ^~~~~~~~~~~~~~~~~~~~ :8:35: warning: integer constant is so large that it is unsigned 8 | ~(aux0 & aux0)) + 18446744073709551615 * ((aux1 ^ aux0) & | ^~~~~~~~~~~~~~~~~~~~ :9:54: warning: integer constant is so large that it is unsigned 9 | ~aux0 | aux1 ^ aux0 | aux1 | aux1) + 18446744073709551615 * | ^~~~~~~~~~~~~~~~~~~~ :10:26: warning: integer constant is so large that it is unsigned 10 | ~aux0) / 18446744073709551615 * ((~aux0 | aux0 | aux0) & | ^~~~~~~~~~~~~~~~~~~~ ASM generation compiler returned: 0 :6:17: warning: integer constant is so large that it is unsigned 6 | return (18446744073709551516 * ~(aux0 & aux0 & (aux0 | aux1)) + | ^~~~~~~~~~~~~~~~~~~~ :7:17: warning: integer constant is so large that it is unsigned 7 | 18446744073709551516 * aux0) * (((aux0 & aux1 ^ aux1) & | ^~~~~~~~~~~~~~~~~~~~ :8:35: warning: integer constant is so large that it is unsigned 8 | ~(aux0 & aux0)) + 18446744073709551615 * ((aux1 ^ aux0) & | ^~~~~~~~~~~~~~~~~~~~ :9:54: warning: integer constant is so large that it is unsigned 9 | ~aux0 | aux1 ^ aux0 | aux1 | aux1) + 18446744073709551615 * | ^~~~~~~~~~~~~~~~~~~~ :10:26: warning: integer constant is so large that it is unsigned 10 | ~aux0) / 18446744073709551615 * ((~aux0 | aux0 | aux0) & | ^~~~~~~~~~~~~~~~~~~~ Execution build compiler returned: 0 Program returned: 0 Result is 18446744073709540917 ```

Clang:

Output ``` :6:10: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 6 | return (18446744073709551516 * ~(aux0 & aux0 & (aux0 | aux1)) + | ^ :7:3: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 7 | 18446744073709551516 * aux0) * (((aux0 & aux1 ^ aux1) & | ^ :8:21: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 8 | ~(aux0 & aux0)) + 18446744073709551615 * ((aux1 ^ aux0) & | ^ :9:40: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 9 | ~aux0 | aux1 ^ aux0 | aux1 | aux1) + 18446744073709551615 * | ^ :10:12: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 10 | ~aux0) / 18446744073709551615 * ((~aux0 | aux0 | aux0) & | ^ 5 warnings generated. ASM generation compiler returned: 0 :6:10: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 6 | return (18446744073709551516 * ~(aux0 & aux0 & (aux0 | aux1)) + | ^ :7:3: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 7 | 18446744073709551516 * aux0) * (((aux0 & aux1 ^ aux1) & | ^ :8:21: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 8 | ~(aux0 & aux0)) + 18446744073709551615 * ((aux1 ^ aux0) & | ^ :9:40: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 9 | ~aux0 | aux1 ^ aux0 | aux1 | aux1) + 18446744073709551615 * | ^ :10:12: warning: integer literal is too large to be represented in a signed integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal] 10 | ~aux0) / 18446744073709551615 * ((~aux0 | aux0 | aux0) & | ^ 5 warnings generated. Execution build compiler returned: 0 Program returned: 0 Result is 0 ```

MSVC:

Output ``` example.cpp ASM generation compiler returned: 0 example.cpp Execution build compiler returned: 0 Program returned: 0 Result is 0 ```
Deniskore commented 2 weeks ago

For now, I think the issue is related to the division only. Code to reproduce the issue:

#include <cassert>
#include <cstdint>
#include <iostream>

// TODO: Change the constant!
constexpr uint8_t OBFUSCATED_CONSTANT = 250;

uint8_t f(uint8_t aux0, uint8_t aux1) {
  // INSERT the expression for OBFUSCATED_CONSTANT / 1
  return 0;
}

void test_mba() {
  for (uint8_t i = 0;; ++i) {

    for (uint8_t j = 0;; ++j) {
      assert(f(i, j) == OBFUSCATED_CONSTANT);
      if (j == UINT8_MAX)
        break;
    }

    if (i == UINT8_MAX)
      break;
  }

  std::cout << "All tests passed!" << std::endl;
}

int main() { test_mba(); }