Rating: 3.0

1. Translate from Braille to get 5a42545a42485a42495a42534253457a6361774253457a797a7561776163 and unhex for ZBTZBHZBIZBSBSEzcawBSEzyzuawac and unhexlify for ZBTZBHZBIZBSBSEzcawBSEzyzuawac
2. reading the source, "\_" gets replaced with "CTF" before the mixing step, so we can guess the "BSE" in the mixed flag is "CTF" shifted by 25
3. to get the value for numShift we can calculate 25+26 (since CTF is uppercase) = 51, chr(0x41+51) gives us "t"
4. reverse the mix and puzzled functions, I opted to do this by editing the provided Python script:

import string

upperFlag = string.ascii_uppercase[:26]
lowerFlag = string.ascii_lowercase[:26]
MIN_LETTER = ord("a")
MIN_CAPLETTER = ord("A")

def reverse_mix(oneLetter, num):
if oneLetter.isupper():
index = upperFlag.index(oneLetter)
shift_index = ord(num)-MIN_CAPLETTER
return chr(MIN_CAPLETTER + (index - shift_index)%len(upperFlag))
else:
index = lowerFlag.index(oneLetter)
shift_index = ord(num)-MIN_LETTER
return chr(MIN_LETTER + (index - shift_index)%len(upperFlag))

def reverse_puzzled(puzzle):
original = ""
pos = 0
while pos < len(puzzle):
if puzzle[pos:pos+3] == "CTF":
original += "_"
pos += 3
else:
if puzzle[pos].isupper():
index = upperFlag.index(puzzle[pos])
index2 = upperFlag.index(puzzle[pos+1])
index3 = upperFlag.index(puzzle[pos+2])
binary = "{0:05b}{1:05b}{2:05b}".format(index, index2, index3)
original += chr(int(binary, 2))
pos += 3
else:
index = lowerFlag.index(puzzle[pos])
index2 = lowerFlag.index(puzzle[pos+1])
hex_val = "{0:01x}{1:01x}".format(index, index2)
original += chr(int(hex_val, 16))
pos += 2
return original

mixed="ZBTZBHZBIZBSBSEzcawBSEzyzuawac"
numShift="t"
unmixed=""
for count, alpha in enumerate(mixed):
unmixed += reverse_mix(alpha, numShift)
print(reverse_puzzled(unmixed))


This prints THIS_is_easy and the flag is TUCTF{THIS_is_easy}