The .Wat ness is open for testing! http://watness.pwni.ng:7744/

When it came out in 2016, the Witness impressed with its ability to gradually teach new players the rules of the game by simply having them play it. With the .Wat ness, we take this just a small step further.


How to solve

First of all, this write-up has a lot of guesses.
Also, teammate imnotkind helped in downloading resources and reversing typescript files!

Super easy guesses

If you’re a ’the witness’ player, you can easily guess four symbols: (Read this with the guide)

  • Multicolored squares in the Witness Multicolored squares in the Witness

  • Suns in the Witness Suns in the Witness

  • Tetris blocks in the Witness Tetris blocks in the Witness

  • Triangles in the Witness Triangles in the Witness

Wait, why the guide does not explain triangles? You need to draw a path exactly passes n edges of the block with n triangles. In The .Wat ness, it is n blue blocks.

Circles, a strange round-edged rectangle, and blue blocks

But what are those?

We need to figure them out…

Reversing

Download all resources via Save All Resources.

By reading src/constraints.ts, you can know there are total 6 constraints and Constraint5 is reversed triangles, and Constraint6 is round-edged rectangle.

By reading problem/common/src/bootstrap.ts, you can see four parameters are passed to fn_assembly/index/checkAll. (In the code, it is this.module.checkAll.) If checkAll returns an empty array, it is the answer. So, what are those four parameters?

 - mtx (parameter 1) : array_BoardMatrixElement
 - parts (parameter 2) : array_PartitionListElement
 - horizontalPathSegments (parameter 3) : array_i32
 - verticalPathSegments (parameter 4): array_i32

The first parameter describes the symbols on the board.

If the board is partitioned by the input path, partition information is passed by the second parameter.

The third and fourth parameter have which edge is passed by the input path. So, the third one will be kinda 7×6 matrix, and the fourth one will be 6×7 matrix.


I’ve run wabt wasm2c to read the wasm file.

checkAll calls Constraint{i}_check functions. Let’s see Constraint6_check.
When reading the code, p{i} is the ith parameter, l{i} is a local variable, and l{i} is a temporal variable. Just understand l{i} as non-volatile registers, and i{i} as volatile registers.

static u32 assembly_index_Constraint6_check(u32 p0, u32 p1, u32 p2, u32 p3) {
  u32 l4 = 0, l5 = 0, l6 = 0, l7 = 0, l8 = 0;
  FUNC_PROLOGUE;
  u32 i0, i1, i2, i3;
  i0 = 0u;
  i1 = 0u;
  i0 = _lib_array_Array_Constraint__constructor(i0, i1);
  l4 = i0;
  i0 = 0u;
  l5 = i0;
  L1: 
    i0 = l5;
    i1 = p0;
    l6 = i1;
    i1 = l6;
    i1 = i32_load((&memory), (u64)(i1 + 4));
    i0 = (u32)((s32)i0 < (s32)i1);
    i0 = !(i0);
    if (i0) {goto B0;}
    i0 = 0u;
    l6 = i0;
    L4: 
      i0 = l6;
      i1 = p0;
      i2 = l5;
      i1 = _lib_array_Array_Array_BoardMatrixElement_____get(i1, i2);
      l7 = i1;
      i1 = l7;
      i1 = i32_load((&memory), (u64)(i1 + 4));
      i0 = (u32)((s32)i0 < (s32)i1);
      i0 = !(i0);
      if (i0) {goto B3;}
      i0 = p0;
      i1 = l5;
      i0 = _lib_array_Array_Array_BoardMatrixElement_____get(i0, i1);
      i1 = l6;
      i0 = _lib_array_Array_BoardMatrixElement____get(i0, i1);
      i0 = i32_load((&memory), (u64)(i0 + 4));
      i1 = 0u;
      i0 = i0 != i1;
      l7 = i0;
      if (i0) {
        i0 = p0;
        i1 = l5;
        i0 = _lib_array_Array_Array_BoardMatrixElement_____get(i0, i1);
        i1 = l6;
        i0 = _lib_array_Array_BoardMatrixElement____get(i0, i1);
        i0 = i32_load((&memory), (u64)(i0 + 4));
        i0 = i32_load((&memory), (u64)(i0 + 12));
        i1 = 2344u;
        i0 = assembly_index_streq(i0, i1);
      } else {
        i0 = l7;
      }
      if (i0) {
        i0 = p0;
        i1 = l5;
        i0 = _lib_array_Array_Array_BoardMatrixElement_____get(i0, i1);
        i1 = l6;
        i0 = _lib_array_Array_BoardMatrixElement____get(i0, i1);
        i0 = i32_load((&memory), (u64)(i0));
        l7 = i0;
        i0 = p2;
        i1 = l5;
        i0 = _lib_array_Array_Array_i32_____get(i0, i1);
        i1 = l6;
        i0 = _lib_array_Array_i32____get(i0, i1);
        i1 = p2;
        i2 = l5;
        i3 = 1u;
        i2 += i3;
        i1 = _lib_array_Array_Array_i32_____get(i1, i2);
        i2 = l6;
        i1 = _lib_array_Array_i32____get(i1, i2);
        i0 += i1;
        i1 = p3;
        i2 = l5;
        i1 = _lib_array_Array_Array_i32_____get(i1, i2);
        i2 = l6;
        i1 = _lib_array_Array_i32____get(i1, i2);
        i0 += i1;
        i1 = p3;
        i2 = l5;
        i1 = _lib_array_Array_Array_i32_____get(i1, i2);
        i2 = l6;
        i3 = 1u;
        i2 += i3;
        i1 = _lib_array_Array_i32____get(i1, i2);
        i0 += i1;
        l8 = i0;
        i0 = l8;
        i1 = 0u;
        i0 = i0 != i1;
        if (i0) {
          i0 = l4;
          i1 = p0;
          i2 = l5;
          i1 = _lib_array_Array_Array_BoardMatrixElement_____get(i1, i2);
          i2 = l6;
          i1 = _lib_array_Array_BoardMatrixElement____get(i1, i2);
          i1 = i32_load((&memory), (u64)(i1 + 4));
          i0 = _lib_array_Array_Constraint__push(i0, i1);
        }
      }
      i0 = l6;
      i1 = 1u;
      i0 += i1;
      l6 = i0;
      goto L4;
    UNREACHABLE;
    B3:;
    i0 = l5;
    i1 = 1u;
    i0 += i1;
    l5 = i0;
    goto L1;
  UNREACHABLE;
  B0:;
  i0 = l4;
  FUNC_EPILOGUE;
  return i0;
}

L1 and L2 are loop labels. Each uses l5 and l6 as an iterator.
The key part is Line 55-104. It checks whether any edge around the block is passed by the input path. If yes, it will return those blocks as array_Constraint.

The return value should be an empty array, so round-edged rectangle symbols are like blue blocks symbols with zero blue blocks. We need to avoid four edges around round-edged rectangles, regardless of its color!

Then, what are reversed triangles? Well, I don’t know.

It’s still solvable without knowing it. Just try all the possible paths around reversed triangles. One of them will be a solution.

Solving

Just do by your hands. If it seems hard to solve, just press F5. I solved all the stages within 2 minutes.

The flag is pctf{what_if_i_made_firmament_instead}.

BTW, I solved all the puzzles in the Witness.