Where the Wild Media Are

Ghost Palette Sep 29, 2020

This article is part of the Alpacawhal guest author series Ghost Palette, where we invite established crypto artists to write from their own perspective on  technical topics related to the scene.

In this edition, we invite OG crypto artist obxium to write about NFTs, media, and how artists can verify the integrity of their art media.


Hello!

The intended audience for this information are artists or collectors who already have a fundamental grasp of what data make up the typical crypto art NFT and are comfortable with fairly deep technical details. You have been warned! 😭

The idea is that a complete work of crypto art is the token + media, as it makes little sense to try and pass off the object as a complete work of art if one of these two are missing. Okay so far?

One more time with fun details!

Example crypto art NFT creation worklfow

The workflow basically goes like this...

  1. Artist interacts with Web 3 app, uploads their art media, enters token metadata, and pays for transaction fees with a connected web 3 wallet (i.e. Metamask, WalletConnect, whatever).
  2. Web 3 application interacts with  smart contract to mint the actual token(s) with metadata according to the artist's intententions as expressed in the Web 3 app. The art media is sent to file storage like the Interplanetary File System or IPFS as it is known.
  3. The media is then pointed to (aka "pinned" to) the token URL as a way to match the two up and form the unholy matrimony that we all know and love as a work of "crypto art". 🎉

Easy and makes such perfect sense right?

Notice any problems tho?

This splitting up of the token into a part that lives "on-chain" and a part that lives in some rando file system is weird and can lead to issues. Computering is hard tho and it is physically unpossible to put the media into the token right now unless that media is super tiny so this is how we do...

Besides being awkward, the disconnect here between media and token sets up other sources of sadness, too. Artists and collectors alike should be aware that the following things can and do happen.

  1. Media and token are permanently disassociated. The media and token can diverge and you are left with a token with no pinned media that could possibly still retain some utility (e.g. let the holder into the secret party). The token holder is going to have a difficult time proving that it is indeed a painting of duct tape banana'd to a wall, however. 🍌
  2. Centralized service outage. Maybe it didn't die, but a server somewhere got  super drunk and the media became unavailable just as you were showing it in a critical show... or attempting a viewing with a potential buyer, or anything important to an artist where the public is involved. Embarrassing and unfortunate!
  3. Artist's original media differs from that stored for the token. In this case, somehow the exact art media is not present in the storage. The media appears okay in the case of images, but it is not exactly the same as what the artist provided. It could actually be a compressed or resized version, or worse.

There is not much an artist can do about points 1 and 2, besides pinning their own media files and providing redundancy (you nerd). In the case of point 3, you cannot always determine why it occurred, but you can at least verify that it has occurred.

Dive so deep into this here crypto art that your brain asplode...

The way that you do this is to compute a cryptographic hash of the media file, after the file is finalized locally, but before it is uploaded, and then again after the token is minted by examining a copy of the file downloaded from its storage URL.

You then compare both hashes for a match.

I will show you how to do so now, using my own live art on 4 of the popular platforms, Known Origin, MakersPlace, SuperRare, and Rarible. I am using command line utilities here, but you can also compare hashes with websites to do the entire process in a browser, too.

Since this is my art, I can store the original media files in a trusted location for the comparisons and that location is of course, obxium.com. All my examples here are static 2D illustrations, but the technique works for any kind of data.

KnownOrigin

obxium. "Cute Alpacawhal BTC," 2020 (KnownOrigin) - original image data: 2160 x 2160, 8-bit/color RGB, non-interlaced, SHA 256 summary 99e5ba641d86dadafd8e4988b63feca2890e054659d173fbe784ef82885fb08f

This is my latest KnownOrigin artwork "Cute Alpacawhal BTC," in an edition of 5.

You can download the original art media and validate it from obxium.com.

curl -sO https://obxium.com/img/cute-alpacawhal-btc.png

Check that the file matches our expecatations as PNG data.

file cute-alpacawhal-btc.png

The output shows the original PNG image data.

cute-alpacawhal-btc.png: PNG image data, 2160 x 2160, 8-bit/color RGB, non-interlaced

Now validate the file against its known SHA 256 summary.

printf "99e5ba641d86dadafd8e4988b63feca2890e054659d173fbe784ef82885fb08f  cute-alpacawhal-btc.png" | shasum -a 256 --check

If all is good, then the following output will be printed.

cute-alpacawhal-btc.png: OK

Being the original image, a match is fully expected here. Now, let's take a look at the file that was stored by KnownOrigin when the NFT was minted.

Right click– but don't save as, jackass! Inspect... 🤣

KnownOrigin's web 3 app places the tokenURI data in a div with the class token-uri, so you can locate it in the page source, as shown.

Download the JSON file that contains the token meta from the token-uri value, and print it with jq to crack it open and feast on the sweet, sweet metadata inside.

curl -s https://ipfs.infura.io/ipfs/Qmae1W6HkYrFjn1VUKZmqMYzmWtKcnChuDyk3SQQhxkMd4 | jq
{
  "name": "Cute Alpacawhal BTC",
  "description": "This is part of the \"Radical Alpacawhals of Crypto\" series. They appear on all the different platforms in random amounts repping various lifestyle brands and so on.",
  "attributes": {
    "artist": "obxium",
    "scarcity": "rare",
    "tags": [
      "Alpacawhal",
      "BTC",
      "Gold",
      "obxium",
      "2020",
      "cute"
    ],
    "asset_type": "image/png",
    "asset_size_in_bytes": 647799
  },
  "external_uri": "https://knownorigin.io/artists/0xf65db13b5ee031cb0ebba525ef21aa6c586681b3",
  "image": "https://ipfs.infura.io/ipfs/QmWDsDdxhvEHQgMW3K4tHVNZhGwyMDHASu9TZbuRpE8rtb/asset.png",
  "artist": "0xf65db13b5ee031cb0ebba525ef21aa6c586681b3"
}

It's all the cool stuff about my artwork, neato! Next, get the media file (named asset.png) by downloading the value of the image field.

curl -sO https://ipfs.infura.io/ipfs/QmWDsDdxhvEHQgMW3K4tHVNZhGwyMDHASu9TZbuRpE8rtb/asset.png

Now you can validate the file against its known SHA 256 summary.

printf "99e5ba641d86dadafd8e4988b63feca2890e054659d173fbe784ef82885fb08f  asset.png" | shasum -a 256 --check

If all is good, then the following output will be printed.

asset.png: OK

Nice, it looks like the cryptographic hash of the image KnownOrigin associated with my "Cute Alpacawhal BTC" NFT exactly matches that of my original artwork. 🙌

MakersPlace

obxium. "GHOSTCHAINZ," 2020 (MakersPlace) - original image data: 2160 x 2600, 8-bit/color RGB, non-interlaced, SHA 256 summary bd07daebcd33265aa06fc78d891fffa030838c342c41a9ab261b13af889c1406

My most recent MakersPlace artwork "GHOSTCHAINZ."

You can download the original art media and validate it from obxium.com.

curl -sO https://obxium.com/img/GHOSTCHAINZ.png
printf "bd07daebcd33265aa06fc78d891fffa030838c342c41a9ab261b13af889c1406  GHOSTCHAINZ.png" | shasum -a 256 --check

If all is good, then the following output will be printed.

You can also check out the image data to get the dimensions, bit depth, and so on.

file GHOSTCHAINZ.png 
GHOSTCHAINZ.png: PNG image data, 2160 x 2600, 8-bit/color RGB, non-interlaced

One feature unique so far to MakersPlace is their Proof of Authenticity page for each artwork minted there.

Here is that page for "GHOSTCHAINZ":

Authenticity of Digital Creation | GHOSTCHAINZ | MakersPlace
MakersPlace is the premier market to discover, collect and invest in truly rare and authentic digital artworks, by the world’s leading artists and creators. Creators on MakersPlace are able to protect and sell their works to a rapidly growing community of thousands of digital creatives and collector…

This is a nice place to discover more about the NFT, including its token ID, contract information, and more.

The most accurate method to determine the media URL we need to find the stored image is by directly querying the MakersPlace smart contract with the tokenURI method, and passing in the token ID. In the case of  "GHOSTCHAINZ", it is MakersPlace token ID 21566. Reading the contract tokenURI method on Etherscan for the token returns this URL string:

ipfs://ipfs/QmSBimtMYWGXG5pLh8wbrndgMW2s47JmqhXeFFVUHGD7eS

This is a native IPFS URL, but if you do not have the necessary IPFS tooling installed to use it directly, you can use a translating server to get the data with HTTPS instead, by altering the URL to this value.

https://ipfs.io/ipfs/QmSBimtMYWGXG5pLh8wbrndgMW2s47JmqhXeFFVUHGD7eS

Now download the file and print it to behold the magical MakersPlace metadata for "GHOSTCHAINZ".

curl -s https://ipfs.io/ipfs/QmSBimtMYWGXG5pLh8wbrndgMW2s47JmqhXeFFVUHGD7eS | jq
{
  "title": "GHOSTCHAINZ",
  "name": "GHOSTCHAINZ",
  "type": "object",
  "imageUrl": "https://ipfsgateway.makersplace.com/ipfs/QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg",
  "description": "This is another ghost of the simulation.\r\n\r\nIt moves in fields of gold dragging ethereal chains to dip and drip until from the other side of the code emerges the finest in swangin' chainz for entertainment purposes only.",
  "attributes": [
    {
      "trait_type": "Creator",
      "value": "obxium"
    }
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "GHOSTCHAINZ"
    },
    "description": {
      "type": "string",
      "description": "This is another ghost of the simulation.\r\n\r\nIt moves in fields of gold dragging ethereal chains to dip and drip until from the other side of the code emerges the finest in swangin' chainz for entertainment purposes only."
    },
    "preview_media_file": {
      "type": "string",
      "description": "https://ipfsgateway.makersplace.com/ipfs/QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg"
    },
    "preview_media_file_type": {
      "type": "string",
      "description": "jpg"
    },
    "created_at": {
      "type": "datetime",
      "description": "2020-05-04T17:09:39.161636+00:00"
    },
    "total_supply": {
      "type": "int",
      "description": 1
    },
    "digital_media_signature_type": {
      "type": "string",
      "description": "SHA-256"
    },
    "digital_media_signature": {
      "type": "string",
      "description": "07d77dc43a1b3a5c3b15a90ecff42fba461492f12a3954261d4c9524507e90e6"
    }
  }
}

Such meta, much detail. WOW!

The field of most interest to us here is imageUrl, which contains the original media URL.

Download this URL.

curl -sO https://ipfsgateway.makersplace.com/ipfs/QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg

Then validate the cryptographic hash of the downloaded file.

printf "bd07daebcd33265aa06fc78d891fffa030838c342c41a9ab261b13af889c1406  QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg" | shasum -a 256 --check
QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg: FAILED
shasum: WARNING: 1 computed checksum did NOT match

Oh noes! Something is wrong and the downloaded data from MakersPlace does not match the original art media. Let's validate that we at least have image data before looking into it more.

file QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg 
QmXctieQkbujSZamJ66RznzbhQW6xWdDAYZgNymqT8sgSg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, progressive, precision 8, 831x1000, components 3

Well, this is certainly unexpected! Somehow the data MakersPlace is storing is JPG even though I minted the are with a PNG! This seems like a case of  #3, from the introduction, "Artist's original media differs from that stored for the token."

What in the– the data is a JPG now?!

The PNG I gave to MakersPlace to mint this art is now a JPG? #WTF

Looking back at the metadata, the imageUrl value is also present as the value of the description field under the preview_media_file field so that's kind of a clue that the preview is a JPEG, but so is the image stored in IPFS?!

I checked numerous other artworks of mine and others, and all still image based art appears to return JPG images always. This probably needs a closer look...and perhaps a clarifying statement from MakersPlace.

UPDATE

I reached out to MakersPlace via Twitter for clarification about what is going on here, and it is apparently part of their strategy to protect the artist's original image. While the original image is not pointed to the token, there is a hash of the original image included in the token metadata as the value of digital_media_signature.

This is a key differentiator between MakersPlace and most other galleries with respect to how tokens are minted. Here's the relevant Twitter exchange.

Excellent clarification by MakersPlace as to the how and why of their media storage strategy.

SuperRare

My latest 💎 SuperRare artwork "STONED", a commision that I created at the request of the awesome crypto artist Lenara. It deals with the topics of Rai stones and current technology (VR), so money and technology in a consumerist pop culture way, but I digress all to hell...

obxium. "STONED," 2020 (SuperRare) - original image data: 3200 x 2160, 8-bit/color RGB, non-interlaced, SHA 256 summary 65d4910f7e7318ee3b7b43dd580ad0835c2b546e0006c05794fa1cce47aa884d

Here are steps using common system utilities to download the media file, and validate it against the correct published SHA 256 summary.

Download the original file.

curl -sO https://obxium.com/img/STONED-original.png

Check that the file matches our expecatations as PNG data.

file STONED-original.png

The output shows the original PNG image data.

STONED-original.png: PNG image data, 3200 x 2160, 8-bit/color RGB, non-interlaced

Now validate the file against its known SHA 256 summary.

printf "65d4910f7e7318ee3b7b43dd580ad0835c2b546e0006c05794fa1cce47aa884d  STONED-original.png" | shasum -a 256 --check

If all is good, then the following output will be printed.

STONED-original.png: OK

Repeat the process with the media file associated with the token. You can actually view source to check the source on SuperRare for the art in question and determine the media storage URL that way.

You can also directly query the smart contract with the tokenURI method, and passing in the token ID. In the case of  "STONED", it is SuperRare token ID 13988. Reading the contract tokenURI method on Etherscan for the token returns this URL string:

https://ipfs.pixura.io/ipfs/QmZoudcfPUaBLNdgcmv3E3bK7dJ6aAmgz8u7NG3sTQEuGk/metadata.json

Downloading this URL gives you a JSON object with an image field containing the actual URL to the original media data as shown here.

curl -s https://ipfs.pixura.io/ipfs/QmZoudcfPUaBLNdgcmv3E3bK7dJ6aAmgz8u7NG3sTQEuGk/metadata.json | jq
{
  "name": "STONED",
  "createdBy": "obxium",
  "yearCreated": "2020",
  "description": "Virtually visiting underwater rai stones [3200px x 2160px]",
  "image": "https://ipfs.pixura.io/ipfs/QmXZ8eBNDMDMU1YbNwnthCUQU3MKrGHZhAuuUsTEszjUHr/STONED.png",
  "media": {
    "uri": "https://ipfs.pixura.io/ipfs/QmXZ8eBNDMDMU1YbNwnthCUQU3MKrGHZhAuuUsTEszjUHr/STONED.png",
    "dimensions": "3200x2160",
    "size": "2041210",
    "mimeType": "image/png"
  },
  "tags": [
    "rai",
    "Yap",
    "coin",
    "DDF",
    "obxium",
    "2020"
  ]
}

Download the file media from the URL found in the image field.

curl -sO https://ipfs.pixura.io/ipfs/QmXZ8eBNDMDMU1YbNwnthCUQU3MKrGHZhAuuUsTEszjUHr/STONED.png

Validate the file against SHA 256 summary.

printf "65d4910f7e7318ee3b7b43dd580ad0835c2b546e0006c05794fa1cce47aa884d  STONED.png" | shasum -a 256 --check

As with the original art, you want to see OK in the output.

STONED.png: OK

Yay, it looks like we are good to go, and have a high degree of confidence that the image associated with my "STONED" NFT exactly matches my original artwork! 😎

Rarible

obxium. "Present Company Excluded," 2020 (SuperRare) - original image data: 1000 x 1000, 8-bit/color RGB, non-interlaced, SHA 256 summary eb5f3082e760dceb00ab77e6cc1262f16612b6482da188f2a54aa7d5ffa9bd47

A recent Rarible artwork entitled "Present Company Excluded."

You can download the original art media and validate it from obxium.com.

curl -sO https://obxium.com/img/PCE.png

Validate the cryptographic hash.

printf "eb5f3082e760dceb00ab77e6cc1262f16612b6482da188f2a54aa7d5ffa9bd47  PCE.png" | shasum -a 256 --check

If all is good, then the following output will be printed.

PCE.png: OK

You can get the token ID from the artwork URL. For example, here is the Rarible URL for this art.

https://app.rarible.com/token/0x60f80121c31a0d46b5279700f9df786054aa5ee5:22866:0xf65db13b5ee031cb0ebba525ef21aa6c586681b3

The Token ID for my art is the string between the two colons, or 22866.

If we use ID with the Rarible smart contract tokenURI method, we get this string back.

https://ipfs.daonomic.com/ipfs/QmQfHGPL2vTzp7fRDZLSrUC4hDxTk45jC4RqM73z3BGwQh

You can get this URL and parse the JSON data to learn the image URL.

curl -s https://ipfs.daonomic.com/ipfs/QmQfHGPL2vTzp7fRDZLSrUC4hDxTk45jC4RqM73z3BGwQh | jq

and the response...

{
  "name": "Present Company Excluded",
  "description": "Worst timeline ever.",
  "image": "ipfs://ipfs/QmYsW9BW1iE1Ek1MdbAWcdKo2Yw6hjyDJkHJZVn2j2rkA8",
  "external_url": "https://app.rarible.com/token/0x60f80121c31a0d46b5279700f9df786054aa5ee5:22866",
  "attributes": []
}

Finally, as with the other examples, get the image URL and validate it.

curl -s https://ipfs.io/ipfs/QmYsW9BW1iE1Ek1MdbAWcdKo2Yw6hjyDJkHJZVn2j2rkA8
printf "eb5f3082e760dceb00ab77e6cc1262f16612b6482da188f2a54aa7d5ffa9bd47  QmYsW9BW1iE1Ek1MdbAWcdKo2Yw6hjyDJkHJZVn2j2rkA8" | shasum -a 256 --check

It checks out, so Rarible appears to store correct data at least in this case, too. 🥃

QmYsW9BW1iE1Ek1MdbAWcdKo2Yw6hjyDJkHJZVn2j2rkA8: OK

Hopefully this was useful information to you and did not bake your mind too hard.

Enjoy and keep on making art!

– obxium ⓞ


We hope you enjoyed Ghost Palette with obxium; if so, make sure to share this with a friend and donate to Alpacawhal.

Tell them Alpacawhal sent you...

obxium

Tags

obxium

OG crypto artists & chaotic neutral organic cyborg

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.