Make CIDv0 from CIDv1 using cid.ipfs.io

Can be https://cid.ipfs.io app extended to display CIDv0 version of supplied hash as well? It does that for v1 already: you enter v0 it show v1.

I often get v1 hashes but need v0 for compatibility reasons.

1 Like

I’m assuming you’re meaning only for CIDs with their data encoded as dag-pb? Because in any other case, it won’t be possible to generate a working v0 CID as they only support that one codec (that’s what CIDv1 fixes). There’s more info about that here.

FWIW you should be able to convert reliably using the tools available, for example:

# If this outputs "protobuf" we can be reasonably certain we can convert
ipfs cid format -f "%c" -b base58btc bafybeiccuppnh2nh54jtubqo2jjmngzlnnmliejjq3xlswxzh24et2llu4
# Convert our CIDv1 to CIDv0 (returns "QmSpnYb3romJejsUqhRepYr6GBwuKUFj1kqrhtk1z2Hn8E")
ipfs cid format -f "%M" -b base58btc bafybeiccuppnh2nh54jtubqo2jjmngzlnnmliejjq3xlswxzh24et2llu4

I can pass along your question of course! I am curious though, why do you need this functionality? Just my $0.02 on the matter, we should be supporting v1 as much as possible, so I think it makes sense to display the data the way it’s currently displayed.

ipfs cid format -f "%c" -b base58btc bafykbzaceaeofefgje22l7rhgtcgs22m32f4ysw5nqa3ty5zawfovqam7pj2c
protobuf


ipfs cid format -f "%M" -b base58btc bafykbzaceaeofefgje22l7rhgtcgs22m32f4ysw5nqa3ty5zawfovqam7pj2c
2Drjgb4raMbmzUmdmjM2EMJ3zmXaJCje7yNBpQMrFvPZjUtjNG

this not longer works

2 Likes

I know how to store in bytes32 CIDv0, but I don’t know how to store in bytes32 CIDv1.

ethers.utils.hexlify(
        ethers.utils.base58
          .decode("QmewVXx1r9drCzf9mdutY8R16tLjQhBQjBvSqyb4gxD1z8")
          .slice(2)
      )

Tell me how to do this and I will stop using CIDv0 =)

I suppose you have to ensure you’re using sha256 as well if you want a proper Qm CIDv0.

Does this help? https://blog.thedisco.zone/?post=cidfacts

Edit: It might still be too long actually, hmm…

CIDv1 allows for truncating hashes, go-ipfs wants at least 20bytes big hashes.
Python pseudo code looks like this:

def decodeAndShortenCID(cid: str) -> bytes32:
  return shortenCID(decodeMultibase(cid))

def shortenCID(cid: bytes) -> bytes32:
  if len(cid) <= 32: # hash short enough already
    return bytes32(cid) # simply zero pad after the CID, you might need to be carefull with endianness here

  if len(binaryCID) >= 34 and binaryCID.startwith([0x12, 0x20]): # this is a CIDv0
    digest = binaryCID[2:34] # remove the 0x12, 0x20 CIDv0 prefix and remove any trailing data
    codec = dagpb
    hash = sha256
    hashLength = 32
    cid = makeCIDv1(codec, hash, hashlength, digest) # continue the algorithm with CIDv1 to know how much to truncate
  
  version, remainingBuffer = readUvarint(cid)
  if version != 1:
    raise "unknown CID version " + str(version)

  codec, remainingBuffer = readUvarint(remainingBuffer)
  hash, remainingBuffer = readUvarint(remainingBuffer)
  if hash == indentity:
    raise "cannot shorten identity hash" # there is probably more hashes that don't supports it, but I don't know them

  hashlength, remainingBuffer = readUvarint(remainingBuffer)

  hashlength -= len(cid) - 32
  if hashlength < 20:
    raise "hash too short"
  digest = remainingBuffer[:hashlength] # truncate the hash

  return bytes32(makeCIDv1(codec, hash, hashlength, digest)) # this might generate 31 bytes big CIDs for varuint varying reasons so same zero padding thing apply here

def makeCIDv1(codec: uint, hash: uint, hashlength: uint, digest: bytes) -> bytes:
  r = bytes() # empty buffer
  r += encodeUvarint(1) # version
  r += encodeUvarint(codec)
  r += encodeUvarint(hash)
  r += encodeUvarint(hashlength)
  r += digest
  return r

You will need to feed your root block (the one you put the CID in the blockchain) to go-ipfs with that truncated hash.
In other words, go-ipfs isn’t capable to realise by itself that a hash is just a truncated one it already have.

Also just because you can do it doesn’t mean you should, you are trading off cryptographic safety, also not all hashes are actually hashes and not all can just be truncated.

1 Like