Thousands of Counterparty Bitcoin assets – 1/1 NFTs and 1/N crypto cards alike – have images associated with them. Many of these are at risk of getting lost due to link rot. This article suggests ways to preserve them.
Let us first list the different kinds of image associations;
B. URL + Hash
C. Hash Only
D. URL Only
URL + Hash
Although the URL itself is on-chain, the image it points to is not. By also adding the file’s hash to the on-chain data, anyone can verify that the current image is indeed the same as the original. This enabled me to authenticate weex’s bitcoin art. The image I downloaded in 2022 matched a RIPEMD-160 hash from the original asset description in 2015.
I haven’t seen any cases of this on Counterparty but I did find one from 2012 on Namecoin. The expired domain ts/triangle‘s metadata included the filename triangle.xcf and a checksum. With no URL to open, my best try was to google the hash. No hits. I then tried googling the filename and got a few hits but neither matched the checksum. Triangle.xcf will remain a mystery until someone releases a copy of the file, if ever.
This is (unfortunately) the most common way of linking a file to a token. In the absence of an on-chain hash it’s difficult, if not impossible, to prove that the image hasn’t been modified. Thankfully, the most popular image host, Imgur, has a policy of immutable images. As long as you trust this company, you can conclude that the image you see today is indeed the original one.
The image-token relationship may be documented in tweets, forum posts, blog articles, etc. It’s essential to consider whether the sources may have been modified later. Twitter, like Imgur, is by policy immutable. Blogs and forums may be verified with Wayback Machine. Spells of Genesis trading cards had initially only off-chain image associations, but in December 2015 I added on-chain hashes for several cards through my XCP Cards project.
How to Back Up From URL
The good news is I already backed up your Counterparty and Dogeparty NFTs!
For the 2022 Dogeparty Hackathon I wrote the Image Archiver python script that finds all image links in asset descriptions, saves them, outputs an html archive, and anchors them all with a hash on the blockchain. The respective archives are;
* SHA256 truncated at 128 bits.
Before we pop the champagne, let’s make it clear, these archives help preserve the image-token connections but do not provide perfect proofs;
- No guarantee a URL hasn’t been tampered with, i.e. different image before.
- The archive itself must be preserved. Please help me back up images and the receipt file.
- You must trust me.
For you to back up your NFT, I recommend the following.
- Save a copy of the receipt file.
- Click through the archive’s alphabetic list until you find your token. Save your NFT’s image. Right-click save the downsized version, but more importantly; click the link to get the original image.
- Manually look for proof that the current image is the same as the original.
- Is there any matching on-chain hash in the asset description or in broadcasts? Check with the Timeline Tool.
- Search for off-chain sources. Collect screenshots and comments in a zip directory.
TOKENNAME bit.ly/xxxx checksumwhere
- bit.ly/xxxx links to the zip file
- checkum is the SHA256 of the zip file
- I recommend cutting the message at 54 characters. It saves on fees as 54 is max broadcast length to fit op_return. A truncated hash is still more than strong enough.
- Share the zip file with other holders (if a 1/N NFT).
How to Back Up an Off-Chain NFT
The process is exactly as above. Collect as much evidence as possible in a zip folder and broadcast its hash on-chain. Share the zip file with as many as possible.
Build Your Own Archive
In theory I could have planted false images in my archive. Say I disliked artist X, and so to hurt him I replaced his images to cause confusion. To minimize this risk, several independent individuals should create archives.
Building an archive is easy if you already run a Counterparty/Dogparty node. Point the script provided on Github to your local database and let if run for about 24 hours. The archive of original XCP images takes up 13 GB but you can opt out from saving these. The downsized images require less than 1 GB and can be much less if you choose a lower resolution.
Good To Know
Below I’ve added some issues I encountered, and a few notes about the archiver.
The archiver looked for image links in two ways;
– if asset description links to JSON file, open it and look for image link.
– else look for image link in asset description.
An image URL was defined as a link ending with ‘.jpg’, ‘.jpeg’, ‘.gif’ or ‘.png’. You can try to run the archiver with more image formats. It may well work with other common extensions. If you want to take it one step further, you can try links that don’t necessarily end with an image extension.
The downsized version is not animated, only the first frame is shown.
Proof Inside JSON
I noticed a few times an image hash inside a json file. But the json itself could have been tampered with. This renders the “proof” useless unless the json file itself has an on-chain hash. So if you do use a json file, make sure also to include a hash of json file in the on-chain metadata AND keep backups of the json file together with the image.
More often than not IPFS links were broken. IPFS links are also very long and expensive to save on-chain.
The Imgur identifier is not a hash. It’s a random string. If you use an Imgur link I suggest you add a hash either in a separate broadcast. Make sure the broadcast is from the same issuer address and mentions the asset.
Also be aware that Imgur modifies the image. This means you need to first upload the image, then download it and finally generate the hash from the downloaded file.
Unfortunately, all the indiesquare links were broken, thus couldn’t be archived.
Advice For Tokens Creators
I recommend using hash as filename. Use SHA256 with the standard hex encoding. Truncate it at 24 characters, i.e. at 96 bits. This is a good tradeoff, as it’s still long enough to be collision resistant (even from brute force attack) while short to save on blockchain space.
Unfortunately, to be included on the Xchain explorer your image must either be hosted on Imgur (that uses a random string as filename) or linked to through a json file. This leaves you with two options;
1. The Imgur Route
Xchain prefers the format
For example, your NFT is called HOCKEYISFUN with image
https://i.imgur.com/sOT3dDr.png and title
Set the asset description to
Download the Image from Imgur and get its SHA256 checksum. From the same issuer address, make the broadcast
Optionally, if you want, you can cut the message at 54 characters. It will save you some fees as 54 is the max broadcast length to fit inside op_return.
2. The JSON Route
Host a json file on your web site. As with an image name, use the hash technique for the json file. The asset description will simply be a URL like this;
Note that the link is exactly 45 characters. Any longer and it wouldn’t fit op_return and cost more in fees (and dust outputs). A quirk with Counterparty issuances is that these extra costs will be repeated for every asset update, so I strongly suggest keeping the URL at 45 chars max.
The great thing about json is that you can add as much metadata as you wish. Use the standard
image_large property to link to the image. Of course, the image hash too must be included inside the json file. I recommend the full hash under
image_large_sha256 although I’m not sure if there’s a standard field for this. It doesn’t hurt either to consistently use the hash-as-filename technique also here.
As long as the URL is live it’s easy to verify your file, even automatically through an algorithm.
More importantly, all URLs should be assumed to break at some point. Maybe in ten years, almost certainly within a few decades. But it only takes one copy of your files to be preserved to keep your NFT alive. Any explorer or wallet can easily enough keep a directory of matching files, just like I did with my image archive.
To be extra safe, you can in addition use the broadcast technique. Broadcast the hash of the image, and now the image can be verified even if the JSON file gets lost.
Bottom line; the hash is the immutable path to your image. The URL is just a temporary pointer to help spread copies of it.