Solving Zden’s “1BiTCoiN WHiTe PaPeR” Puzzle

Puzzle can be found on Zden’s website http://crypto.haluska.sk/

Solved by

JTobcat —@JTobcat
Ziot — @bbuerhaus
Motive —@leemsparks

The Puzzle

After almost 2 years with no new puzzles, Zden has released his second puzzle of 2021 with the visually interesting 1BiTCoiN WHiTe PaPeR artwork. Some information can be found about the artwork encoded in the metadata of the image and on Opensea:

I created this generative artwork by processing the content of Bitcoin White Paper by Satoshi Nakamoto. It’s at the same time a crypto puzzle that is not visible at first glance. Artwork is also notarized on the Bitcoin blockchain by a transaction of 777 Satoshis from the puzzle’s address. The SHA-256 fingerprint from this image creates the private key of the notarization wallet. The first buyer of this artwork as NFT will receive a high-quality, hand-signed, physical print of size 28 x 28 inches (71.12 x 71.12 centimeters) — please deliver your shipping address by a signed message from your purchasing wallet (contact zden@satori.sk).

Zden Hlinka ~ April & May 2021 ~ Release: 16052121

Puzzle Name: 1BiTCoiN WHiTe PaPeR
Puzzle Difficulty: Hard
Puzzle Address: 1BiTCoiNsuFnkCFGkv6AGgwWxN31GUwY6W
Cryptocurrency: Bitcoin
Launch Date: 16 May 2021 21:00 (CET)
Medium: Digital
Technique: Generative
Pixel Resolution: 9000 x 9000
Notarization Address: 19ferXDjGX7XnErWWcd4SbYg4t8Jm5NRDi
SHA-256 Fingerprint: 5d3a6d707b653c0e95c9d192b6f5cf55ea54ae84ad6608fe0607a4e27896175e
Release URL: crypto.haluska.sk & opensea.io/assets/zden-cryptoart
IPFS Artwork Link: https://ipfs.io/ipfs/Qmdm7SxhVGDVt9krbNpwAxkQGwH5a74FVW1sKNXxCjzmBq?filename=1BiTCoiN-WHiTe-PaPeR.png
Physical Print: 28 x 28 inches (71.12 x 71.12 centimeters)

The Solve

Based on the information above, it is known that the image encodes the entirety of the Bitcoin Whitepaper. Looking closer at the image, it can be seen to be one continuous line, that when it hits an edge, jumps to the other edge and continues on. Zooming in on the art reveals some other curious information, such as a single red pixel near all 4 corners of the image. This actually provides the bounding box of the puzzle and can be cropped to reveal an 8192x8192 image. This seems significant as it gives us our first key piece of info as 8192 is 2048x4 (2048 being the number of words in the bip wordlist used to make bitcoin wallet seeds) and tells us that the image has most likely been scaled up by a factor of 4x.

The lonely red dots.

Now that we have the puzzle boundary, and have determined the line seems to be continuous, it is time to find where the line starts and ends. After some hunting, both ends have been identified, with one end at coordinates (4096, 4096) and the other at (3474, 7870) Note: Coordinates are given based on an image coordinate system with the origin in the upper left corner and positive X going right, and positive Y going down

The two ends of the line

Of the two options, it seems most logical the line that is in the dead center of the image is most likely the start, so we will begin there. Beginning at this section, it can be seen that the line segments all seem to have different lengths and no obvious pattern to rotation logic at first glance. The easiest data to extract at this stage to determine what is going on is documenting the end points of each line segment.

The first 7 line segments highlighted in red

Using the measure tool in Photoshop (or any capable image tool like GIMP), we begin measuring the relative X and Y coordinate changes between each point.

For example: Going from the start point to point 1 we must travel -120 in the X-direction and +36 in the Y-direction (remember positive moves down on an image)

Point 1: (-120, 36)
Point 2: (80, 12)
Point 3: (60, 36)
Point 4: (56, -152)
Point 5: (-124, -64)
Point 6: (20, 20)
Point 7: (72, -204)

The first thing that stands out is all the coordinate values are divisible by 4, which makes sense due to the earlier deduction that the image was meant to be 2048x2048 and was scaled up. So lets start by dividing each of the values by 4.

Point 1: (-30, 9)
Point 2: (20, 3)
Point 3: (15, 9)
Point 4: (14, -38)
Point 5: (-31, -16)
Point 6: (5, 5)
Point 7: (18, -51)

Ignoring +/- signs, a lot of the values seems to be between 1–26, or standard alphabet range. Putting the numbers into a string 30 9 20 3 15 9 14 38 31 16 5 5 18 51 and converting those between 1–26 gives the first puzzle breakthrough with the output of ?itcoin??peer? which aligns with the start of the Bitcoin Whitepaper header that says Bitcoin: A Peer-to-Peer Electronic Cash System. This tells us that each line segment encodes two characters based on its relative movement from the previous segment. Using this information, we now know 30=B, 38=:, 31=A, and -=51 in our original coordinates. The first thought was the puzzle required a custom character mapping to be recreated using the line segments along with determining how to assign +/- movement. After a lot of manual mapping of letters and a custom assignment of +/- signs, it was discovered the entire whitepaper to coordinate conversion could be boiled down to an equation. First we break up the entire paper into XY character bigrams and using the following equations to determine line segment shifts.

Strip whitepace/newlines and split the whitepaper into bigrams
(ie. Bi|tc|oi|n:|AP|ee|r-|to|-P|ee|rE…)

Assign the first character as X, and second character as Y and convert them to their ascii decimal value. Then use the equation below to get the line segment shift.

X-coord = (dec[Xchar]-96)*4
Y-coord = (dec[Ychar]-96)*4

Example: The first two character are Bi, which when converted to their ascii decimal values, give 66 and 105

X-coord = (66-96)*4 = -120
Y-coord = (105-96)*4 = 36

Which tells us the line segment should move (-120, 36) relative to the previous segment endpoint

This gives us the information on how the line is being created, with the goal to recreate the entire image from the whitepaper. It was believed that doing this would reveal an anomaly in the image which would be a hidden private key to the puzzle address. To begin we first had to resolve the logic when the edge of the image was hit. This was pretty straight forward as you just wrap the coordinate to the other side and connect it with a light gray line.

The first edge hit

So in the case of the first jump in the image, our last line segment puts us at (8188, 7472) and we need to encode the characters st which requires a movement of (76, 80) but this would put us beyond the edge boundary of the image. So to wrap this around you could use

NewVal=(8188+76)%8192

to get the next coordinate as (72, 7552) with the Y value shifting normally as it was still within bounds.

Note: it was observed that every jump like this always required a 6 px correction factor to push the point towards the center of the image for some unknown reason.

This process would perfectly recreate the image with a few final nuances. The text from the figures in the Whitepaper were used (as they were selectable when highlighting text in the pdf) and the equations were also used. Since the equations used special characters that didn't fall within the 256 ascii charset, some manual work was required to measure the coordinates in the image and manually assign the coordinate values when these characters were used during the drawing creation. (There was probably some UTF logic to mathematically account for these that we didn’t determine)

We created a Python script using Python Image Library (PIL/Pillow) to retrace the lines and validate our logic. You can view the final script here: https://gist.github.com/ziot/2d96b41bd92e4c765f60f59bbd49644e

The final validated Whitepaper string can be found here
https://gist.github.com/ziot/a56e93728a5a7423e8e15a822f5850c7

The validated image
close up

At this point we were stumped as we were able to perfectly recreate the image using the data from the whitepaper and didn’t see any anomalies within the string for a hidden private key that we were expecting. After a little more digging, we finally found the true puzzle. The line actually continued on past the end of the whitepaper string and could be revealed using any steg tool or photoshop.

The hidden line has been highlighted for clarity
This is what the private key hidden lines looked like if you remove all of the whitepaper lines.

This is where the fun begins as we now have an equation to determine what characters these will map to once we can extract the coordinates of each line segment. This turned out to be no easy task, as the lines were layered underneath the main lines with many stretches hidden and there wasn't as obvious changes in segments as there was with the main image. (which becomes more apparent why later)

While trying to extract the lines manually, we also reversed what we were doing with Python previously and tried to retrace/extract characters using the angles we were finding manually. You can view that script here: https://gist.github.com/ziot/dafeb296a7ec99363c5397e1149a3a59

After quite a few failed attempts at extracting meaningful data from the lines, a method was finally found that seemed to have relatively high success at determining the details of each line segment. The failed attempts weren’t a total loss though as it was noticed almost all coordinate shifts seemed to fall between 156–208 (which is why the slope didn't change much between segments with such a narrow window) which is what led to the improved strategy now that we knew the bounds. This strategy involved meticulously measuring the slope of each line using as much visible data as possible until it fell within the bounds found previously.

Measuring slopes

This method worked by finding the points at which a line segment repeated itself. Since we knew the image was scaled up by 4, we knew 4 identical sloped line segments should exist between each set of endpoints. In the image above, the slope of the segment is -40/-39 which when multiplied by 4, tells us the end coordinate of this segment is (-160, -156) away. Doing this manual work for the entire image gave us 107 segment data points. Thus using our equation previously to convert to plaintext gave us an initial output of

12891, 364, -10, -17301, -5, 8478, -8, 424, 7737, 19, -45, 168, -27, 52, -6, -16101, -842, 3560, -2120, 3, -7, 220, -319, 189562625, 54, 12652, -17627, 4233, 246, -6, 3, -33, 1516, -1089, 1047, -287, 371, -24, 4, -1758, 4509, -1, 114, -4, 38, -51, 3, , 1345, 1506

This at first glance seemed to be more coordinates until counting up the number of commas revealed there would be 50 numbers, which was 1 less than a private key of 51 length. So somehow this string will map to a private key, but there was obviously some corrupted data that needed to be resolved. After some thought on what the numbers could be, it was noticed most of them were below 18000 and the string seemed to have a fairly even run of positive and negative numbers. This is where the original Whitepaper comes into play which happens to be 17670 characters and we just so happened to perfectly validate as being correct by recreating the initial artwork. So this was a sigh of relief that all that work wasn’t for nothing as it was now needed for this final step as a book cipher where you must index into the WP text to extract characters, but first we need to fix some of the obvious errors in our string. There was no silver bullet to fixing this besides being even more meticulous trying to properly identify the slopes of the lines on a second pass.

12891, 364, -10, -17301, -5, 8478, -8, 423, 8857, 19, -45, 168, -27, 52, -6, -161, -11842, 3560, -2121, 3, -7, 220, -319, 178, -2625, 54, 12652, -17627, 4533, 246, -6, 3, -33, 1516, -1089, 1047, -287, 371, -24, 4, -1758, 4509, -1, 334, -4, 38, -51, 3, -2015, 1506

A few more iterations and review led us to feel confident that only 50 numbers exist in the string while we wanted 51. This led to the theory that the puzzle stripped the leading 5 off the private key which was a similar mechanic in a previous puzzle. Using this knowledge, and the first 6 numbers that we had validated so many times we felt confident in the output, we knew that the start point for the string had to be between characters 4057 and 4414 to stay within the 1–17670 boundaries within the first 5 steps. It just so happens the character 5 exists at position 4105 in the White Paper, which was ideal, so we decided to use this as a logical start point. Assigning this as the start and extracting the characters based on each value shift led to promising results initially.

We’re onto something here

Right away we see uppercase characters and numbers appear in the first 8 values pulled. Seeing as how Uppercase and numbers only account for about 3% of the entire whitepaper, we knew this wasn’t just a coincidence that we pulled 5 in our 8 characters. We were also validated by the fact the first indexed character was J which is one of only a few acceptable characters that can come after the 5 in an uncompressed private key. Now that we could pinpoint where the errors were, it was back to what would hopefully be the final audit of line segments. Some time later we were able to correct the final few line segments at which point the private key dropped in perfectly.

The final segment points

(-188, -184) (-160, -156) (-188, -208) (-180, -168) (-176, -208) (-204, -188) (-192, -208) (-204, -188) (-164, -180) (-192, -188) (-208, -204) (-172, -208) (-160, -176) (-164, -160) (-208, -204) (-160, -208) (-172, -180) (-180, -208) (-164, -164) (-172, -164) (-208, -188) (-156, -208) (-204, -176) (-172, -208) (-188, -168) (-160, -208) (-204, -184) (-164, -208) (-172, -184) (-208, -204) (-168, -208) (-204, -188) (-168, -188) (-208, -204) (-188, -188) (-160, -176) (-184, -208) (-180, -172) (-168, -192) (-208, -204) (-184, -188) (-184, -188) (-208, -180) (-208, -204) (-164, -208) (-184, -184) (-192, -208) (-204, -180) (-188, -156) (-208, -188) (-160, -156) (-208, -204) (-188, -172) (-184, -172) (-208, -172) (-176, -208) (-188, -184) (-172, -176) (-184, -208) (-204, -188) (-164, -168) (-184, -164) (-208, -176) (-172, -180) (-180, -208) (-184, -176) (-168, -208) (-204, -168) (-208, -180) (-208, -204) (-180, -180) (-208, -188) (-172, -188) (-168, -208) (-204, -188) (-192, -160) (-156, -208) (-188, -192) (-176, -164) (-208, -204) (-184, -160) (-164, -208) (-180, -164) (-188, -208) (-204, -184) (-176, -208) (-176, -208) (-204, -188) (-164, -172) (-160, -208) (-176, -172) (-192, -156) (-208, -204) (-188, -208) (-180, -180) (-176, -208) (-204, -176) (-208, -180) (-160, -208) (-204, -172) (-188, -208) (-180, -208) (-204, -184) (-192, -188) (-172, -208) (-188, -172) (-192, -168)

The final plaintext conversion

12891, 364, -10, -17301, -5, 8478, -8, 533, 7757, 19, -45, 168, -27, 52, -6, -161, -11842, 3560, -2121, 3, -7, 220, -319, 189, -1525, 54, 12542, -17627, 4533, 246, -6, 3, -33, 1516, -1089, 1047, -287, 371, -24, 4, -1758, 4509, -1, 334, -4, 38, -51, 3, -2015, 1506

The final extract

Success!

Giving the final private key of

5J75Nt7nGQfMWBsoQF74hou2yFc7mK2tHrEA1q3wn3Ls82sHhzA

and access to the 1BiTCoiNsuFnkCFGkv6AGgwWxN31GUwY6W wallet

Special Thanks

We’d like to thank Zden for continuing to release fantastic top tier puzzles for the crypto puzzles community.