Walkthrough

How I imagined people would figure my puzzle out ...

So, we have an image. The first thing anyone would do is to look at it in an image viewer. For this image all you see is that it's all just white, and there's nothing there. Not much more an image viewer can tell me, so I guess look at the pixels in the image (e.g. with PIL).

        
vshcmd: > python3
vshcmd: > from PIL import Image
vshcmd: > challenge_image = Image.open('puzzle3/challenge-image.png')
vshcmd: > set(challenge_image.getdata())
{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217}
>>>
        
      

That's somewhat interesting, we have all the odd numbers as our "data". But they're not all the same (as white), and how do they represent colours?
... bit of googling on PNG image type ...
... come across the 'indexed' colour type ...
... look at the palette of the image ...

      
vshcmd: > challenge_image.palette.mode
'RGB'
>>>
vshcmd: > challenge_image.palette.palette
b'\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00'
>>>
      
    

That palette looks like it can explain why everything is white: all the indexes that are used in the image have the white colour. There are a bunch of other indexes not used in the image, and some of them are non-white.

You may even have printed the image out in terms of these numbers and seen that they encode the shapes of the alphabet and numbers.

      
vshcmd: > all_pixels = iter(challenge_image.getdata())
vshcmd: > for y in range(challenge_image.height):
vshcmd: >   for x in range(challenge_image.width):
vshcmd: >       print('{0:3}'.format(next(all_pixels)), end='')
vshcmd: >   print()^M
... snip ...
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1  1  1
1  1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1  1
1  1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1 75 75 75 75 75 75 75 75 75  1  1 75 75 75 75  1  1  1  1
1  1  1  1  1  1 75 75 75 75  1  1  1  1  1  1  1 75 75 75 75  1  1  1  1
1  1  1  1  1  1 75 75 75 75  1  1  1  1  1  1 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1 75 75 75 75 75 75 75 75 75 75 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1  1 75 75 75 75 75 75 75 75  1 75 75 75 75  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
... snip ...
      
    

Here is the point that someone just has to make a guess, if you read the clue of "Shift-The-Red" then you might recognise that the last colour in the palette is pure red, and that you have to move (or "shift") it.

The answer is to take that red colour from the end, and put it at the start. This moves all other pixels one up in the index, changing the mapping between colours and indexes. This change in the mapping now selects certain letters out by the index they're encoded with -- turning those letters black.

If you want to adjust the palette yourself you'd have to update the CRC of the PLTE chunk now (which is unfortunate, but I didn't find a way to keep the CRC the same while still having a transform as neat as this one), but if using PIL at least you may not have to worry about it.

      
vshcmd: > orig_palette = challenge_image.palette.palette
vshcmd: > challenge_image.palette.palette = orig_palette[-3:] + orig_palette[:-3]
vshcmd: > challenge_image.show()
>>> >>> >>>
      
    

And then you have the solution image. The password is just read off of this image left-to-right, top-to-bottom.

The Solution Image

Solution!